new
JavaScript 中的关键字在第一次遇到时可能会非常混乱,因为人们往往认为 JavaScript 不是面向对象的编程语言。
- 它是什么?
- 它解决了哪些问题?
- 什么时候合适,什么时候不合适?
new
JavaScript 中的关键字在第一次遇到时可能会非常混乱,因为人们往往认为 JavaScript 不是面向对象的编程语言。
它做了 5 件事:
this
变量指向新创建的对象。this
提到时使用新创建的对象。null
对象引用。在这种情况下,将返回该对象引用。注意:构造函数指的是new
关键字后面的函数,如
new ConstructorFunction(arg1, arg2)
完成此操作后,如果请求新对象的未定义属性,脚本将改为检查对象的[[prototype]]对象以获取该属性。这就是您如何获得类似于 JavaScript 中传统类继承的东西。
关于这一点最困难的部分是第 2 点。每个对象(包括函数)都有一个称为[[prototype]] 的内部属性。它只能在对象创建时设置,可以使用new、Object.create或基于文字(函数默认为 Function.prototype,数字为 Number.prototype 等)。它只能用Object.getPrototypeOf(someObject)读取。有没有其他的方式来设置或读取此值。
函数,除了隐藏的[[prototype]]属性,还有一个叫做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
在最终找到这个页面之前,我阅读了大量关于这个主题的垃圾,其中用漂亮的图表很好地解释了这一点。
假设你有这个功能:
var Foo = function(){
this.A = 1;
this.B = 2;
};
如果您将其称为独立函数,如下所示:
Foo();
执行此函数将向window
对象(A
和B
)添加两个属性。它将它添加到 thewindow
因为window
当你这样执行它时调用该函数的对象,并且this
在一个函数中是调用该函数的对象。至少在 Javascript 中。
现在,这样称呼它new
:
var bar = new Foo();
当您添加new
到函数调用时会发生什么是创建了一个新对象(只是var bar = new Object()
),并且this
函数内的 指向Object
您刚刚创建的新对象,而不是调用该函数的对象。所以,bar
现在与属性的对象A
和B
。任何函数都可以是构造函数,只是并不总是有意义。
除了丹尼尔霍华德的回答,这里是new
(或至少似乎是):
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
尽管
var obj = New(A, 1, 2);
相当于
var obj = new A(1, 2);
在浏览器控制台中尝试以下代码。
function Foo() {
return this;
}
var a = Foo(); //returns window object
var b = new Foo(); //returns empty object of foo
a instanceof Window; // true
a instanceof Foo; // false
b instanceof Window; // false
b instanceof Foo; // true
现在您可以阅读社区维基答案:)
所以它可能不是用于创建对象的实例
它正是为此而使用的。您可以像这样定义一个函数构造函数:
function Person(name) {
this.name = name;
}
var john = new Person('John');
然而,ECMAScript 的额外好处是您可以扩展该.prototype
属性,因此我们可以执行以下操作...
Person.prototype.getName = function() { return this.name; }
从此构造函数创建的所有对象现在都有一个,getName
因为它们可以访问原型链。