通过对对象的创建,继承的理解,我们可以发现,在平时使用时,prototype和实例中的属性都可以直接通过this.para来调用。而且优先使用实例中的属性,然后在根据原型链一步步的向上寻找属性的位置,直到找到为止。在平时,这些机制对于我们使用对象有很大帮助,但是有时候会产生实例属性覆盖原型属性,使我们调用不到正确的值。这时候我们就首先要判断我们现在能得到的属性来自于哪个位置。
首先是in操作符,in操作符可以判断某个属性在对象中能否被访问,不管是在实例中还是原型中。看以下这个例子:
1 function Myobj(){ 2 this.name=‘Tom‘; 3 this.age=‘20‘; 4 } 5 Myobj.prototype.getName = function(){ 6 console.log(this.name); 7 } 8 var obj = new Myobj(); 9 console.log(‘name‘ in obj); 10 console.log(‘getName‘ in obj);
最后两个console.log返回的都是true,这样就有了可以确定某个属性是否在这个对象中了。
接下来就是hasOwnProperty了,它可以判断某个属性是来自实例中还是原型中。对于在实例中的属性会返回true,而在原型中的属性会返回false,看下面这个例子:
1 function Myobj(){ 2 } 3 Myobj.prototype.name = ‘Peter‘; 4 Myobj.prototype.getName = function(){ 5 console.log(this.name); 6 } 7 var obj = new Myobj(); 8 console.log(obj.hasOwnProperty(‘name‘)); //false 9 obj.name = ‘Tom‘; 10 console.log(obj.hasOwnProperty(‘name‘)); //true 11 delete obj.name; 12 console.log(obj.hasOwnProperty(‘name‘)); //false
通过hasOwnProperty方法的使用,我们可以清楚的知道我们访问的到底是实例属性,还是来自原型或原型链中的属性。在调用obj.hasOwnProperty(‘name‘)时,只有重写name属性,才能使name成为一个实例属性,那么才会返回true。delete删除了这个name实例属性后,hasOwnProperty又会返回false了。
根据以上的这些函数的特性,我们可以编写一个函数来检测属性是否来自于原型:
1 function isParaFromProto(obj,para){ 2 if(para in obj){ 3 return (!obj.hasOwnProperty(para))?true:false; 4 }else{ 5 throw new Error(‘para not in obj‘); 6 } 7 }
函数的使用如下:
1 function Myobj(){ 2 } 3 Myobj.prototype.name = ‘Peter‘; 4 Myobj.prototype.getName = function(){ 5 console.log(this.name); 6 } 7 var obj = new Myobj(); 8 console.log(isParaFromProto(obj,‘name‘)); //true 9 obj.name = ‘Tom‘; 10 console.log(isParaFromProto(obj,‘name‘)); //false 11 delete obj.name; 12 console.log(isParaFromProto(obj,‘name‘)); //true
关于in操作符
in操作符主要有两个用处,一个是以上介绍过的,另一个是用在for语句中。但是两处地方在一些设置更改以后还是有不同的地方。Object中定义有defineProperty方法,它可以设置对象中属性的特性(不能设置原型中的属性),通过将Enumerable属性设置为false,那么for in循环就无法遍历到这个属性了,就想object中原生的__proto__属性。但是这时用in操作符判断属性是否在对象中时,还是可以返回true的。
1 function Myobj(){ 2 this.name = ‘Tom‘; 3 } 4 var obj = new Myobj(),arr = []; 5 for(var i in obj){ 6 arr.push(i); 7 } 8 console.log(arr); //[‘name‘] 9 console.log(‘name‘ in obj); //true 10 arr=[]; 11 Object.defineProperty(obj,‘name‘,{enumerable:false}); 12 for(var i in obj){ 13 arr.push(i); 14 } 15 console.log(arr); //[] 16 console.log(‘name‘ in obj); //true