JavaScript 中的 new 运算符是如何工作的?

IT技术 javascript oop object new-operator
2021-02-02 22:51:10

可能是 JavaScript 中最不为人知的部分,站在原型链旁边。

那么问题来了:如何...

new dataObj(args); 

...实际上创建一个对象,并定义它的原型链/构造函数/等等?

最好是展示一个替代方案,以完全理解这个关键字。

2个回答

new操作者使用内部[[Construct]]方法,它基本上具有下列功能:

  • 初始化一个新的本地对象
  • 设置[[Prototype]]此对象的内部,指向 Functionprototype属性。
    • 如果函数的prototype属性不是对象(原始值,例如 Number、String、Boolean、Undefined 或 Null),Object.prototype则改用它。
  • 创建对象后,它调用函数,提供对象作为其this值。
  • 如果被调用函数的返回值是一个原语,则返回内部创建的对象。
  • 否则,如果返回一个对象,则内部创建的对象将丢失。

new运算符功能的等效实现可以这样表达(假设 ECMAScript 5Object.create方法可用):

function NEW(f) {
  var obj, ret, proto;

  // Check if `f.prototype` is an object, not a primitive
  proto = Object(f.prototype) === f.prototype ? f.prototype : Object.prototype;

  // Create an object that inherits from `proto`
  obj = Object.create(proto);

  // Apply the function setting `obj` as the `this` value
  ret = f.apply(obj, Array.prototype.slice.call(arguments, 1));

  if (Object(ret) === ret) { // the result is an object?
    return ret;
  }
  return obj;
}

// Example usage:
function Foo (arg) {
  this.prop = arg;
}
Foo.prototype.inherited = 'baz';

var obj = NEW(Foo, 'bar');
obj.prop;          // 'bar'
obj.inherited;     // 'baz'
obj instanceof Foo // true
该术语的双重用法肯定令人困惑。然而,答案遗漏了对象构造函数的设置;从我的实验来看,似乎构造函数被克隆、应用并添加到结果 .constructor 值中。
2021-03-21 22:51:10
用 > var newObj = {}; 替换 Object.create(proto) 是否安全?newObj.prototype = 原型;?
2021-03-27 22:51:10
@pico.creator:不,该prototype属性仅对 Function 对象有意义,当用作构造函数时,并且在我的示例实现中使用构造函数new,无论如何都需要使用new运算符......唯一的另一种方法是使用该__proto__属性,但它是非标准的并且正在被弃用。请参阅此答案,其中我解释了prototype函数对象的属性与所有对象具有形成原型链内部 [[Prototype]]属性之间的区别
2021-04-04 22:51:10
我假设arguments示例中的应该是f.. 还是我遗漏了什么?
2021-04-09 22:51:10

表达式new C(arg1, arg2)

假设 C 是一个 JavaScript 函数(否则你会得到一个错误):

  1. 创建一个新的空对象(无属性)
  2. 将新对象的原型设置为 的“ prototype”属性的值C
    • 注意:prototype函数的默认值是一个对象(在声明函数时自动创建),其原型设置为Object.prototype并且一个constructor属性指向函数C
    • 注意:术语可能会令人困惑。命名为“原型”的性质是一样的对象的原型。只有函数具有名为“prototype”的属性,但所有对象都有一个原型。
  3. 调用函数C与“ this”设置为新的对象,并使用所提供的参数。
  4. 如果调用函数C返回一个对象,这个对象就是表达式的结果。否则新创建的对象就是表达式的结果。

newECMAScript 5的替代Object.createObject方法是使用内置方法。

new C(arg1, arg2) 将相当于:

var obj = Object.createObject(C.prototype);
C.apply(obj, [arg1, arg2]);

标准 JavaScript 不允许您显式设置对象的原型,因此Object.createObject无法在语言本身中实现。某些实现确实允许它通过非标准属性 __proto__。在这种情况下,new C可以像这样模拟:

var obj = {};
obj.__proto__ = C.prototype;
C.apply(obj, [arg1, arg2]);
注意第 2 点:prototype任何用户定义函数属性的默认值是一个对象,它包含constructor引用函数本身属性,并且它继承自Object.prototype. 该对象在创建函数对象时被初始化关于Object.create在ES3上只能部分模拟,设置[[Prototype]]属性可以通过临时构造函数来完成,但是是的,完全模拟是不可能的,查看更多干杯。
2021-03-21 22:51:10