大多数编程语言是基于类的语言,而 JS 是一种基于原型继承的语言。
1、为什么会有原型和原型链?
首先,先来看一下为什么会有原型和原型链,原型和原型链能带来什么好处。在面向对象编程中,创建对象的方式有很多种,最简单的就是工厂模式和构造函数模式,然而,这些方式创建的对象,不能共享属性和方法,每一个对象会重复创建相同的属性和方法,造成内存资源的浪费。最简单的,每个变量都会有一个 toString 方法,那么是每个变量都有一个自己的方法吗,显然不是的。原型的作用就是帮助我们存放公用的属性和方法。
2、理解原型对象
我们创建的每一个函数都有一个 prototype 属性,该属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,这个对象就是该函数的原型对象。原型对象自动获得一个 constructor 属性,这个属性又指向了函数本身。
3、理解原型链
简单来讲,构造函数、原型、实例有如下关系:每一个构造函数都有一个原型对象 prototype,原型对象都包含一个指向构造函数的指针 constructor,而实例都包含一个指向原型对象的内部指针__proto__。
基于以上关系,我们让一个构造函数的原型等于另一个类型的实例,此时,该原型对象就包含了一个指向另一个原型的指针,相应的,另一个原型中也包含着一个指向另一个构造函数的指针。加入另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是原型链的基本概念。
一个例子:
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.alertName = function() {
alert(this.name)
}
var p = new Person('张三', 20)
p.alertAge = function() {
alert(this.age)
}
p.alertAge() // 自身属性
p.alertName() // p._proto_(Person.prototype)中找
p.toString() // p._proto_._proto_(Object.prototype)中找
//循环对象自身的属性
for (var item in p) {
//高级浏览器已经屏蔽了来自原型的属性,但是这个为了保证兼容性和健壮性建议还是添加这个筛选
if (p.hasOwnProperty(item)) {
console.log(item)
}
}
复制代码
4、总结
- prototype 是函数的原型对象,它是一个对象,这个对象又包含了一个 constructor 属性指向了该函数(prototype 是函数的属性,而且我们一般讨论的是构造函数);
- 对象的__proto__指向它构造函数的 prototype(__proto__是实例的属性);
- 所有的构造函数的原型链最后都会指向 Object 构造函数的原型,即可以理解 Object 构造函数的原型是所有原型链的最底层,即
Object.prototype.__proto__ === null
; - 要寻找一个函数的 prototype,就先看它是从谁继承来的;
- 要寻找一个对象的__proto__,就先看它是谁的实例,找它的构造函数;
5、习题
记住上一小节中的几句话,我们再来看下面的题目,就比较简单了。以下等式恒成立:
第一组: (几个原生对象的原型关系)
Object.__proto__ === Function.prototype // 将Object视为Function的实例
Object.prototype.__proto__ === null // 将Object视为构造函数
Function.__proto__ === Function.prototype // 将Function视为Function的实例
Function.prototype.__proto__ === Object.prototype //将Function视为构造函数,它的原型是Object的一个实例
Array.__proto__ === Function.prototype // 将Array视为Function的实例
Array.prototype.__proto__ === Object.prototype //将Array视为构造函数,它的原型是Object的一个实例
//类推 Boolean、 String、 Number......
复制代码
第二组:
var obj = {}
obj.__proto__ === Object.prototype // obj是Object的实例
obj.prototype === undefined // obj不是函数,所以没有原型对象属性
var arr = []
arr.__proto__ === Array.prototype // arr是Array的实例
var fn = function() {}
fn.__proto__ === Function.prototype // 将fn视为Function的实例
fn.prototype.__proto__ === Object.prototype // 将fn视为函数,它的原型是Object的一个实例
function Test() {}
var test = new Test()
Test.prototype.__proto__ === Object.prototype // 将Test视为构造函数,它的原型是Object的一个实例
test.__proto__ === Test.prototype // test是Test的实例
复制代码
参考
- Javascript 高级程序设计(第 3 版)
- 三句话给你解释清楚原型和原型链
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END