浅谈JavaScript原型链
先来看一下,构造函数----实例----原型三者之间的关系
JavaScript怎么实现继承?
1.经典继承
var o = {
name:"张三",
age:"18"
};
var obj = Object.create(o);
console.log(obj.name,obj.age);
结果
2.混入式继承
var obj1 = {
name:"张三",
age:"18"
};
var obj2 = {};
for(var k in obj1){
obj2[k] = obj1[k];
}
console.log(obj1);
console.log(obj2);
结果
3.使用原型继承
function obj() {
}
obj.prototype.name = "张三";
obj.prototype.age = "18";
var obj1 = new obj();
var obj2 = new obj();
console.log("obj1:",obj1);
console.log("obj2:",obj2);
结果
如何扩展或者修改一个内置对象?
Array.prototype.fn = function () {
console.log("我是一个数组");
};
Array.prototype.push = function () {
console.log("push没有咯");
};
这种方式怕是不太合理哦,万一别人也想加一个fn方法啊,你把push改了别人要用怎么办?
我们选择利用原型的特性
function MyArray() {
}
//创建一个Array实例
var arr = new Array();
//改变原型指向
MyArray.prototype = arr;
MyArray.prototype.fn = function () {
console.log("我是一个数组");
};
MyArray.prototype.reverse = function () {
console.log("reverse方法改变咯");
};
var a = new MyArray();
a.push(1,2,3,4);
a.fn();
a.reverse();
var b = new Array(1,2,3,4);
try{
b.fn();
}catch (e){
console.log("b没有这个方法");
}
b.reverse();
console.log("a:",a);
console.log("b",b);
结果
我们发现MyArray的实例能用自己定义的fn函数,能改变原来Array的方法,还能用Array的方法如同一个数组
而Array并没有受到上面改变的影响
来看看MyArray改变原型后,.prototype的值和它的constructor值
console.log(MyArray.prototype);
console.log(MyArray.prototype.constructor);
结果
我们发现.prototype中有自己添加的fn方法和重写的reverse方法,而我们没有自己添加constructor属性,系统直接通过__proto__找到了Array的原型中的constructor的构造函数,也就是MyArray直接用的Array的构造函数
为什么Array没有被上面的方法重写?
因为是直接在MyArray的prototype中添加的,根本没有Array.prototype的事
为什么MyArray能用Array原型中的方法?
如果MyArray中没有这个方法就会通过__proto__找到原型中arr属性(Array的实例对象)再通过__proto__在它的原型中寻找方法,然后一直向下,形成了原型链
看图说明
什么是原型链?
1.每个构造函数都有原型对象
2.每个对象都会有构造函数
3.每个构造函数的原型都是一个对象,那么这个原型对象也会有构造函数,那么这个原型对象的构造函数也会有原型对象
4.这样就会形成一个链式的结构,称为原型链
画一个简单的原型链来解释
这是一个最基本的原型链,可以理解为:
a--->A.prototype--->Object.prototype--->null
a中没有的属性会去A的原型中找,如果还是没有就是它的上级Object的原型中找,还是没有就报错
规则:
1.访问对象的成员时,会先去自身查找,找到就使用
2.没有找到,去当前对象的原型中查找,找到就使用
3.没有找到,继续像这个对象的原型的构造函数的原型中查找(向上继续找),找到就使用
4.如果最后到Object的原型都没有找到,就直接报错
一个实例对象一共会继承多少成员:
构造函数是怎么来的?
function A1(name) {
this.name = name;
}
var A2 = new Function("name","this.name = name;");
var a1 = new A1("张三");
var a2 = new A2("张三");
console.log("a1:",a1.name);
console.log(A1);
console.log("a2:",a2.name);
console.log(A2);
结果
我们发现可以通过new Function创建出来一个函数,所以A1构造函数也是一个实例对象由Function函数创建
1.那么Function的构造函数是谁 ?
console.log(Function.constructor);
结果
自己把自己给创建出来了
2.来看看Function的原型是谁?
console.log(Function.prototype);
结果
3.再来看看Function的原型的原型是谁
console.log(Function.prototype.__proto__);
console.log(Function.prototype.__proto__.constructor);
结果
Function的原型的原型的构造函数是Object,所以Function的原型的原型是Object的原型,再往上Object的原型就是null了
4.那这个Object的构造函数又是谁?
console.log(Object.constructor);
结果
居然还是Function
由上可知
1.构造函数由Function创建
2.Function的构造函数就是自己本身
3.Function的原型是一个空的函数
4.Function的原型的原型是Object的原型
5.Object是Function创建
更新原型链图
有点乱,整理一下
再换一种画法
结论:
1. Object构造函数是通过Function构造函数创建的
2.Function构造函数是自己把自己创建的
来看一个槽点
console.log(Function.constructor);
console.log(Object.constructor);
结果
这个结果就是我们上面那个结论,介绍一个运算符instanceof
instanceof运算符希望左操作数是一个对象,右操作数标识对象的类。如果左侧对象是右侧类的实例,则表达式返回为true,否则返回false
看下面的代码
console.log(Function instanceof Function);
console.log(Function instanceof Object);
结果
Function不是Function自己创建吗?
Function也是Object的实例?
Object不是Function创建的吗?
Object也创建了Function?
再来看看这个
console.log(Object instanceof Function);
console.log(Object instanceof Object);
结果
真是越来越奇怪了,互相创建??
换个例子看下
function A(name) {
this.name = name;
}
var a = new A("张三");
console.log(a instanceof A);
console.log(a instanceof Object);
console.log(a instanceof Function);
console.log(A instanceof Function);
console.log(A instanceof Object);
结果
怎么会出现这种情况?还是得提一下instanceof的判断机制,并不是就是光判断a是不是A的实例,而是可以理解为
a.__proto__.__proto__.... = A.prototype
instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型
举例说明一下
function A(name) {
this.name = name;
}
var a = new A("张三");
console.log(a instanceof A);
console.log(a.__proto__ === A.prototype);
console.log(a instanceof Object);
console.log(a.__proto__.__proto__ === Object.prototype);
console.log(a instanceof Function);
//这个玩意,并没有a再__proto__下去就是null了
console.log(A instanceof Function);
console.log(A.__proto__ === Function.prototype);
console.log(A instanceof Object);
console.log(A.__proto__.__proto__ === Object.prototype);
结果
没有懂就结合上面的原型链图再看一下
我们回到原点,看那四句的输出为什么会是true
先附上图解
两条原型链
Function-->Function.prototype-->Object.prototype-->null
Object-->Function.prototype-->Object.prototype-->null
解释那四句
console.log(Function instanceof Function);
//相当于
console.log(Function.__proto__ === Function.prototype);
console.log(Function instanceof Object);
//相当于
console.log(Function.__proto__.__proto__ === Object.prototype);
console.log(Object instanceof Function);
//相当于
console.log(Object.__proto__ === Function.prototype);
console.log(Object instanceof Object);
//相当于
console.log(Object.__proto__.__proto__ === Object.prototype);
结果
请结合上图自己看
就写到这吧,emmm......