Моя дилемма, касающаяся наследования прототипов JavaScript и метода hasOwnProperty - PullRequest
2 голосов
/ 29 сентября 2010

В основном все, кто пишет о перечислении членов в 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, поскольку age является единственным прямым членом mary ... два других члена, name и surname, являются прототипом цепь.

Но, очевидно, я хочу, чтобы все 3 члена были перебраны в конструкции for..in; но если вы удалите hasOwnProperty, вы можете получить членов из Object.Prototype, если кто-то добавит к нему функции.


Так что это моя дилемма.

Используете ли вы наследование прототипа в сочетании с методом hasOwnProperty, но рискуете получить членов, которые находятся слишком далеко по цепочке во время перечисления?

Или вы используете другие формы наследования, которые добавляют членов непосредственно к объекту, а не к прототипу?

Ответы [ 2 ]

3 голосов
/ 29 сентября 2010

Hm.Вы говорите «очень близко в цепочке прототипов», но на самом деле, что это значит очень близко?Является ли три уровня глубиной «близко» или «далеко».

В любом случае, вы можете изменить функцию побитового вызова и реализовать собственную функцию hasOwnProperty для каждого объекта, которая будет проходить через цепочку прототипов только до уровня объекта.Это решит вашу дилемму получения членов, которые добавляются в Object.prototype, не используя hasOwnProperty.Код прикреплен ниже:

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
0 голосов
/ 29 сентября 2010

Если вам нужно перебрать цепочку прототипов объекта, вы можете использовать hasOwnProperty, чтобы пропустить прямых членов (как вы сказали). Это, конечно, также будет выполнять итерацию любого другого члена, который был добавлен к прототипу этого объекта (Object.Prototype и т. Д.). Нет способа избежать этого.

Это все равно, что спрашивать, как избежать перечисления определенных элементов объекта car = {yellow, green, black} (псевдокод) ... вы не ... вы просто пропускаете определенные элементы в зависимости от их значения.


Добавление членов напрямую к объекту на самом деле не является формой наследования, если, конечно, вы не создаете объекты с использованием техники begetObject() ... потому что она использует Prototype для добавления членов.

...