Gra*_*ing 364 javascript constructor new-operator object-create
Javascript 1.9.3/ECMAScript 5介绍Object.create道格拉斯·克罗克福德等人长期以来一直在倡导.如何new在下面的代码中替换Object.create?
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();
Run Code Online (Sandbox Code Playgroud)
(假设存在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();
Run Code Online (Sandbox Code Playgroud)
似乎没有任何优势,所以我想我没有得到它.我可能过于新古典主义了.我应该如何使用MY_GLOBAL.nextId创建用户'bob'?
CMS*_*CMS 246
只有一个级别的继承,你的例子可能不会让你看到真正的好处Object.create.
此方法允许您轻松实现差异继承,其中对象可以直接从其他对象继承.
在您的userB例子,我不认为你的init方法应该是公开的,甚至不需要存在,如果再次调用此方法对现有的对象实例,将id和name性质将发生变化.
Object.create 允许您使用第二个参数初始化对象属性,例如:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
Run Code Online (Sandbox Code Playgroud)
如您所见,属性可以在第二个参数上初始化Object.create,对象文字使用类似于Object.defineProperties和Object.defineProperty方法使用的语法.
它可以让你设置属性的属性(enumerable,writable,或configurable),它可以是非常有用的.
Noe*_*ams 49
使用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!!!
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为Object.create(...)提倡使用数据创建新对象的做法; 这里的Animal基准变的原型的部分lion和bird,并且当它是共享的会引起问题.使用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
Run Code Online (Sandbox Code Playgroud)
关于传入的可选属性属性,Object.create(...)可以使用这些属性添加Object.defineProperties(...).
小智 41
Object.create还不是几个浏览器的标准,例如IE8,Opera v11.5,Konq 4.3没有它.您可以为这些浏览器使用Douglas Crockford的Object.create版本,但这不包括CMS答案中使用的第二个"初始化对象"参数.
对于跨浏览器代码,在此期间获得对象初始化的一种方法是定制Crockford的Object.create.这是一种方法: -
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
Run Code Online (Sandbox Code Playgroud)
这维护了Crockford原型继承,并且还检查对象中的任何init方法,然后使用您的参数运行它,比如说new man('John','Smith').你的代码变成: -
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
Run Code Online (Sandbox Code Playgroud)
所以bob继承了sayHello方法,现在有自己的属性id = 1和name ='Bob'.当然,这些属性都是可写的和可枚举的.这也是一种比ECMA Object.create更简单的初始化方法,特别是如果您不关心可写,可枚举和可配置的属性.
对于没有init方法的初始化,可以使用以下Crockford mod: -
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
Run Code Online (Sandbox Code Playgroud)
这将按照定义的顺序在userB参数之后使用Object.gen参数从左到右填充userB自己的属性.它使用for(prop in o)循环,因此,根据ECMA标准,属性枚举的顺序不能保证与属性定义的顺序相同.但是,在(4)主要浏览器上测试的几个代码示例显示它们是相同的,只要使用hasOwnProperty过滤器,有时即使不使用.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Run Code Online (Sandbox Code Playgroud)
我会说比Object.build更简单,因为userB不需要init方法.userB也不是一个特定的构造函数,但看起来像一个普通的单例对象.因此,使用此方法,您可以从普通的普通对象构造和初始化.
Nam*_*ANG 22
TL; DR:
new Computer()将调用构造函数Computer(){}一次,而Object.create(Computer.prototype)不会.
所有优点都基于这一点.
虽然对于一些内部引擎优化的原因,new Computer()可能会更慢,这是不直观的.
sam*_*ces 13
您可以使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');
Run Code Online (Sandbox Code Playgroud)
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}
Run Code Online (Sandbox Code Playgroud)
注意:上面的代码片段创建了一个源对象的克隆(也就是cObj = aObj中的引用,而不是引用).它比copy-properties方法(参见1)更有优势,因为它不会复制对象成员属性.相反,它创建了另一个-destination-对象,并在源对象上设置了原型.此外,当在dest对象上修改属性时,它们是"动态"创建的,掩盖了原型(src)的属性.这构成了克隆不可变对象的快速有效方法.
这里需要注意的是,这适用于创建后不应修改的源对象(不可变).如果在创建后修改了源对象,则也将修改所有克隆的未屏蔽属性.
这里小提琴(http://jsfiddle.net/y5b5q/1/)(需要具有Object.create功能的浏览器).
我认为有问题的主要观点是理解new与Object.create方法之间的区别.根据这个答案和这个视频 new关键字做下一件事:
创建新对象.
将新对象链接到构造函数(prototype).
使this变量指向新对象.
使用新对象执行构造函数并隐式执行return this;
将构造函数名称分配给新对象的属性constructor.
Object.create只执行1st和2nd步骤!!!
在提供的代码示例中,这不是什么大问题,但在下一个示例中它是:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
Run Code Online (Sandbox Code Playgroud)
副作用结果将是:
[ undefined, 'James' ]
Run Code Online (Sandbox Code Playgroud)
因为Guest.prototype = new SiteMember();
但我们不需要执行父构造函数方法,我们只需要getName在Guest中使用make方法.因此我们必须使用Object.create.
如果替换Guest.prototype = new SiteMember();
为Guest.prototype = Object.create(SiteMember.prototype);结果:
[ 'James' ]
Run Code Online (Sandbox Code Playgroud)
有时您无法使用NEW创建对象,但仍然可以调用CREATE方法.
例如:如果要定义自定义元素,则必须从HTMLElement派生.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
173713 次 |
| 最近记录: |