【发布时间】:2014-08-25 21:57:59
【问题描述】:
在 Crockford 的“Good Parts”一书中,他提到要避免使用“new”,因为它是一种反模式,因为该语言是原型语言而不是经典语言。但是,根据他的建议,我无法使用原型属性。我尝试了几种不同的方法:
// 在下面的例子中,我们无法访问原型属性,因为当 parent 用一个可以访问原型属性的函数对象初始化时,当执行 parent 时,我们返回一个对象字面量,它没有有权访问该属性。我们在下面得到的错误是“TypeError: p.info is not a function”。发生这种情况是因为 p 未定义 info,因为 p 是对象文字。它是具有原型属性的父级。
var parent = function(name, age){
var name = name || "";
var age = age || "";
var that = {};
that.name = function(){
return name;
}
that.age = function(){
return age;
}
return that;
}
parent.prototype.info = function(){
return "name: " + this.name() + " age: " + this.age();
}
var p = parent("John",25);
console.log("name: " + p.name() + " age: " + p.age() + " info: " + p.info());
// 这里我们遇到了同样的问题:
var parent = function(name, age){
var name = name || "";
var age = age || "";
return {
name: function(){
return name;
},
age: function(){
return age;
}
}
}
parent.prototype.info = function(){
return "name: " + this.name() + " age: " + this.age();
}
var p = parent("John",25);
console.log("name: " + p.name() + " age: " + p.age() + " info: " + p.info());
// 这也不起作用,因为“p”将是未定义的,因为函数的返回值是未定义的。此外,“this”指的是全局对象,即浏览器中的窗口。
var parent = function(name, age){
var name = name || "";
var age = age || "";
this.name = function(){
return name;
}
this.age = function(){
return age;
}
}
parent.prototype.info = function(){
return "name: " + this.name() + " age: " + this.age();
}
var p = parent("John",25);
console.log("name: " + p.name() + " age: " + p.age() + " info: " + p.info());
// 但是使用“new”关键字来构造对象允许我们访问原型。这一定意味着 Parent 的返回值是一个函数,而不是一个常规对象。根据 Stoyan Stefanov 在他的“Javascript 模式”一书中的说法,当使用 new 关键字时,在幕后会创建一个空白对象,该对象继承自 Parent 的(函数)原型:Object.create(Person.prototype)。然后“this”的所有引用都附加到该对象并返回。
var Parent = function(name, age){
var name = name || "";
var age = age || "";
this.name = function(){
return name;
}
this.age = function(){
return age;
}
}
Parent.prototype.info = function(){
return "name: " + this.name() + " age: " + this.age();
}
var p = new Parent("John",25);
console.log("name: " + p.name() + " age: " + p.age() + " info: " + p.info());
// 不幸的是,我无法模拟这个。我收到错误:“TypeError:this.prototype 不是对象或空值”。显然,在使用时,“this”还不是父级。
var parent = function(name, age){
var name = name || "";
var age = age || "";
var that = Object.create(this.prototype);
that.name = function(){
return name;
}
that.age = function(){
return age;
}
return that;
}
parent.prototype.info = function(){
return "name: " + this.name() + " age: " + this.age();
}
var p = parent("John",25);
console.log("name: " + p.name() + " age: " + p.age() + " info: " + p.info())
所以当 Crockford 说避免使用“new”时,我们应该如何向原型添加属性?
【问题讨论】:
-
你可以使用 Object.create() 或者更新的 setPrototypeOf(),或者只是 extend()。
-
你误用了
this。 -
@dandavis Object.create() 是在 ES5 中引入的。当他鼓励避免“新”时,他的书就在那之前出现了。所以我想要一个不涉及 ES5 的解决方案,如果这样的解决方案存在的话。
-
@JohnMerlino:我认为道格在当时称它为 begat(),但它基本上是同一回事。大多数 Object.create polyfill 看起来像 Dougs 的旧对象制造商。javascript.crockford.com/prototypal.html
-
Pre-ES5 我认为你不能完全避免
new,除了使用__proto__。Object.create是要走的路。
标签: javascript