欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

浅谈JavaScript原型链

程序员文章站 2024-03-13 10:52:57
...

先来看一下,构造函数----实例----原型三者之间的关系

浅谈JavaScript原型链

JavaScript怎么实现继承?

1.经典继承

    var o = {
        name:"张三",
        age:"18"
    };
    var obj = Object.create(o);
    console.log(obj.name,obj.age);

结果

 浅谈JavaScript原型链

2.混入式继承

    var obj1 = {
        name:"张三",
        age:"18"
    };
    var obj2 = {};
    for(var k in obj1){
        obj2[k] = obj1[k];
    }
    console.log(obj1);
    console.log(obj2);

结果

浅谈JavaScript原型链

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);

结果

浅谈JavaScript原型链

 

如何扩展或者修改一个内置对象?

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);

结果

浅谈JavaScript原型链

我们发现MyArray的实例能用自己定义的fn函数,能改变原来Array的方法,还能用Array的方法如同一个数组

而Array并没有受到上面改变的影响

来看看MyArray改变原型后,.prototype的值和它的constructor值

    console.log(MyArray.prototype);
    console.log(MyArray.prototype.constructor);

结果

浅谈JavaScript原型链

我们发现.prototype中有自己添加的fn方法和重写的reverse方法,而我们没有自己添加constructor属性,系统直接通过__proto__找到了Array的原型中的constructor的构造函数,也就是MyArray直接用的Array的构造函数

为什么Array没有被上面的方法重写?

因为是直接在MyArray的prototype中添加的,根本没有Array.prototype的事

为什么MyArray能用Array原型中的方法?

如果MyArray中没有这个方法就会通过__proto__找到原型中arr属性(Array的实例对象)再通过__proto__在它的原型中寻找方法,然后一直向下,形成了原型链

看图说明

浅谈JavaScript原型链

什么是原型链?

1.每个构造函数都有原型对象

2.每个对象都会有构造函数

3.每个构造函数的原型都是一个对象,那么这个原型对象也会有构造函数,那么这个原型对象的构造函数也会有原型对象

4.这样就会形成一个链式的结构,称为原型链

 

画一个简单的原型链来解释

浅谈JavaScript原型链

这是一个最基本的原型链,可以理解为:

a--->A.prototype--->Object.prototype--->null

a中没有的属性会去A的原型中找,如果还是没有就是它的上级Object的原型中找,还是没有就报错

规则:

1.访问对象的成员时,会先去自身查找,找到就使用

2.没有找到,去当前对象的原型中查找,找到就使用

3.没有找到,继续像这个对象的原型的构造函数的原型中查找(向上继续找),找到就使用

4.如果最后到Object的原型都没有找到,就直接报错

 

一个实例对象一共会继承多少成员:

浅谈JavaScript原型链

 

构造函数是怎么来的?

    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);

结果

浅谈JavaScript原型链

我们发现可以通过new Function创建出来一个函数,所以A1构造函数也是一个实例对象由Function函数创建

 

1.那么Function的构造函数是谁 ?

console.log(Function.constructor);

结果

浅谈JavaScript原型链

自己把自己给创建出来了 

 

2.来看看Function的原型是谁?

console.log(Function.prototype);

结果

浅谈JavaScript原型链

 

3.再来看看Function的原型的原型是谁 

console.log(Function.prototype.__proto__);
console.log(Function.prototype.__proto__.constructor);

结果

浅谈JavaScript原型链

Function的原型的原型的构造函数是Object,所以Function的原型的原型是Object的原型,再往上Object的原型就是null了

 

4.那这个Object的构造函数又是谁?

console.log(Object.constructor);

结果

浅谈JavaScript原型链

居然还是Function

 

由上可知

1.构造函数由Function创建

2.Function的构造函数就是自己本身

3.Function的原型是一个空的函数

4.Function的原型的原型是Object的原型

5.Object是Function创建

 

更新原型链图

浅谈JavaScript原型链

有点乱,整理一下

浅谈JavaScript原型链

再换一种画法

浅谈JavaScript原型链

结论:

1. Object构造函数是通过Function构造函数创建的

2.Function构造函数是自己把自己创建的

 

来看一个槽点

console.log(Function.constructor);
console.log(Object.constructor);

结果

浅谈JavaScript原型链

这个结果就是我们上面那个结论,介绍一个运算符instanceof

instanceof运算符希望左操作数是一个对象,右操作数标识对象的类。如果左侧对象是右侧类的实例,则表达式返回为true,否则返回false

看下面的代码

console.log(Function instanceof Function);
console.log(Function instanceof Object);

结果

浅谈JavaScript原型链

Function不是Function自己创建吗?

Function也是Object的实例?

Object不是Function创建的吗?

Object也创建了Function?

再来看看这个

console.log(Object instanceof Function);
console.log(Object instanceof Object);

结果

浅谈JavaScript原型链

真是越来越奇怪了,互相创建??

换个例子看下

    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);

结果

浅谈JavaScript原型链

怎么会出现这种情况?还是得提一下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);

结果

浅谈JavaScript原型链 

没有懂就结合上面的原型链图再看一下

 

我们回到原点,看那四句的输出为什么会是true

先附上图解

浅谈JavaScript原型链

两条原型链

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);

结果

浅谈JavaScript原型链 

请结合上图自己看

 

就写到这吧,emmm......

浅谈JavaScript原型链