JavaScript 中的“new”关键字是什么?

新手上路,请多包涵

JavaScript 中的 new 关键字在第一次遇到时可能会很混乱,因为人们倾向于认为 JavaScript 不是一种面向对象的编程语言。

  • 它是什么?

  • 它解决了哪些问题?

  • 什么时候合适,什么时候不合适?

原文由 Alon Gubkin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 773
2 个回答

它做了 5 件事:

  1. 它创建一个新对象。这个对象的类型就是 object

  2. 它将这个新对象的内部、不可访问的 [[prototype]] (即 proto )属性设置为构造函数的外部、可访问的 原型 对象(每个函数对象都自动具有 原型 属性)。

  3. 它使 this 变量指向新创建的对象。

  4. 每当提到 this 一点时,它都会使用新创建的对象执行构造函数。

  5. 它返回新创建的对象,除非构造函数返回非 null 对象引用。在这种情况下,将返回该对象引用。

注意: 构造函数 是指 new 关键字后面的函数,如

new ConstructorFunction(arg1, arg2)

完成此操作后,如果请求新对象的未定义属性,脚本将改为检查对象的 [[prototype]] 对象的属性。这就是在 JavaScript 中获得类似于传统类继承的方法。

最困难的部分是第 2 点。每个对象(包括函数)都有这个称为 [[prototype]] 的内部属性。它 只能 在对象创建时设置,可以使用 newObject.create 或基于字面量(函数默认为 Function.prototype,数字为 Number.prototype 等)。它只能用 Object.getPrototypeOf(someObject) 读取。 没有 其他方法可以设置或读取此值。

函数,除了隐藏的 [[prototype]] 属性外,还有一个称为 原型 的属性,您可以访问和修改它,为您创建的对象提供继承的属性和方法。


这是一个例子:

 ObjMaker = function() {this.a = 'first';};
 // ObjMaker is just a function, there's nothing special about it that makes
 // it a constructor.

 ObjMaker.prototype.b = 'second';
 // like all functions, ObjMaker has an accessible prototype property that
 // we can alter. I just added a property called 'b' to it. Like
 // all objects, ObjMaker also has an inaccessible [[prototype]] property
 // that we can't do anything with

 obj1 = new ObjMaker();
 // 3 things just happened.
 // A new, empty object was created called obj1. At first obj1 was the same
 // as {}. The [[prototype]] property of obj1 was then set to the current
 // object value of the ObjMaker.prototype (if ObjMaker.prototype is later
 // assigned a new object value, obj1's [[prototype]] will not change, but you
 // can alter the properties of ObjMaker.prototype to add to both the
 // prototype and [[prototype]]). The ObjMaker function was executed, with
 // obj1 in place of this... so obj1.a was set to 'first'.

 obj1.a;
 // returns 'first'
 obj1.b;
 // obj1 doesn't have a property called 'b', so JavaScript checks
 // its [[prototype]]. Its [[prototype]] is the same as ObjMaker.prototype
 // ObjMaker.prototype has a property called 'b' with value 'second'
 // returns 'second'

这就像类继承,因为现在,您使用 new ObjMaker() 创建的任何对象似乎也继承了“b”属性。

如果你想要一个子类之类的东西,那么你可以这样做:

 SubObjMaker = function () {};
 SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated!
 // Because we used 'new', the [[prototype]] property of SubObjMaker.prototype
 // is now set to the object value of ObjMaker.prototype.
 // The modern way to do this is with Object.create(), which was added in ECMAScript 5:
 // SubObjMaker.prototype = Object.create(ObjMaker.prototype);

 SubObjMaker.prototype.c = 'third';
 obj2 = new SubObjMaker();
 // [[prototype]] property of obj2 is now set to SubObjMaker.prototype
 // Remember that the [[prototype]] property of SubObjMaker.prototype
 // is ObjMaker.prototype. So now obj2 has a prototype chain!
 // obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype

 obj2.c;
 // returns 'third', from SubObjMaker.prototype

 obj2.b;
 // returns 'second', from ObjMaker.prototype

 obj2.a;
 // returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype
 // was created with the ObjMaker function, which assigned a for us


在最终找到 这个页面 之前,我阅读了大量关于这个主题的垃圾,其中用漂亮的图表很好地解释了这一点。

原文由 Daniel Howard 发布,翻译遵循 CC BY-SA 4.0 许可协议

假设你有这个功能:

 var Foo = function(){
  this.A = 1;
  this.B = 2;
};

如果您将其称为独立函数,如下所示:

 Foo();

执行此函数将向 window 对象添加两个属性( AB )。它将它添加到 window 因为 window 是当你这样执行它时调用函数的对象,而 this 调用函数的对象是对象功能。至少在 JavaScript 中。

现在,用 new 这样称呼它:

 var bar = new Foo();

When you add new to a function call, a new object is created (just var bar = new Object() ) and the this within the function points to the new Object 你刚刚创建的,而不是调用函数的对象。所以 bar 现在是一个具有属性 AB 的对象。任何函数都可以是构造函数;它并不总是有意义。

原文由 JulianR 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题