基本上每个人都在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
,是原型链。
但显然,我希望在for..in
构造中迭代所有3个成员;但如果您删除hasOwnProperty
,则可以从Object.Prototype
获取成员,如果有人添加了功能。
所以这就是我的困境。
您是否将原型继承与hasOwnProperty
方法结合使用,但在枚举期间冒险让成员在链条上走得太远?
或者您是否使用其他形式的继承将直接添加到对象而不是原型?
答案 0 :(得分:3)
嗯。你说“在原型链中非常接近”,但实际上,这意味着什么非常接近?是三级深度“接近”还是“远”。
无论如何,你可以改变一个beget函数并为每个对象实现自己的hasOwnProperty函数,它只会通过原型链直到Object级别。这将解决您通过不使用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
答案 1 :(得分:0)
如果您需要遍历对象的原型链,可以使用hasOwnProperty
跳过直接成员(正如您所说)。这当然也会迭代添加到该对象原型中的任何其他成员(Object.Prototype
等)。没有办法避免这种情况。
这就像询问如何避免枚举car = {yellow, green, black}
对象的某些成员(伪代码)......你没有......你只是根据它们的价值跳过某些成员。
直接向对象添加 成员实际上并不是一种继承形式,除非您使用begetObject()
技术创建对象...因为它使用Prototype添加成员