使用“ Object.create”代替“ new”

一笑奈何 提交于 2020-02-26 09:32:16

Javascript 1.9.3 / ECMAScript 5引入了Object.create ,这是Douglas Crockford等人提倡的很长时间了。 如何使用Object.create替换下面代码中的new

var UserA = function(nameParam) {
    this.id = MY_GLOBAL.nextId();
    this.name = nameParam;
}
UserA.prototype.sayHello = function() {
    console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();

(假设存在MY_GLOBAL.nextId )。

我能想到的最好的是:

var userB = {
    init: function(nameParam) {
        this.id = MY_GLOBAL.nextId();
        this.name = nameParam;
    },
    sayHello: function() {
        console.log('Hello '+ this.name);
    }
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();

似乎没有任何优势,所以我想我没有。 我可能太新古典了。 我应该如何使用Object.create创建用户“ bob”?


#1楼

您可以使init方法返回this ,然后将调用链接在一起,如下所示:

var userB = {
    init: function(nameParam) {
        this.id = MY_GLOBAL.nextId();
        this.name = nameParam;
        return this;
    },
    sayHello: function() {
        console.log('Hello '+ this.name);
    }
};

var bob = Object.create(userB).init('Bob');

#2楼

Object.create的另一种可能用法是以廉价且有效的方式克隆不可变对象。

var anObj = {
    a: "test",
    b: "jest"
};

var bObj = Object.create(anObj);

bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj

// now bObj is {a: test, b: gone, c: brand}

注意 :上面的代码片段创建了源对象的克隆(也就是不是引用,如cObj = aObj)。 它优于copy-properties方法(请参见1 ),因为它不会复制对象成员属性。 而是创建另一个-destination-对象,并将其原型设置在源对象上。 此外,当在目标对象上修改属性时,它们会“即时”创建,从而掩盖了原型的(src)属性。这是一种克隆不可变对象的快速有效方法。

需要注意的是,这适用于在创建后不可修改的源对象(不可变的)。 如果在创建后修改了源对象,那么所有克隆的未屏蔽属性也将被修改。

在此处拨弄( http://jsfiddle.net/y5b5q/1/ )(需要Object.create功能的浏览器)。


#3楼

使用Object.create(...)对于new object确实没有任何优势。

那些主张使用此方法的人通常会说出相当模糊的优点: “可伸缩性”或“ 对JavaScript更自然 ”等。

但是,我还没有看到一个具体的示例,该示例表明Object.create与使用new相比具有任何优势。 相反,存在已知问题。 Sam Elsamman描述了当嵌套对象并使用Object.create(...)时会发生的情况

var Animal = {
    traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!

发生这种情况是因为Object.create(...)提倡一种使用数据来创建新对象的做法。 在这里, Animal基准面成为lionbird原型的一部分,并且由于共享而引起问题。 使用new时,原型继承是显式的:

function Animal() {
    this.traits = {};
}

function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();

var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4

关于传递到Object.create(...)的可选属性,可以使用Object.defineProperties(...)添加这些属性。


#4楼

优点是Object.create通常在大多数浏览器中都比new

在这个jsperf示例中 ,在Chromium中, new浏览器的速度Object.create(obj) 30倍,尽管两者都非常快。 这一切都是很奇怪的,因为new要做更多的事情(例如调用构造函数),其中Object.create应该只是将传入的对象作为原型创建一个新的Object(用Crockford说的秘密链接)

也许浏览器没有赶上Object.create高效性(也许它们是基于new的幕后...甚至是本机代码)


#5楼

TL; DR:

new Computer()将调用构造函数Function Computer(){}一次,而Object.create(Computer.prototype)不会。

所有优点都基于这一点。

关于性能的旁注:类似于new Computer()构造函数调用已由引擎进行了优化,因此它甚至可能比Object.create更快。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!