Javascript教程:原型对象中in操
function Person() {} Person.prototype.name = "Nicholas"; Person.prototype.age = "29"; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function () { alert(this.name); }; var person1 = new Person(); var person2 = new Person(); alert(person1.hasOwnProperty("name")); //false alert("name" in person1); //true person1.name = "Greg"; alert(person1.name); //"Greg" ——来自实例 alert(person1.hasOwnProperty("name")); //true; alert("name" in person1); //true alert(person2.name); //"Nicholas"——来自原型 alert(person2.hasOwnProperty("name")); //false alert("name" in person1); //true delete person1.name; alert(person1.name); //"Nicholas" ——来自原型 alert(person1.hasOwnProperty("name")); //false alert("name" in person1); //true;
在以上代码执行的整个过程中,name属性要么直接在对象上访问到,要么是通过原型访问到的。因此,调用“name” in Person1始终都返回true,无论该属性存在与实例中还是存在与原型中。同时使用hasOwnProperty()方法和in操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中,如下所示:
function hasPrototypeProperty(object, name) { return !object.hasOwnProperty(name) && (name in object); }由于in操作符只要通过对象能够访问到属性就就返回true,hasOwnProperty()只在属性存在于实例中时才返回true,因此只要in操作符返回true而hasOwnProperty()返回false,就可以确定属性是原型中的属性。下面来看一看上面定义的函数hasPrototypeProperty()用法:
function Person() { } Person.prototype.name = "Nicholas"; Person.prototype.age = "29"; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function () { alert(this.name); }; var person = new Person(); alert(hasPrototypeProperty(person, "name")); //true person.name = "Greg"; alert(hasPrototypeProperty(person, "name")); //false 在这里,name属性先是存在于原型中,因此hasPrototypeProperty()返回true。当在实例中重写name属性后,该属性就存在于实例中了,因此hasPrototypeProperty()返回false;
在使用for-in循环时,返回的是所有能够通过对象访问的、可枚举的(enumerated)属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。屏蔽了原型中不可枚举属性(即设置了[[DontEnum]]标记的属性)的实例属性也会在for-in循环中返回,因为规定,所有开发人员定义的属性都是可枚举的——只有IE除外;
IE的JScript实现中存在一个bug,即屏蔽了不可枚举属性的实例属性不会出现在for-in循环中。例如:
当以上代码运行时,应该会显示一个警告框,表明找到了toString()方法。这里的对象o定义了一个名为toString()的方法,该方法屏蔽了原型中(不可枚举)的toString()方法。在IE中,由于其实现认为原型的toString()方法被打上了[[DontEnum]]标记就应该跳过该属性,结果我们就不会看到警告框。该bug会影响默认不可枚举的所有属性和方法,包括:hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()和valueOf()。有的浏览器也为constructor和prototype属性打上了[[DontEnum]]标记,但这并不是所有浏览器共同的做法;
原型与in操作符有两种方式使用in操作符:单独使用和在for-in循环中使用。在单独使用时,in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例还是原型中。看一看下面的例子: