首先看一下什么是构造函数、原型、实例
// 构造函数
function P (name) {
this.name = name
this.gohome = function () {
console.log(this.name + ' gooing')
}
this.__proto__.sayName = function () {
console.log('my name is ' + this.name)
}
}
// 原型
P.prototype.sayHi = function () {
console.log('Hi ' + this.name)
}
P.prototype.getlen = function () {
return String(this.name).length
}
// 实例
var p1 = new P('tree')
var p2 = new P('bob')
p1.sayName() // my name is tree
p1.sayHi() // Hi tree
// p1的__proto__和P的prototype相等
console.log(p1.__proto__ === P.prototype) // true
// 如果没有返回值则,默认返回undefined,两个原型函数相等
console.log(p1.sayHi === p2.sayHi) // true
console.log(p1.sayHi() === p2.sayHi()) // true
console.log(p1.getlen === p2.getlen) // true
console.log(p1.getlen() === p2.getlen()) // false
// 如果不是原型上的函数,且没有返回值,则实例出来的两个函数不相等
console.log(p1.gohome === p2.gohome) // false
console.log(p1.gohome() === p2.gohome()) //true
判断对象上是否有某一属性
//
function p (name) {
this.name = name
this.__proto__.sayName = function () {
console.log('my name is ' + this.name)
}
}
var p1 = new P('tree')
// 判断某一属性是否来自实例
p1.hasOwnProperty('name') // true
p1.hasOwnProperty('sayName') //false
// 判断对象上是否有某一属性,不管是否来自实例还是原型
console.log('name' in p1) //true
console.log('sayName' in p1) //true
// 判断某一属性是否只来自原型
function jugObj (obj, name) {
return (name in obj) && !obj.hasOwnProperty(name)
}
什么是原型链
// 构造函数
function P () {
}
// 原型
console.log(P.prototype)
// 实例
var p1 = new P()
ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象。原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
那么,如果我们让原型对象等于另一个类型的实例,结果会怎样呢?
显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。
这就是所谓原型链的基本概念。
实现原型链有一种基本模式,其代码大致如下:
function SuperType () {
this.superFlag = true
}
SuperType.prototype.getSuperValue = function () {
return this.superFlag
}
function SubType () {
this.subflag = true
}
// 原型等于另一个的实例
SubType.prototype = new SuperType()
SubType.property.getSubValue = function () {
return this.subFlag
}
var instance = new SubType()
console.log(instance.getSuperValue()) //true
// 确定原型和实例的关系
// 1.instanceof
console.log(instance instanceof Object); // true
console.log(instance instanceof SuperType); // true
console.log(instance instanceof SubType); // true
// 2.isPrototypeOf()
cosnole.log(Object.prototype.isPrototypeOf(instance)) // true
console.log(SuperType.prototype.isPrototypeOf(instance)) // true
cosnole.log(SubType.prototype.isPrototypeOf(instance)) // true
注意:
1. 所有的引用类型都继承了Object,而这个继承也是通过原型链实现的。
这也是自定义类型会继承toString(),valueOf()等默认方法的原因;
2. 子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎样,
给原型添加方法的代码一定要放在替换原型的语句之后,
即 SubType.prototype = new SuperType(); // 之后再添加方法;
3. 在通过原型链实现继承时,不能使用对象字面量创建原型方法,如 SubType.prototype = {...};