JavaScript中原型和原型链
原型[prototype]:
为其他对象提供共享属性的对象。
每个函数都有一个原型(prototype)属性,这个属性是一个指针,指向一个对象,这个对象包含特定实例共享的一些属性和方法。
以例服人:
这个例子说明了原型对象是共享的,并且是一个指针,并且对象的实例中也有指向prototype指向对象的指针。
function Animal(name) {
this.name = name || "动物";
}
Animal.prototype.runs = function() {
console.log(this.name + ',跑起来了\n')
}
var dog = new Animal('小狗')
dog.runs() //输出"小狗跑起来了"
// 下面增加的方法,dog对象可以使用吗?
Animal.prototype.hi = function() {console.log('hi')}
dog.hi() //输出"hi",说明原型属性是一个指针,指向一个共享对象,不管先添加的还是后添加的方法都能调用
//dog作为一个Animal实例,他的__proto__属性和Animal.prototype指向同一个对象,所以才可以使用原型的方法。
console.dir(dog) // 查看 dog.__proto__
// dog.__proto__ & Animal.prototype
console.log(dog.__proto__ === Animal.prototype) //true,有相同的指针地址
原生构造函数的原型对象[不单函数有原型对象]
console.dir(Object.prototype)
console.dir(Array.prototype)
console.dir(String.prototype)
console.dir(Date.prototype)
再看一个__proto__ & prototype的例子
var obj = { }
obj.toString() // "[object Object]"
//obj 对象为什么有 toString 方法?
//因为 obj 对象是 Object 构造函数的实例,obj 对象的原型指针指向 Object.prototype 对象。console.log(obj.__proto__ === Object.prototype )
通过原型关系图理解:
再看一个函数的原型的例子
var obj = {name: 'jack'}
function getName() {
console.log(this.name)
}
// 问题:Animal.call 方法来自哪?
getName.call(obj) //来自Function对象
console.dir(getName)
console.log(getName.__proto__ === Function.prototype) //true
console.log(Function.prototype.__proto__ === Object.prototype) //true
通过原型关系图理解
原型继承:
function Animal() {
this.name = '动物'
}
Animal.prototype.runs = function() {
console.log(this.name + ',跑起来了\n')
return this
}
function Bird() {
this.name = '鸟'
}
Bird.prototype = new Animal() //让Bird的原型等于Animal的实例,因为new Animal中有__proto__指向Animal.prototype的指向(沿着原型链寻找),此处也可以写为Bird.prototype = Animal.prototype
Bird.prototype.fly = function() {
console.log(this.name + ',飞走了\n')
return this
}
function Crow(name) {
this.name = name || '乌鸦'
}
Crow.prototype = new Bird()
Crow.prototype.drink = function() {
console.log(this.name + ',喝饱了水\n')
return this
}
var crow = new Crow('一只可爱的小乌鸦')
crow.drink().runs().fly()
console.dir(crow)
输出结果:
原型总结:
每一个构造函数都有一个和其对应的原型对象。
构造函数的 prototype 属性和其实例对象的 “__proto__” 属性指向同一个对象。
某构造函数的所有实例对象,共享一份原型对象。
所有的对象都可以通过 “__proto__” 属性,最终连接到 Object.prototype 对象。
构造函数用 prototype 来定义原型的属性和方法,实例对象用 “__proto__” 来查找原型的属性和方法。
当查找一个对象的属性或方法时,JS引擎会向上遍历其原型链,直到找到给定名称的属性为止。如果最终在 Object.prototype 对象仍然没有找到此属性或方法,则返回 undefined 值。