在Crockford的书“Good Parts”中,他提到要避免使用“new”,因为它是一种反模式,因为这种语言是原型的而不是经典的。但是,使用他的建议,我无法使用原型属性。我尝试了几种不同的东西:
//在下面的例子中,我们无法访问prototype属性,因为虽然使用一个可以访问prototype属性的函数对象初始化parent,但是当执行parent时,我们返回一个对象文字,而不是可以访问该属性。我们得到的错误是“TypeError:p.info不是函数”。发生这种情况是因为p未定义信息,因为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 Patterns”中的说法,当使用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不是对象或null”。显然,在使用时,“这个”还不是父母。
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”时,我们应该如何为原型添加属性?
答案 0 :(得分:1)
使用Object.create()
功能,您可以这样做:
// base, its prototype will be used to create a new parent
function Parent(name, age) {
this.name = name || '';
this.age = age || '';
};
// factory to create a new parent
function createParent(name, age) {
var proto = Parent.prototype;
var properties = {
name: {writable: true, configurable: true, value: name || ''},
age: {writable: true, configurable: true, value: age || ''}
};
var parent = Object.create(proto, properties);
return parent;
}
// augment the Parent's prototype
Parent.prototype.info = function(){
return "name: " + this.name + " age: " + this.age;
}
// Create a new Parent
var p = createParent("John",25);
// Test
console.log("name: " + p.name + " age: " + p.age + " info: " + p.info());
您可以查看here,了解有关如何使用Object.create()
功能的更多选项/变体。
根据您的需要,您可以使用不同的方法实现类似的功能。一个简单的例子:
var parentBase = {};
var parent = function(name, age){
var name = name || "";
var age = age || "";
var that = parentBase;
that.name = function(){
return name;
}
that.age = function(){
return age;
}
return that;
}
parentBase.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());
您最好使用Object.create
,因为它位于ECMAS 5中,为您提供更多选项,灵活性和功能,您无需自己实施。 Object.create实现了Douglas Crockford描述的模式。如果平台不支持它,那么你可以像Crockford建议here那样进行自定义实现。
您可以使用Object.beget
与上述Object.create
类似的内容。你可以尝试一下:
if (typeof Object.beget !== 'function') {
Object.beget = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
// base, its prototype will be used to create a new parent
function Parent(name, age) {
this.name = name || '';
this.age = age || '';
};
// factory to create a new parent
function createParent(name, age) {
var proto = Parent.prototype;
var parent = Object.beget(proto);
parent.name = name || '';
parent.age = age || '';
return parent;
}
// augment the Parent's prototype
Parent.prototype.info = function(){
return "name: " + this.name + " age: " + this.age;
}
// Create a new Parent
var p = createParent("John",25);
// Test
console.log("name: " + p.name + " age: " + p.age + " info: " + p.info());
答案 1 :(得分:0)
尝试(此模式)
var parent = function(name, age){
var name = name || "";
var age = age || "";
// add `info` as `var`
var that = {}, info;
// change method to function expression
that.name = (function(){
return name;
}())
// change method to function expression
that.age = (function(){
return age;
}())
return that;
// add `|| {}` , for accessing `parent.info`
} || {};
// add param `that` to `parent.info` function
parent.info = function(that){
return "name: " + that.name + " age: " + that.age;
};
var p = parent("John",25);
console.log("name: " + p.name + " age: " + p.age + " info: " + parent.info(p));
// var results = document.createElement("div");
// results.innerHTML = parent.info(p);
// document.body.appendChild(results);