我最近偶然发现了JavaScript中的object .create()方法,并试图推断它与使用new SomeFunction()创建对象的新实例有何不同,以及当您想要使用其中一个而不是另一个时。
考虑下面的例子:
var test = {
val: 1,
func: function() {
return this.val;
}
};
var testA = Object.create(test);
testA.val = 2;
console.log(test.func()); // 1
console.log(testA.func()); // 2
console.log('other test');
var otherTest = function() {
this.val = 1;
this.func = function() {
return this.val;
};
};
var otherTestA = new otherTest();
var otherTestB = new otherTest();
otherTestB.val = 2;
console.log(otherTestA.val); // 1
console.log(otherTestB.val); // 2
console.log(otherTestA.func()); // 1
console.log(otherTestB.func()); // 2
请注意,在这两种情况下观察到相同的行为。在我看来,这两种情况的主要区别是:
在object .create()中使用的对象实际上形成了新对象的原型,而在new Function()中声明的属性/函数不形成原型。
不能像使用函数式语法一样使用Object.create()语法创建闭包。考虑到JavaScript的词法(相对于块)类型范围,这是合乎逻辑的。
上述说法正确吗?我是不是遗漏了什么?什么时候你会使用其中一种而不是另一种?
编辑:链接到上述代码示例的jsfiddle版本:http://jsfiddle.net/rZfYL/
让我试着解释(更多在博客上):
When you write Car constructor var Car = function(){}, this is how things are internally:
We have one {prototype} hidden link to Function.prototype which is not accessible and one prototype link to Car.prototype which is accessible and has an actual constructor of Car. Both Function.prototype and Car.prototype have hidden links to Object.prototype.
When we want to create two equivalent objects by using the new operator and create method then we have to do it like this: Honda = new Car(); and Maruti = Object.create(Car.prototype).
What is happening?
Honda = new Car(); — When you create an object like this then hidden {prototype} property is pointed to Car.prototype. So here, the {prototype} of the Honda object will always be Car.prototype — we don't have any option to change the {prototype} property of the object. What if I want to change the prototype of our newly created object?
Maruti = Object.create(Car.prototype) — When you create an object like this you have an extra option to choose your object's {prototype} property. If you want Car.prototype as the {prototype} then pass it as a parameter in the function. If you don't want any {prototype} for your object then you can pass null like this: Maruti = Object.create(null).
结论-通过使用方法对象。创建时你可以自由选择你的对象{prototype}属性。在new Car();中,你没有这样的自由。
面向对象JavaScript的首选方式:
假设我们有两个对象a和b。
var a = new Object();
var b = new Object();
现在,假设a有一些b也想访问的方法。为此,我们需要对象继承(只有当我们想要访问这些方法时,a才应该是b的原型)。如果我们检查a和b的原型,我们会发现它们共享Object.prototype原型。
Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
问题-我们想要对象a作为b的原型,但是在这里我们用原型object .prototype创建了对象b。
解决方案- ECMAScript 5引入了Object.create(),可以轻松实现这种继承。如果我们像这样创建对象b:
var b = Object.create(a);
然后,
a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
因此,如果你正在编写面向对象的脚本,那么object .create()对于继承非常有用。
Object.create(Constructor.prototype)是new Constructor的一部分
这是新的构造函数实现
// 1. define constructor function
function myConstructor(name, age) {
this.name = name;
this.age = age;
}
myConstructor.prototype.greet = function(){
console.log(this.name, this.age)
};
// 2. new operator implementation
let newOperatorWithConstructor = function(name, age) {
const newInstance = new Object(); // empty object
Object.setPrototypeOf(newInstance, myConstructor.prototype); // set prototype
const bindedConstructor = myConstructor.bind(newInstance); // this binding
bindedConstructor(name, age); // execute binded constructor function
return newInstance; // return instance
};
// 3. produce new instance
const instance = new myConstructor("jun", 28);
const instance2 = newOperatorWithConstructor("jun", 28);
console.log(instance);
console.log(instance2);
new构造函数实现包含Object。创建方法
newOperatorWithConstructor = function(name, age) {
const newInstance = Object.create(myConstructor.prototype); // empty object, prototype chaining
const bindedConstructor = myConstructor.bind(newInstance); // this binding
bindedConstructor(name, age); // execute binded constructor function
return newInstance; // return instance
};
console.log(newOperatorWithConstructor("jun", 28));
让我试着解释(更多在博客上):
When you write Car constructor var Car = function(){}, this is how things are internally:
We have one {prototype} hidden link to Function.prototype which is not accessible and one prototype link to Car.prototype which is accessible and has an actual constructor of Car. Both Function.prototype and Car.prototype have hidden links to Object.prototype.
When we want to create two equivalent objects by using the new operator and create method then we have to do it like this: Honda = new Car(); and Maruti = Object.create(Car.prototype).
What is happening?
Honda = new Car(); — When you create an object like this then hidden {prototype} property is pointed to Car.prototype. So here, the {prototype} of the Honda object will always be Car.prototype — we don't have any option to change the {prototype} property of the object. What if I want to change the prototype of our newly created object?
Maruti = Object.create(Car.prototype) — When you create an object like this you have an extra option to choose your object's {prototype} property. If you want Car.prototype as the {prototype} then pass it as a parameter in the function. If you don't want any {prototype} for your object then you can pass null like this: Maruti = Object.create(null).
结论-通过使用方法对象。创建时你可以自由选择你的对象{prototype}属性。在new Car();中,你没有这样的自由。
面向对象JavaScript的首选方式:
假设我们有两个对象a和b。
var a = new Object();
var b = new Object();
现在,假设a有一些b也想访问的方法。为此,我们需要对象继承(只有当我们想要访问这些方法时,a才应该是b的原型)。如果我们检查a和b的原型,我们会发现它们共享Object.prototype原型。
Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
问题-我们想要对象a作为b的原型,但是在这里我们用原型object .prototype创建了对象b。
解决方案- ECMAScript 5引入了Object.create(),可以轻松实现这种继承。如果我们像这样创建对象b:
var b = Object.create(a);
然后,
a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
因此,如果你正在编写面向对象的脚本,那么object .create()对于继承非常有用。