javascript - 在不使用 "new"实例化函数对象的情况下访问原型(prototype)属性

标签 javascript

在 Crockford 的书“Good Parts”中,他提到要避免使用“new”,因为它是一种反模式,因为语言是原型(prototype)的而不是经典的。但是,根据他的建议,我无法使用原型(prototype)属性。我尝试了几种不同的方法:

//在下面的例子中,我们无法访问原型(prototype)属性,因为虽然 parent 是用一个可以访问原型(prototype)属性的函数对象初始化的,但是当 parent 被执行时,我们返回一个对象字面量,它不会有权使用该属性(property)。我们在下面得到的错误是“TypeError: p.info is not a function”。发生这种情况是因为 p 的信息未定义,因为 p 是对象文字。具有原型(prototype)属性的是父级。

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”指的是全局对象,在浏览器中是window。

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”关键字构造对象允许我们访问原型(prototype)。那一定意味着 Parent 的返回值是一个函数而不是一个普通对象。根据 Stoyan Stefanov 在他的《Javascript 模式》一书中的说法,当使用 new 关键字时,会在幕后创建一个空白对象,它继承自 Parent 的(函数)原型(prototype):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”。显然,在使用时,“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”时,我们应该如何向原型(prototype)添加属性?

最佳答案

使用 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 中并为您提供更多选项、灵 active 和功能,您不必自己实现。 Object.create 实现了 Douglas Crockford 描述的模式。如果平台不支持它,那么您可以按照 Crockford 的建议进行自定义实现 here .

您可以使用与我上面描述的 Object.create 类似的 Object.beget。你可以试试:

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());

关于javascript - 在不使用 "new"实例化函数对象的情况下访问原型(prototype)属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25476373/

相关文章:

Javascript/HTML5 - 网络桌面/移动应用程序的音频流录制

javascript - 数据绑定(bind)中的 KnockoutJS 值切换

javascript - django include_javascript/use_javascript 和类似的

javascript - 通过 jquery 获取和设置图像 URL

javascript - JS 数组未正确访问

javascript - 循环遍历 JSON 数组

javascript - 如何进行 JavaScript 碰撞?

javascript - 所有 Bootstrap 下拉菜单都显示相同的项目

javascript - 未捕获的类型错误 : Cannot read property 'top' of undefined error

javascript - jquery 封装电子邮件地址