JavaScript深入理解之原型与原型链( 二 )


function Person() {};Person.prototype.name = "laker" ;var student = new Person();console.log(student.name); // lakerconsole.log(student.hasOwnProperty("name")); // falsestudent.name = "xiaoming";console.log(student.name); //xiaoming 屏蔽了原型对象中的 name 属性console.log(student.hasOwnProperty("name")); // true
上面主要是针对属性确认存在的情况下 , 如果这个属性不一定存在的话 , 这样判断就不够准确 , 因此我们需要首先判断这个属性是否存在 , 然后再进行上面的判断操作 。
判断一个属性是否存在 , 我们可以使用 in 操作符 , 它会在对象能够访问给定属性时返回 true , 无论该属性存在于实例还是原型中 。
因此我们可以封装这样一个函数 , 来判断一个属性是否存在于原型中 。
???????function hasPrototypeProperty(object, name){ return !object.hasOwnProperty(name) && (name in object);}
for-in 循环
在使用 for-in 循环时 , 返回的是所有能够通过对象访问的、可枚举的属性 , 其中包括了存在于实例中的属性 , 也包括了存在于原型中的属性 。
需要注意的一点是 , 屏蔽了实例中不可枚举属性的实例属性也会在 for-in 循环中返回 。
所有属性获取
如果想要获得对象上所有可枚举的实例属性 , 可以使用 .keys() 方法 , 这个方法接收一个对象作为参数 , 返回一个包含所有可枚举属性的字符串数组 。
如果想要获取所有的实例属性 , 无论它是否可以枚举 , 我们可以使用 .() 方法 。
原型链 原型链理解
【JavaScript深入理解之原型与原型链】 中描述了原型链的概念 , 并将原型链作为实现继承的主要方法 。其基本思想是利用的一个引用类型继承另一个引用类型的属性和方法 。
原型链的主要实现方法是让构造函数的对象等于另一个类型的实例 , 此时的对象因为是实例 , 因此将包含一个指向另一个原型的指针 , 相应地另一个原型中也包含着一个指向另一个构造函数的指针 。假如另一个原型又是另一个类型的实例 , 那么上述关系依然成立 , 如此层层递进 , 就构成了实例与类型的链条 。这就是原型链的基本概念 。
下面我们来看一个例子 。
function Super(){};function Middle(){};function Sub(){};Middle.prototype = new Super();Sub.prototype = new Middle();var suber = new Sub();
下面我们来看看这几个对象间的关系
默认的原型
其实我们上面这个原型链是不完整的 , 还记得我们以前说过所有的引用类型都继承了吗?这个继承就是通过原型链来实现的 。我们一定要记住 , 所有函数的默认原型都是的实例 , 因此默认原型都会包含一个内部指针 , 指向 .。这也正是所有的自定义类型都会继承 () 、() 等默认方法的根本原因 。
那么我更新一下我们上面的原型链 。
. 就是原型链的终点了 , 我们可以试着打印一下 .. , 我们会发现返回的是一个 null 空对象 , 这就意味着原型链的结束 。
函数也是对象
其实上面的原型链还少了一部分 , 为什么呢 。因为我们知道在中 , 函数也是对象 , 那么函数也应该有它的原型对象 。下面我们通过一个实例来了解它们之间的关系 。