Javascript 理解 Object.create() 和 new SomeFunction() 的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4166616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding the difference between Object.create() and new SomeFunction()
提问by Matt
I recently stumbled upon the Object.create()
method in JavaScript, and am trying to deduce how it is different from creating a new instance of an object with new SomeFunction()
, and when you would want to use one over the other.
我最近偶然发现了Object.create()
JavaScript 中的方法,并试图推断它与使用 来创建对象的新实例有何不同new SomeFunction()
,以及何时需要使用一个而不是另一个。
Consider the following example:
考虑以下示例:
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
Notice that the same behaviour is observed in both cases. It seems to me that the primary differences between these two scenarios are:
请注意,在两种情况下都观察到相同的行为。在我看来,这两种情况之间的主要区别是:
- The object used in
Object.create()
actually forms the prototype of the new object, whereas in thenew Function()
from the declared properties/functions do not form the prototype. - 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.
- 中使用的对象
Object.create()
实际上形成了新对象的原型,而new Function()
来自声明的属性/函数的对象不形成原型。 - 您不能
Object.create()
像使用函数式语法那样使用语法创建闭包。考虑到 JavaScript 的词法(vs 块)类型范围,这是合乎逻辑的。
Are the above statements correct? And am I missing something? When would you use one over the other?
以上说法正确吗?我错过了什么吗?你什么时候会使用一个?
EDIT: link to jsfiddle version of above code sample: http://jsfiddle.net/rZfYL/
编辑:链接到上述代码示例的 jsfiddle 版本:http: //jsfiddle.net/rZfYL/
采纳答案by CMS
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.
Object.create 中使用的对象实际上构成了新对象的原型,而在 new Function() 形式中,声明的属性/函数并不构成原型。
Yes, Object.create
builds an object that inherits directly from the one passed as its first argument.
是的,Object.create
构建一个直接从作为第一个参数传递的对象继承的对象。
With constructor functions, the newly created object inherits from the constructor's prototype, e.g.:
使用构造函数,新创建的对象继承自构造函数的原型,例如:
var o = new SomeConstructor();
In the above example, o
inherits directly from SomeConstructor.prototype
.
在上面的例子中,o
直接继承自SomeConstructor.prototype
.
There's a difference here, with Object.create
you can create an object that doesn't inherit from anything, Object.create(null);
, on the other hand, if you set SomeConstructor.prototype = null;
the newly created object will inherit from Object.prototype
.
这里有一个区别,Object.create
您可以创建一个不从任何继承的对象,Object.create(null);
另一方面,如果您设置SomeConstructor.prototype = null;
新创建的对象将从Object.prototype
.
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.
您不能像使用函数式语法那样使用 Object.create 语法创建闭包。考虑到 JavaScript 的词法(vs 块)类型范围,这是合乎逻辑的。
Well, you can create closures, e.g. using property descriptors argument:
好吧,您可以创建闭包,例如使用属性描述符参数:
var o = Object.create({inherited: 1}, {
foo: {
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
}
});
o.foo; // "foobar"
Note that I'm talking about the ECMAScript 5th Edition Object.create
method, not the Crockford's shim.
请注意,我说的是 ECMAScript 第 5 版Object.create
方法,而不是 Crockford 的 shim。
The method is starting to be natively implemented on latest browsers, check this compatibility table.
该方法开始在最新浏览器上本地实现,请查看此兼容性表。
回答by Evi1M4chine
Very simply said, new X
is Object.create(X.prototype)
with additionally running the constructor
function. (And giving the constructor
the chance to return
the actual object that should be the result of the expression instead of this
.)
很简单的说,new X
就是Object.create(X.prototype)
带有额外的运行constructor
功能。(并为实际对象提供constructor
机会,return
该对象应该是表达式的结果而不是this
。)
That's it. :)
就是这样。:)
The rest of the answers are just confusing, because apparently nobody else reads the definition of new
either. ;)
其余的答案只是令人困惑,因为显然没有其他人阅读两者的定义new
。;)
回答by Ray Hulha
Here are the steps that happen internally for both calls:
(Hint: the only difference is in step 3)
以下是两个调用在内部发生的步骤:(
提示:唯一的区别在于第 3 步)
new Test()
:
new Test()
:
- create
new Object()
obj - set
obj.__proto__
toTest.prototype
return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value
- 创建
new Object()
对象 - 设置
obj.__proto__
为Test.prototype
return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value
Object.create( Test.prototype )
Object.create( Test.prototype )
- create
new Object()
obj - set
obj.__proto__
toTest.prototype
return obj;
- 创建
new Object()
对象 - 设置
obj.__proto__
为Test.prototype
return obj;
So basically Object.create
doesn't execute the constructor.
所以基本上Object.create
不执行构造函数。
回答by Anshul
Let me try to explain (more on Blog) :
让我试着解释一下(更多关于博客):
- When you write
Car
constructorvar Car = function(){}
, this is how things are internally:We have one
{prototype}
hidden link toFunction.prototype
which is not accessible and oneprototype
link toCar.prototype
which is accessible and has an actualconstructor
ofCar
. Both Function.prototype and Car.prototype have hidden links toObject.prototype
. When we want to create two equivalent objects by using the
new
operator andcreate
method then we have to do it like this:Honda = new Car();
andMaruti = Object.create(Car.prototype)
.What is happening?
Honda = new Car();
— When you create an object like this then hidden{prototype}
property is pointed toCar.prototype
. So here, the{prototype}
of the Honda object will always beCar.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 passnull
like this:Maruti = Object.create(null)
.
- 当您编写
Car
constructor 时var Car = function(){}
,内部情况是这样的:我们有一个无法访问的
{prototype}
隐藏链接Function.prototype
和一个可访问的prototype
链接,Car.prototype
并且具有实际constructor
的Car
. Function.prototype 和 Car.prototype 都有指向Object.prototype
. 当我们想使用
new
操作符和create
方法创建两个等价的对象时,我们必须这样做:Honda = new Car();
和Maruti = Object.create(Car.prototype)
。怎么了?
Honda = new Car();
— 当您创建这样的对象时,隐藏{prototype}
属性将指向Car.prototype
。所以在这里,{prototype}
本田对象的 将永远是Car.prototype
——我们没有任何选项来改变{prototype}
对象的属性。如果我想改变我们新创建的对象的原型怎么办?Maruti = Object.create(Car.prototype)
— 当您创建这样的对象时,您有一个额外的选项来选择您的对象的{prototype}
属性。如果您希望 Car.prototype 作为 ,{prototype}
则将其作为函数中的参数传递。如果你不希望任何{prototype}
对你的对象,那么你可以通过null
这样的:Maruti = Object.create(null)
。
Conclusion — By using the method Object.create
you have the freedom to choose your object {prototype}
property. In new Car();
, you don't have that freedom.
结论 — 通过使用该方法,Object.create
您可以自由选择对象{prototype}
属性。在new Car();
,你没有那个自由。
Preferred way in OO JavaScript :
OO JavaScript 中的首选方式:
Suppose we have two objects a
and b
.
假设我们有两个对象a
和b
。
var a = new Object();
var b = new Object();
Now, suppose a
has some methods which b
also wants to access. For that, we require object inheritance (a
should be the prototype of b
only if we want access to those methods). If we check the prototypes of a
and b
then we will find out that they share the prototype Object.prototype
.
现在,假设a
有一些方法b
也想访问。为此,我们需要对象继承(仅当我们想要访问这些方法时才a
应该是原型b
)。如果我们检查的原型a
和b
那么我们会发现,它们共享原型Object.prototype
。
Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
Problem —we want object a
as the prototype of b
, but here we created object b
with the prototype Object.prototype
.
Solution —ECMAScript 5 introduced Object.create()
, to achieve such inheritance easily. If we create object b
like this:
问题 —我们希望 objecta
作为 的原型b
,但在这里我们b
使用原型创建了 object Object.prototype
。
解决方案——ECMAScript 5 引入Object.create()
,轻松实现这种继承。如果我们b
像这样创建对象:
var b = Object.create(a);
then,
然后,
a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
So, if you are doing object oriented scripting then Object.create()
is very useful for inheritance.
因此,如果您正在执行面向对象的脚本编写,那么Object.create()
对于继承非常有用。
回答by Leopd
This:
这个:
var foo = new Foo();
and
和
var foo = Object.create(Foo.prototype);
are quite similar. One important difference is that new Foo
actually runs constructor code, whereas Object.create
will not execute code such as
非常相似。一个重要的区别是new Foo
实际运行构造函数代码,而Object.create
不会执行诸如
function Foo() {
alert("This constructor does not run with Object.create");
}
Note that if you use the two-parameter version of Object.create()
then you can do much more powerful things.
请注意,如果您使用Object.create()
then的两个参数版本,您可以做更强大的事情。
回答by user1931858
The difference is the so-called "pseudoclassical vs. prototypal inheritance". The suggestion is to use only one type in your code, not mixing the two.
区别在于所谓的“伪经典与原型继承”。建议是在您的代码中只使用一种类型,而不是混合使用这两种类型。
In pseudoclassical inheritance (with "new" operator), imagine that you first define a pseudo-class, and then create objects from that class. For example, define a pseudo-class "Person", and then create "Alice" and "Bob" from "Person".
在伪经典继承中(使用“new”运算符),假设您首先定义一个伪类,然后从该类创建对象。例如,定义一个伪类“Person”,然后从“Person”创建“Alice”和“Bob”。
In prototypal inheritance (using Object.create), you directly create a specific person "Alice", and then create another person "Bob" using "Alice" as a prototype. There is no "class" here; all are objects.
在原型继承中(使用Object.create),你直接创建一个特定的人“Alice”,然后使用“Alice”作为原型创建另一个人“Bob”。这里没有“类”;都是对象。
Internally, JavaScript uses "prototypal inheritance"; the "pseudoclassical" way is just some sugar.
在内部,JavaScript 使用“原型继承”;“伪经典”的方式只是一些糖。
See this linkfor a comparison of the two ways.
回答by user3124360
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
Summary:
概括:
1) with new
keyword there are two things to note;
1) 使用new
关键字有两点需要注意;
a) function is used as a constructor
a) 函数用作构造函数
b) function.prototype
object is passed to the __proto__
property ... or where __proto__
is not supported, it is the second place where the new object looks to find properties
b)function.prototype
对象传递给__proto__
属性...或者__proto__
不支持的地方,是新对象寻找属性的第二个地方
2) with Object.create(obj.prototype)
you are constructing an object (obj.prototype
) and passing it to the intended object ..with the difference that now new object's __proto__
is also pointing to obj.prototype (please ref ans by xj9 for that)
2)Object.create(obj.prototype)
你正在构造一个对象(obj.prototype
)并将它传递给预期的对象......不同的是现在新对象__proto__
也指向obj.prototype(请参考xj9的答案)
回答by Ted
Object creation variants.
对象创建变体。
Variant 1: 'new Object()' -> Object constructor without arguments.
变体 1:' new Object()' -> 不带参数的对象构造函数。
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
Variant 2: 'new Object(person)' -> Object constructor with argument.
变体 2:' new Object(person)' -> 带参数的对象构造函数。
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 }
Variant 3.1: 'Object.create(person)'. Use Object.create with simple object 'person'. 'Object.create(person)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'person'.
变体 3.1:' Object.create(person)'。将 Object.create 与简单的对象“person”一起使用。'Object.create(person)' 将创建(并返回)新的空对象并将属性 '__proto__' 添加到同一个新的空对象。这个属性 '__proto__' 将指向对象 'person'。
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!
Variant 3.2: 'Object.create(Object.prototype)'. Use Object.create with built-in object -> 'Object.prototype'. 'Object.create(Object.prototype)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'Object.prototype'.
变体 3.2:' Object.create(Object.prototype)'。使用带有内置对象的 Object.create -> 'Object.prototype'。'Object.create(Object.prototype)' 将创建(并返回)新的空对象并将属性 '__proto__' 添加到同一个新的空对象。此属性“__proto__”将指向对象“Object.prototype”。
// '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
Variant 4: 'new SomeFunction()'
变体 4:' new SomeFunction()'
// '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!
回答by xj9
Internally Object.create
does this:
在内部Object.create
这样做:
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
The syntax just takes away the illusion that JavaScript uses Classical Inheritance.
语法只是消除了 JavaScript 使用经典继承的错觉。
回答by V. Kovpak
Accordingly to this answerand to this videonew
keyword does next things:
Creates new object.
Links new object to constructor function (
prototype
).Makes
this
variable point to the new object.Executes constructor function using the new object and implicit perform
return this
;Assigns constructor function name to new object's property
constructor
.
创建新对象。
将新对象链接到构造函数 (
prototype
)。使
this
变量指向新对象。使用新对象和隐式执行执行构造函数
return this
;将构造函数名称分配给新对象的属性
constructor
。
Object.create
performs only 1st
and 2nd
steps!!!
Object.create
只执行1st
和2nd
步骤!!!