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

Javascript 理解Object.create()和new SomeFunction()之间的区别,javascript,prototype,object-create,Javascript,Prototype,Object Create,我最近偶然发现了JavaScript中的Object.create()方法,并试图推断它与使用new SomeFunction()创建对象的新实例有什么不同,以及何时您希望使用一个实例而不是另一个实例 考虑以下示例: var测试={ 瓦尔:1, func:function(){ 返回此.val; } }; var testA=Object.create(测试); testA.val=2; console.log(test.func());//1. console.log(testA.func(

我最近偶然发现了JavaScript中的
Object.create()
方法,并试图推断它与使用
new SomeFunction()
创建对象的新实例有什么不同,以及何时您希望使用一个实例而不是另一个实例

考虑以下示例:

var测试={
瓦尔:1,
func:function(){
返回此.val;
}
};
var testA=Object.create(测试);
testA.val=2;
console.log(test.func());//1.
console.log(testA.func());//2.
console.log(“其他测试”);
var otherTest=函数(){
这个值=1;
this.func=函数(){
返回此.val;
};
};
var otherTestA=新的otherTest();
var otherTestB=新的otherTest();
其他测试b.val=2;
console.log(otherTestA.val);//1.
console.log(otherTestB.val);//2.
console.log(otherTestA.func());//1.

console.log(otherTestB.func());//2
内部
对象。创建
执行以下操作:

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};
语法只是消除了JavaScript使用经典继承的错觉

object.create中使用的对象实际上构成了新对象的原型,而在new Function()表单中,声明的属性/函数并不构成原型

是,
Object.create
生成一个直接从作为第一个参数传递的对象继承的对象

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 }
使用构造函数函数,新创建的对象继承自构造函数的原型,例如:

var o = new SomeConstructor();
在上面的示例中,
o
直接从
SomeConstructor.prototype
继承

这里有一个区别,就是
Object.create
你可以创建一个不从任何东西继承的对象,
Object.create(null)SomeConstructor.prototype=null
新创建的对象将继承自
object.prototype

不能像使用函数语法一样使用Object.create语法创建闭包。考虑到JavaScript的词法(vs块)类型范围,这是合乎逻辑的

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

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

o.foo; // "foobar"
请注意,我说的是ECMAScript第5版方法,而不是Crockford的垫片


该方法已开始在最新浏览器上以本机方式实现,请检查此项。

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


新测试()

  • 创建新对象()obj
  • obj.\uuuu proto\uuuu
    设置为
    Test.prototype
  • returntest.call(obj)| | obj;
    //通常返回obj,但JS中的构造函数可以返回值

  • Object.create(Test.prototype)

  • 创建新对象()obj
  • obj.\uuuu proto\uuuu
    设置为
    Test.prototype
  • 返回obj


  • 因此基本上,
    Object.create
    不执行构造函数。

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

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

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

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


    有关这两种方法的比较,请参见。

    非常简单地说,
    新X
    对象。创建(X.prototype)
    ,并另外运行
    构造函数
    函数。(并使
    构造函数有机会
    返回实际对象,该对象应该是表达式的结果,而不是

    就这样。:)

    其余的答案只是让人困惑,因为显然没有其他人阅读
    new
    的定义

    总结:

    1) 对于
    new
    关键字,有两件事需要注意

    a) 函数用作构造函数

    b)
    function.prototype
    对象被传递到
    \uuuuu proto\uuuu
    属性。。。或者在不支持
    \uuuu proto\uuuu
    的地方,它是新对象查找属性的第二个地方

    2) 使用
    Object.create(obj.prototype)
    您正在构造一个对象(
    obj.prototype
    )并将其传递给预期的对象。不同的是,现在新对象的
    \uuuu proto\uuu
    也指向obj.prototype(请参考xj9的ans)

    这是:

    var foo = new Foo();
    

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

    function Foo() {
        alert("This constructor does not run with Object.create");
    }
    
    请注意,如果您使用双参数版本的
    Object.create()
    ,那么您可以做更强大的事情。

    让我试着解释一下(更多信息):

  • 当您编写
    Car
    构造函数
    var Car=function(){}
    时,内部情况如下: 我们有一个
    {prototype}
    函数的隐藏链接。prototype
    是不可访问的,还有一个
    prototype
    汽车的链接。prototype
    是可访问的,并且有一个
    汽车的实际
    构造函数
    。Function.prototype和Car.prototype都有指向Object.prototype的隐藏链接
  • 当我们想使用
    new
    操作符和
    create
    方法创建两个等效对象时,我们必须这样做:
    Honda=new Car()
    Maruti=Object.create(Car.pr
    
    function Foo() {
        alert("This constructor does not run with Object.create");
    }
    
    var a = new Object();
    var b = new Object();
    
    Object.prototype.isPrototypeOf(b); //true
    a.isPrototypeOf(b); //false (the problem comes into the picture here).
    
    var b = Object.create(a);
    
    a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
    
    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
    
    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 }
    
    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!
    
    // '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
    
    // '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!