理解Object.create()和new SomeFunction()之间的区别

我最近偶然发现了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/

152821 次浏览

在内部Object.create这样做:

Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};

语法只是消除了JavaScript使用经典继承的错觉。

object中使用的对象。create实际上形成了新对象的原型,而在new Function()形式中,声明的属性/函数不形成原型。

是的,Object.create构建了一个对象,该对象直接继承作为其第一个参数传递的对象。

使用构造函数,新创建的对象继承自构造函数的原型,例如:

var o = new SomeConstructor();

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

这里有一个区别,使用Object.create,你可以创建一个不继承任何东西的对象Object.create(null);,另一方面,如果你设置SomeConstructor.prototype = null;,新创建的对象将继承Object.prototype

你不能用对象创建闭包。像使用函数式语法一样创建语法。考虑到JavaScript的词法(相对于块)类型范围,这是合乎逻辑的。

你可以创建闭包,例如使用属性描述符参数:

var o = Object.create({inherited: 1}, {
foo: {
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
}
});


o.foo; // "foobar"

注意,我说的是ECMAScript第5版Object.create方法,而不是Crockford's shim。

该方法开始在最新的浏览器上本机实现,检查这个兼容性表

下面是两个调用内部发生的步骤 (提示:唯一的区别是在步骤3)


new Test():

  1. 创建new Object() obj
  2. obj.__proto__设置为Test.prototype
  3. return Test.call(obj) || obj; //通常返回obj,但JS中的构造函数可以返回值

Object.create( Test.prototype )

  1. 创建new Object() obj
  2. obj.__proto__设置为Test.prototype
  3. return obj;

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

区别在于所谓的“伪经典vs.原型继承”。建议在代码中只使用一种类型,不要混合使用两种类型。

在伪经典继承中(使用"new"操作符),假设您首先定义了一个伪类,然后从该类创建对象。例如,定义一个伪类“Person”,然后从“Person”创建“Alice”和“Bob”。

在原型继承中(使用Object.create),您直接创建一个特定的人“Alice”,然后使用“Alice”作为原型创建另一个人“Bob”。这里没有“阶级”;都是对象。

在内部,JavaScript使用“原型继承”;“伪古典”的方式只是一些糖。

两种方法的比较请参见这个链接

简单地说,new XObject.create(X.prototype),另外运行constructor函数。(并使constructor有机会return应该是表达式结果的实际对象,而不是this。)

就是这样。:)

其余的答案只是令人困惑,因为显然没有人读的定义。;)

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)使用new关键字有两件事要注意;

A)函数被用作构造函数

b) function.prototype对象被传递给__proto__属性…或者不支持__proto__的地方,则是新对象查找属性的第二个位置

2)使用Object.create(obj.prototype)你正在构造一个对象(obj.prototype)并将其传递给预期的对象。不同的是,现在new object的__proto__也指向obj。原型(请参考ans by xj9)

这样的:

var foo = new Foo();

而且

var foo = Object.create(Foo.prototype);

非常相似。一个重要的区别是new Foo实际上运行构造函数代码,而Object.create不会执行诸如

function Foo() {
alert("This constructor does not run with Object.create");
}

注意,如果你使用双参数版本的Object.create(),那么你可以做更强大的事情。

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

    当你编写Car构造函数var Car = function(){}时,内部是这样的: A diagram of prototypal chains when creating javascript objects 我们有一个{prototype}隐藏链接到Function.prototype,这个链接是不可访问的,而一个prototype链接到Car.prototype,这个链接是可访问的,并且有一个实际的constructorCar。这两个函数。原型和汽车。 . prototype包含Object.prototype的隐藏链接 当我们想通过使用new操作符和create方法创建两个等价的对象时,我们必须这样做:Honda = new Car();Maruti = Object.create(Car.prototype)用于不同对象创建方法的原型链图 发生了什么?< / p > < p > Honda = new Car();本;当你创建这样一个对象时,隐藏的{prototype}属性会指向Car.prototype。因此在这里,Honda对象的{prototype}始终是Car.prototype —我们没有任何选项来改变对象的{prototype}属性。如果我想改变新创建对象的原型呢?< br > Maruti = Object.create(Car.prototype) < / >强本;当你创建一个这样的对象时,你有一个额外的选项来选择对象的{prototype}属性。如果你想要Car。原型作为{prototype},然后将其作为函数的参数传递。如果你的对象不需要任何{prototype},那么你可以像这样传递null: Maruti = Object.create(null).

结论本;通过使用Object.create方法,你可以自由地选择对象的{prototype}属性。在new Car();中,你没有这样的自由。

面向对象JavaScript的首选方式:

假设我们有两个对象ab

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

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

Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
我们想要对象a作为b的原型,但是在这里我们用原型Object.prototype创建了对象bECMAScript 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()对于继承非常有用。

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

  1. 创建新对象。

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

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

  4. 使用new对象执行构造函数,隐式执行return this;

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

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

对象创建变量。


变体1: '新对象()' ->不带参数的对象构造函数。

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


变种2: '新对象(人)' ->带参数的对象构造函数。

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


__abc0: ' __abc1 '。使用对象。用简单的对象“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


__abc0: ' __abc1 '。使用对象。创建内置对象-> ' 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


__abc0: ' __abc1 '

// '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

Object.create(Constructor.prototype)new Constructor的一部分

这是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 Constructor实现包含Object.create方法

      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));