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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 11:12:34  来源:igfitidea点击:

Understanding the difference between Object.create() and new SomeFunction()

javascriptprototypeobject-create

提问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 the new 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.createbuilds 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, oinherits directly from SomeConstructor.prototype.

在上面的例子中,o直接继承自SomeConstructor.prototype.

There's a difference here, with Object.createyou 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.createmethod, 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 Xis Object.create(X.prototype)with additionally running the constructorfunction. (And giving the constructorthe chance to returnthe 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 neweither. ;)

其余的答案只是令人困惑,因为显然没有其他人阅读两者的定义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()

  1. create new Object()obj
  2. set obj.__proto__to Test.prototype
  3. return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value
  1. 创建new Object()对象
  2. 设置obj.__proto__Test.prototype
  3. 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 )

  1. create new Object()obj
  2. set obj.__proto__to Test.prototype
  3. return obj;
  1. 创建new Object()对象
  2. 设置obj.__proto__Test.prototype
  3. return obj;


So basically Object.createdoesn't execute the constructor.

所以基本上Object.create不执行构造函数。

回答by Anshul

Let me try to explain (more on Blog) :

让我试着解释一下(更多关于博客):

  1. When you write Carconstructor var Car = function(){}, this is how things are internally: A diagram of prototypal chains when creating javascript objectsWe have one {prototype}hidden link to Function.prototypewhich is not accessible and one prototypelink to Car.prototypewhich is accessible and has an actual constructorof Car. Both Function.prototype and Car.prototype have hidden links to Object.prototype.
  2. When we want to create two equivalent objects by using the newoperator and createmethod then we have to do it like this: Honda = new Car();and Maruti = Object.create(Car.prototype).A diagram of prototypal chains for differing object creation methodsWhat 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 nulllike this: Maruti = Object.create(null).

  1. 当您编写Carconstructor 时var Car = function(){},内部情况是这样的: 创建javascript对象时的原型链图我们有一个无法访问的{prototype}隐藏链接Function.prototype和一个可访问的prototype链接,Car.prototype并且具有实际constructorCar. Function.prototype 和 Car.prototype 都有指向Object.prototype.
  2. 当我们想使用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.createyou 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 aand b.

假设我们有两个对象ab

var a = new Object();
var b = new Object();

Now, suppose ahas some methods which balso wants to access. For that, we require object inheritance (ashould be the prototype of bonly if we want access to those methods). If we check the prototypes of aand bthen we will find out that they share the prototype Object.prototype.

现在,假设a有一些方法b也想访问。为此,我们需要对象继承(仅当我们想要访问这些方法时才a应该是原型b)。如果我们检查的原型ab那么我们会发现,它们共享原型Object.prototype

Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).

Problem —we want object aas the prototype of b, but here we created object bwith the prototype Object.prototype. Solution —ECMAScript 5 introduced Object.create(), to achieve such inheritance easily. If we create object blike 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 Fooactually runs constructor code, whereas Object.createwill 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 newkeyword there are two things to note;

1) 使用new关键字有两点需要注意;

a) function is used as a constructor

a) 函数用作构造函数

b) function.prototypeobject 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

enter image description here

在此处输入图片说明



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 }

enter image description here

在此处输入图片说明



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!

enter image description here

在此处输入图片说明



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

enter image description here

在此处输入图片说明



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!

enter image description here

在此处输入图片说明

回答by xj9

Internally Object.createdoes 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 videonewkeyword does next things:

根据这个答案这个视频new关键字做接下来的事情:

  1. Creates new object.

  2. Links new object to constructor function (prototype).

  3. Makes thisvariable point to the new object.

  4. Executes constructor function using the new object and implicit perform return this;

  5. Assigns constructor function name to new object's property constructor.

  1. 创建新对象。

  2. 将新对象链接到构造函数 ( prototype)。

  3. 使this变量指向新对象。

  4. 使用新对象和隐式执行执行构造函数return this

  5. 将构造函数名称分配给新对象的属性constructor

Object.createperforms only 1stand 2ndsteps!!!

Object.create只执行1st2nd步骤!!!