【问题标题】:prototype chain in javascriptjavascript中的原型链
【发布时间】:2012-07-02 13:42:54
【问题描述】:

假设我有两个构造函数:

var Person = function(xx,xx,xxx,xxxxxxx) {
  //Person initialization
}

var Man = function(xx,xx,xxx,xxx) {
  //Man initialization
}

我希望 Man 从 Person 扩展。

以下是我的想法:

给定一个已创建的 Man 对象:

var m=new Man("xx",....);

1) 当m的属性被访问时,会在Man.prototype中搜索。

2) 如果找不到,应该在Man.prototype.__prop__找到。

所以我要做的就是将Man.prototype.__prop__ 链接到Person.prototype

我知道这是常见的方式:

function inherit(superClass) {
    function F() {}
    F.prototype = superClass.prototype;
    return new F;
}
Man.prototype=inherit(Person);

但是当我尝试这个时:

Man.prototype.prototype=Person.prototype.

为什么它不起作用?

【问题讨论】:

    标签: javascript prototype


    【解决方案1】:

    听起来就像您实际上想要将Man 的实例链接到Person 的实例,该实例保留了在其构造函数中添加的任何属性,在这种情况下,您可能真的想要这样的东西:

    function Person(a, b) {
        this.a = a;
        this.b = b;
    }
    
    function Man() {}
    Man.prototype = new Person("val1", "val2");
    
    var m = new Man();
    console.log(m.a);
    

    ...打印val1

    额外的杂谈

    inherit 的目的是从一个函数创建一个对象,该函数的prototype 是给定超类的函数(没有显式使用new),这正是它的作用。因此,以下打印出string

    function Person() {}
    Person.prototype.test = "string";
    
    function Man() {}
    
    function inherit(superClass) {
        function F() {}
        F.prototype = superClass.prototype;
        return new F;
    }
    
    var t = inherit(Person);
    console.log(t.test);
    

    但你通常希望将返回的对象分配给另一个函数的原型:

    Man.prototype = inherit(Person);
    
    var m = new Man();
    console.log(m.test);
    

    ...所以m.test 也打印string,这意味着使用Man 创建的对象链接到Personprototype)。

    请注意 Man.prototype.prototypeundefined 并且 -- 这是重要的部分 -- 也没有意义。函数有原型。其他对象(例如Man.prototype)则没有。 prototype 属性在任何其他情况下都不神奇。为随机对象的 prototype 属性赋值并没有什么特别的。这只是另一个属性。

    还要注意,我们从inherit 返回的东西通过其prototype 链接到Person,并且无法访问添加到Personinstances 的任何属性。

    【讨论】:

    • 我知道这是旧的,但你不认为答案的 真正相关 部分只是说明“......原型属性并不神奇”的段落在任何其他情况下......”?顺便说一句,当检查m 的结果结构时,它真的似乎 像嵌套的prototype 属性(它实际上是,但出于某种原因仅由JS 引擎在内部管理)。因此,按照 OP 中的说明,尝试直接设置嵌套的 prototype(而不是将祖先的 prototype 包装到一个对象中并覆盖整个后代的 prototype 对象)似乎是合乎逻辑的,或者不是吗?
    【解决方案2】:

    我是怎么做的(关于你的例子):

    var Person = function () {
    }
    
    // Define "Person" methods
    
    var Man = function () {
    }
    
    Man.prototype = new Person();
    
    // Define "Man" methods
    

    更新

    关于带参数的构造函数:刚刚发现了这个可以真正帮助您弄清楚的SO问题(第二个答案,第一部分):JavaScript inheritance: when constructor has arguments

    【讨论】:

    • @volpay:构造函数方法的参数不为空怎么办?
    【解决方案3】:

    有很多通用方法可以做到这一点。我将提供其中三个:

    1.) 使用 Function 对象作为构造函数和继承的新对象的原型对象。实现应该如下所示:

    var person = {
        toString : function() {
            return this.firstName + ' ' + this.lastName;
        }
    }
    
    
    function extend(constructor, obj) {
        var newObj = Object.create(constructor);
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                newObj[prop] = obj[prop];
            }
        }
        return newObj;
    }
    
    var man = extend(person, 
        {
            sex: "male", 
            age: "22"
        });
    
    var name = extend(man, 
        {
            firstName: "Simo",
            lastName: "Endre"
        });
    
    name.man;
    name.toString();
    

    2.) 在这种情况下,我们将使用 Function 对象作为构造函数,以模拟 C# 或 Java 等语言中的经典继承。对象的原型属性将用作构造函数,新创建的对象将继承对象原型根的所有属性。在这种情况下,对象的原型只有一种增强作用,有效的实现是在函数方法中完成的。

    var Person = function(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    Person.prototype.toString = function() {
        return this.firstName + ' ' + this.lastName;
    }
    
    function inherit(func) {
        // passing function arguments into an array except the first one which is the function object itself
        var args = Array.prototype.slice.call(arguments, 1);
    
        // invoke the constructor passing the new Object and the rest of the arguments
        var obj = Object.create(func.prototype);
        func.apply(obj, args);        
    
        //return the new object
        return obj;   
    }
    
    var man = inherit(Person, "Simo", "Endre");
    man.toString();
    

    3.) 众所周知的继承模型:

    function extend(o) {
      function F() {}
    
      // We'll set the newly created function prototype property to the object. 
      //This act as a constructor.
      F.prototype = o;
    
      // Using the `new` operator we'll get a new object whose prototype is o.
      return new F();
    };
    

    【讨论】:

      猜你喜欢
      • 2016-04-10
      • 1970-01-01
      • 1970-01-01
      • 2013-05-09
      • 2016-04-03
      • 2018-01-19
      • 2019-02-03
      • 1970-01-01
      相关资源
      最近更新 更多