Understanding the difference between Object.create() and new SomeFunction()
我最近偶然发现了javascript中的
请考虑以下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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的词汇(vs块)类型范围。
以上说法正确吗?我错过什么了吗?你什么时候用一个比另一个?
编辑:链接到上述代码的jsFiddle版本示例:http://jsFiddle.net/rzfyl/
很简单地说,
就是这样。:)
其余的答案都是令人困惑的,因为显然没有其他人读过
The object used in Object.create actually forms the prototype of the new object, where as in the new Function() form the declared properties/functions do not form the prototype.
是的,
使用构造函数函数,新创建的对象继承了构造函数的原型,例如:
1 | var o = new SomeConstructor(); |
在上面的例子中,
这里有一个区别,使用
You cannot create closures with the Object.create syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.
好吧,您可以创建闭包,例如使用属性描述符参数:
1 2 3 4 5 6 7 8 9 10 11 12 | var o = Object.create({inherited: 1}, { foo: { get: (function () { // a closure var closured = 'foo'; return function () { return closured+'bar'; }; })() } }); o.foo; //"foobar" |
注意,我所说的是ECMAScript第五版
该方法已开始在最新的浏览器上本机实现,请检查此兼容性表。
以下是两个调用的内部步骤:(提示:唯一的区别在步骤3中)
// normally obj is returned but constructors in JS can return a value
所以基本上
让我试着解释一下(更多关于博客的内容):
当我们想使用
结论:通过使用
OO javascript中的首选方法:
假设我们有两个对象:
1 2 | var a = new Object(); var b = new Object(); |
现在,假设
1 2 | Object.prototype.isPrototypeOf(b); //true a.isPrototypeOf(b); //false (the problem comes into the picture here). |
问题—我们希望对象
1 | var b = Object.create(a); |
然后,
1 | a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.) |
因此,如果您正在执行面向对象的脚本,那么
这是:
1 | var foo = new Foo(); |
和
1 | var foo = Object.create(Foo.prototype); |
非常相似。一个重要的区别是,
1 2 3 | function Foo() { alert("This constructor does not run with Object.create"); } |
注意,如果您使用两参数版本的
区别在于所谓的"伪经典与原型继承"。建议在代码中只使用一种类型,而不要混合使用这两种类型。
在伪经典继承(使用"new"运算符)中,假设您首先定义了一个伪类,然后从该类创建对象。例如,定义一个伪类"person",然后从"person"创建"alice"和"bob"。
在原型继承(使用object.create)中,直接创建一个特定的人"alice",然后使用"alice"作为原型创建另一个人"bob"。这里没有"类";所有的都是对象。
在内部,JavaScript使用"原型继承";"伪经典"方法只是一些甜头。
请参阅此链接以了解这两种方法的比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function Test(){ this.prop1 = 'prop1'; this.prop2 = 'prop2'; this.func1 = function(){ return this.prop1 + this.prop2; } }; Test.prototype.protoProp1 = 'protoProp1'; Test.prototype.protoProp2 = 'protoProp2'; var newKeywordTest = new Test(); var objectCreateTest = Object.create(Test.prototype); /* Object.create */ console.log(objectCreateTest.prop1); // undefined console.log(objectCreateTest.protoProp1); // protoProp1 console.log(objectCreateTest.__proto__.protoProp1); // protoProp1 /* new */ console.log(newKeywordTest.prop1); // prop1 console.log(newKeywordTest.__proto__.protoProp1); // protoProp1 |
总结:
1)对于
a)函数用作构造函数
b)将
2)使用
在内部,
1 2 3 4 5 | Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; |
语法消除了JavaScript使用经典继承的假象。
因此,对于这个答案和这个视频,
创建新对象。
将新对象链接到构造函数函数(
使
使用新对象执行构造器函数,隐式执行
将构造函数函数名赋给新对象的属性
对象创建变量。
变量1:"new object()"->不带参数的对象构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | var p1 = new Object(); // 'new Object()' create and return empty object -> {} var p2 = new Object(); // 'new Object()' create and return empty object -> {} console.log(p1); // empty object -> {} console.log(p2); // empty object -> {} // p1 and p2 are pointers to different objects console.log(p1 === p2); // false console.log(p1.prototype); // undefined // empty object which is in fact Object.prototype console.log(p1.__proto__); // {} // empty object to which p1.__proto__ points console.log(Object.prototype); // {} console.log(p1.__proto__ === Object.prototype); // true // null, which is in fact Object.prototype.__proto__ console.log(p1.__proto__.__proto__); // null console.log(Object.prototype.__proto__); // null |
变量2:"new object(person)"->带参数的对象构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | const person = { name: 'no name', lastName: 'no lastName', age: -1 } // 'new Object(person)' return 'person', which is pointer to the object -> // -> { name: 'no name', lastName: 'no lastName', age: -1 } var p1 = new Object(person); // 'new Object(person)' return 'person', which is pointer to the object -> // -> { name: 'no name', lastName: 'no lastName', age: -1 } var p2 = new Object(person); // person, p1 and p2 are pointers to the same object console.log(p1 === p2); // true console.log(p1 === person); // true console.log(p2 === person); // true p1.name = 'John'; // change 'name' by 'p1' p2.lastName = 'Doe'; // change 'lastName' by 'p2' person.age = 25; // change 'age' by 'person' // when print 'p1', 'p2' and 'person', it's the same result, // because the object they points is the same console.log(p1); // { name: 'John', lastName: 'Doe', age: 25 } console.log(p2); // { name: 'John', lastName: 'Doe', age: 25 } console.log(person); // { name: 'John', lastName: 'Doe', age: 25 } |
变量3.1:"object.create(person)"。使用object.create和简单对象"person"。对象。create(person)'将创建(并返回)新的空对象,并将属性"uu proto_uuuuuu"添加到同一个新的空对象。此属性"proto"将指向对象"person"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | const person = { name: 'no name', lastName: 'no lastName', age: -1, getInfo: function getName() { return `${this.name} ${this.lastName}, ${this.age}!`; } } var p1 = Object.create(person); var p2 = Object.create(person); // 'p1.__proto__' and 'p2.__proto__' points to // the same object -> 'person' // { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] } console.log(p1.__proto__); console.log(p2.__proto__); console.log(p1.__proto__ === p2.__proto__); // true console.log(person.__proto__); // {}(which is the Object.prototype) // 'person', 'p1' and 'p2' are different console.log(p1 === person); // false console.log(p1 === p2); // false console.log(p2 === person); // false // { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] } console.log(person); console.log(p1); // empty object - {} console.log(p2); // empty object - {} // add properties to object 'p1' // (properties with the same names like in object 'person') p1.name = 'John'; p1.lastName = 'Doe'; p1.age = 25; // add properties to object 'p2' // (properties with the same names like in object 'person') p2.name = 'Tom'; p2.lastName = 'Harrison'; p2.age = 38; // { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] } console.log(person); // { name: 'John', lastName: 'Doe', age: 25 } console.log(p1); // { name: 'Tom', lastName: 'Harrison', age: 38 } console.log(p2); // use by '__proto__'(link from 'p1' to 'person'), // person's function 'getInfo' console.log(p1.getInfo()); // John Doe, 25! // use by '__proto__'(link from 'p2' to 'person'), // person's function 'getInfo' console.log(p2.getInfo()); // Tom Harrison, 38! |
变量3.2:"object.create(object.prototype)"。使用object.create和内置对象->"object.prototype".object.create(object.prototype)将创建(并返回)新的空对象,并将属性"uu proto_uuuuuuuu"添加到同一个新的空对象。此属性"proto"将指向对象"object.prototype"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // 'Object.create(Object.prototype)' : // 1. create and return empty object -> {}. // 2. add to 'p1' property '__proto__', which is link to 'Object.prototype' var p1 = Object.create(Object.prototype); // 'Object.create(Object.prototype)' : // 1. create and return empty object -> {}. // 2. add to 'p2' property '__proto__', which is link to 'Object.prototype' var p2 = Object.create(Object.prototype); console.log(p1); // {} console.log(p2); // {} console.log(p1 === p2); // false console.log(p1.prototype); // undefined console.log(p2.prototype); // undefined console.log(p1.__proto__ === Object.prototype); // true console.log(p2.__proto__ === Object.prototype); // true |
变量4:"new someFunction()"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | // 'this' in constructor-function 'Person' // represents a new instace, // that will be created by 'new Person(...)' // and returned implicitly function Person(name, lastName, age) { this.name = name; this.lastName = lastName; this.age = age; //----------------------------------------------------------------- // !--- only for demonstration --- // if add function 'getInfo' into // constructor-function 'Person', // then all instances will have a copy of the function 'getInfo'! // // this.getInfo: function getInfo() { // return this.name +"" + this.lastName +"," + this.age +"!"; // } //----------------------------------------------------------------- } // 'Person.prototype' is an empty object // (before add function 'getInfo') console.log(Person.prototype); // Person {} // With 'getInfo' added to 'Person.prototype', // instances by their properties '__proto__', // will have access to the function 'getInfo'. // With this approach, instances not need // a copy of the function 'getInfo' for every instance. Person.prototype.getInfo = function getInfo() { return this.name +"" + this.lastName +"," + this.age +"!"; } // after function 'getInfo' is added to 'Person.prototype' console.log(Person.prototype); // Person { getInfo: [Function: getInfo] } // create instance 'p1' var p1 = new Person('John', 'Doe', 25); // create instance 'p2' var p2 = new Person('Tom', 'Harrison', 38); // Person { name: 'John', lastName: 'Doe', age: 25 } console.log(p1); // Person { name: 'Tom', lastName: 'Harrison', age: 38 } console.log(p2); // 'p1.__proto__' points to 'Person.prototype' console.log(p1.__proto__); // Person { getInfo: [Function: getInfo] } // 'p2.__proto__' points to 'Person.prototype' console.log(p2.__proto__); // Person { getInfo: [Function: getInfo] } console.log(p1.__proto__ === p2.__proto__); // true // 'p1' and 'p2' points to different objects(instaces of 'Person') console.log(p1 === p2); // false // 'p1' by its property '__proto__' reaches 'Person.prototype.getInfo' // and use 'getInfo' with 'p1'-instance's data console.log(p1.getInfo()); // John Doe, 25! // 'p2' by its property '__proto__' reaches 'Person.prototype.getInfo' // and use 'getInfo' with 'p2'-instance's data console.log(p2.getInfo()); // Tom Harrison, 38! |