原型
代码示例:
// 构造函数
this.name = name
}
Foo.prototype.alertName = function () {
alert(this.name)
}
// 创建示例
var f = new Foo(‘zhangsan’)
f.printName = function () {
console.log(this.name)
}
// 测试
f.printName()
f.alertName()
执行“printName”时很容易理解,但执行“alertName”时会发生什么?这里还有一个需要记住的要点**当试图获取对象的属性时,如果对象本身没有这个属性,它将被删除`__proto__`(即其构造函数的’prototype’),因此’f.alertName’将找到’Foo。原型alertName”。
如何确定该属性是否是对象本身的属性?当使用“hasOwnProperty”时,它通常用于遍历对象。
var item
for (item in f) {
// 高级浏览器已经在 for in 中屏蔽了来自原型的属性,但是这里建议大家还是加上这个判断,保证程序的健壮性
if (f.hasOwnProperty(item)) {
console.log(item)
}
}
原型链
接着上面的示例,如果执行`f.toString()`时,又发生了什么?
// 省略 N 行
// 测试
f.printName()
f.alertName()
f.toString()
因为`f`本身没有`toString()`,并且`f.__proto__`(即`Foo.prototype`)中也没有`toString`。这个问题还是得拿出刚才那句话——**当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的`__proto__`(即它的构造函数的`prototype`)中寻找**。
如果在`f.__proto__`中没有找到`toString`,那么就继续去`f.__proto__.__proto__`中寻找,因为`f.__proto__`就是一个普通的对象而已嘛!
* `f.__proto__`即`Foo.prototype`,没有找到`toString`,继续往上找
* `f.__proto__.__proto__`即`Foo.prototype.__proto__`。`Foo.prototype`就是一个普通的对象,因此`Foo.prototype.__proto__`就是`Object.prototype`,在这里可以找到`toString`
* 因此`f.toString`最终对应到了`Object.prototype.toString`
这样一直往上找,你会发现是一个链式的结构,所以叫做“原型链”。如果一直找到最上层都没有找到,那么就宣告失败,返回`undefined`。最上层是什么 —— `
Object.prototype.__proto__ === null`