js继承3:__proto__,prototype和new

原型链里最重要的属性就是prototype, prototype里存储了从上游拷贝而来的属性
Chrome里用proto表示prototype的指向,
比如说: X = new Y();
X对象的proto指向X对象的原型链上游Y, 再由Y的proto指向Y对象的原型链上游, 从而构成一条原型链条.

一:先看示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//1 父对象
function Y() {
};
Y.prototype = {
_name: 'ruantao.duapp.com'
};
//2 子对象
var X = new Y();
//3 子对象属性
console.log(X.prototype);//undefined
console.log(X.__proto__);//Object {_name: "ruantao.duapp.com"}
console.log(X._name);//ruantao.duapp.com
//4 父对象属性
console.log(Y.prototype);//Object {_name: "ruantao.duapp.com"}
console.log(Y.__proto__);//function Empty() {}
//5 修改子对象属性
X._name = "kangkang";
console.log(X._name);//子对象之前复制而来的属性被修改
console.log(Y.prototype._name);//父对象原型中的属性不被修改

二:New如何工作

下边代码模拟new的工作
第一步: 创建类的实例. 这步是把一个空的对象的 proto 属性设置为 F.prototype
第二步: 初始化实例. 函数 F 被传入参数并调用, 关键字 this 被设定为该实例
第三步: 立即执行, 返回实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function _new (f) {
var n = { '__proto__': f.prototype }; //第一步 创建类的实例。这步是把一个空的对象的 __proto__ 属性设置为 F.prototype
return (function () {
f.apply(n, arguments); //第二步 初始化实例。函数 F 被传入参数并调用,关键字 this 被设定为该实例
return n; //第三步 立即执行,返回实例
})();
};
//1 父对象
function Y() {
};
Y.prototype = {
_name: 'ruantao.duapp.com'
};
//2 子对象, 使用模拟的_new
var X = _new(Y);//用_new
//3 子对象属性
console.log(X.prototype);//undefined
console.log(X.__proto__);//Object {_name: "ruantao.duapp.com"}
console.log(X._name);//ruantao.duapp.com
//4 父对象属性
console.log(Y.prototype);//Object {_name: "ruantao.duapp.com"}
console.log(Y.__proto__);//function Empty() {}
//5 修改子对象属性
X._name = "kangkang";
console.log(X._name);//子对象之前复制而来的属性被修改
console.log(Y.prototype._name);//父对象原型中的属性不被修改

三:以下代码模拟了js引擎如何查找属性:

js里查找属性的规则也比较简单: 就是先在本对象中查找, 查不到沿原型链上溯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//属性查找函数
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop)) {
console.log("在对象==>"+obj+"内找到属性==>"+prop);
return obj[prop]
} else if (obj.__proto__ !== null) {
console.log("在父对象==>"+obj+"内找到属性==>"+prop);
return getProperty(obj.__proto__, prop)
} else {
return undefined
}
}
//1 父对象
function Y() {
};
Y.prototype = {
_name: 'ruantao.duapp.com'
};
//2 子对象, 使用模拟的_new
var X = new Y();//用_new
//3 子对象属性
getProperty(X,"_name")

从上图能看出prototype和constructor是怎么循环引用的, 下面来说最开始碰到的问题

四:instanceof操作符

instanceof操作符检查后边的操作符, 是否在前边操作符的原型链上

1
2
X instanceof Y//true
X instanceof Object//true