【问题标题】:My dilemma involving JavaScript's Prototypal Inheritance and the hasOwnProperty method我的困境涉及 JavaScript 的原型继承和 hasOwnProperty 方法
【发布时间】:2010-09-29 08:41:14
【问题描述】:

基本上每个在 JavaScript 中写成员枚举的人都强烈主张使用 hasOwnProperty 方法以避免上升原型链。

我知道这是一种防御性编程形式,以防止迭代添加到例如Object.prototype 中的成员。但是其他继承的成员呢?比如说,原型链中非常接近的成员......您实际上希望被枚举的成员。

假设我有以下内容:

var beget = function (o) { // http://javascript.crockford.com/prototypal.html
    function F() {};
    F.prototype = o;
    return new F();
};

var john = { name: 'john', surname: 'grech' },
    mary = beget(john),
    p;

mary.age = 42; //augmenting 'mary'

// 'surname' in mary              => true
// mary.hasOwnProperty('surname') => false

for (p in mary) {
    //skipping over non-direct members, meaning that we also skip members
    //inherited from 'john'
    if (!mary.hasOwnProperty(p)) { 
        continue;
    }
    console.log(p);
}

在上面的示例中,只会显示age,因为agemary 的唯一直接成员...另外两个成员namesurname 是原型链。

但显然,我希望在 for..in 构造中迭代所有 3 个成员;但是如果你删除了hasOwnProperty,那么如果有人向它添加了功能,你就可以从Object.Prototype 获取成员。


所以这是我的困境。

您是否将原型继承与hasOwnProperty 方法结合使用,但冒着在枚举过程中让成员过于靠前的风险?

或者您是否使用将成员直接添加到对象而不是原型的其他继承形式?

【问题讨论】:

    标签: javascript inheritance prototype hasownproperty


    【解决方案1】:

    嗯。您说的是“原型链中非常接近”,但实际上,非常接近是什么意思?三级深是“近”还是“远”。

    无论如何,您可以更改一点beget 函数并为每个对象实现自己的hasOwnProperty 函数,这将通过原型链直到对象级别。这将解决您通过不使用 hasOwnProperty 来获取添加到 Object.prototype 的成员的困境。下面附上代码:

    var beget = function (o) { // http://javascript.crockford.com/prototypal.html
        function F() {
            this.hasOwnProperty = function(key) {
                return (key != "hasOwnProperty" 
                    && Object.prototype.hasOwnProperty.call( this, key ) 
                    || o.hasOwnProperty( key )
                );
            }
        };
    
        F.prototype = o;
        return new F();
    };
    
    var john = { name: 'john', surname: 'grech' },
        mary = beget( john ),
        p    = beget( mary );
    
    mary.age  = 42; //augmenting 'mary'
    mary.name = "mary";
    p.size    = "38";
    
    // testing prototype of Object.
    Object.prototype.not_own = function(){}
    
    for(var i in p) {
        console.debug('Key',i, p.hasOwnProperty(i));
    }
    
    // p.hasOwnProperty("size");    // -> true
    // p.hasOwnProperty("age");     // -> true
    // p.hasOwnProperty("name");    // -> true
    // p.hasOwnProperty("not_own"); // -> false
    

    【讨论】:

      【解决方案2】:

      如果您需要遍历对象的原型链,您可以使用hasOwnProperty 跳过直接成员(如您所说)。当然,这也会遍历添加到该对象原型中的任何其他成员(Object.Prototype 等)。没有办法避免这种情况。

      这就像询问如何避免枚举 car = {yellow, green, black} 对象(伪代码)的某些成员......你不会......你只是根据它们的值跳过某些成员。


      直接向对象添加成员并不是真正的继承形式,当然除非您使用begetObject() 技术创建对象...因为它使用原型来添加成员。

      【讨论】:

      • 我并没有说通过添加直接成员来扩充对象是继承。但是使用beget 函数,您正在使用原型继承,因为您“继承”的类的成员被添加到原型中。
      • 话虽如此,你的回答并没有让我更接近理解应该做什么。
      • @Andreas:目前还不清楚您要做什么。如果您尝试迭代对象,我回答了您的问题。如果您尝试使用直接成员和 begetObject() 进行继承,您的问题是什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-07
      • 2013-05-09
      • 1970-01-01
      • 1970-01-01
      • 2015-03-19
      • 1970-01-01
      • 2013-07-17
      相关资源
      最近更新 更多