美文网首页js
JS原型与原型链

JS原型与原型链

作者: 书虫和泰迪熊 | 来源:发表于2020-04-02 17:20 被阅读0次

    prototype(原型对象)

    prototype 是函数才有的属性,只要创建一个函数,就会为该函数创建一个prototype 属性(称为原型对象)
    每个原型对象(prototype) 都有两个属性:

    1. constructor 该属性指向构造函数
      Person.prototype.constructor === Person
      
    2. __ proto__
      image.png

    __ proto__ (原型)

    每创建一个JavaScript 对象(除了null),该对象上都会有一个 __ proto__ 属性,这个属性指向该函数的原型对象

    image.png
    总结公式如下
    var 对象 = new 函数()
    对象.__proto__  === 函数.prototype
    

    简单描述 new 一个对象过程
    正常 new一个

    image.png

    自己实现一个


    image.png

    原型链

    上面已经说了

    p.__proto__  ===  Person.prototype   // true
    

    同样 Person.prototype 也是一个对象,所以他也有 __ proto__ 属性,所以

    Person.prototype.__proto__ === Object.prototype  // true
    

    Object也有__ proto__ 属性,但是比较特殊是null,说明 Object 没有继承

    Object.Prototype.__proto__ === null  // true
    

    所以有

    p.__proto__.__proto__ === Object.prototype   // true
    p.__proto__.__proto__.__proto__ === null      // true
    

    我们把这种由 __ proto__ 串起来直到 Object.prototype.__ proto__ 为 null 的链叫原型链,原型链的形成真正靠的是 __ proto__,而不是 prototype。
    如下图


    image.png

    由此可以得到下面结论
    所有函数都是 Function 的实例,Object, Number, String 这些都是函数 - 构造函数,所以他们都是Function 的实例。

    Number.__proto__ === Function.prototype  // true
    String.__proto__ === Function.prototype     // true
    Object.__proto__ === Function.prototype    // true
    

    那Function是谁的实例?
    Function的直接实例还是Function

    Function.__proto__ === Function.prototype   // true
    Function.__proto__.__proto__ === Function.prototype.__proto__  // true
    



    instanceof的底层实现原理,手动实现一个instanceof
    instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
    即 实例.__ proto __ ==? 函数.prototype 或者沿着原型链想上(Object)寻找,如下
    实例.__ proto __ . __ proto __ ....... ==? 函数.prototype

    // 因为 instanceof 是个关键字,我们只能写一个函数 instance_of 来模拟 instanceof 功能
    function instance_of(L, R) {   //L 表示左表达式,R 表示右表达式
        var O = R.prototype;
        L = L.__proto__;
        while (true) { 
            if (L === null) 
            return false; 
            if (O === L) // 这里重点:当 O 严格等于 L 时,返回true 
            return true; 
            L = L.__proto__; 
        } 
    }
    
    // 测试
    var a = []
    var b = {}
     
    function Foo(){}
    var c = new Foo()
     
    function child(){}
    function father(){}
    child.prototype = new father() 
    var d = new child()
     
    console.log(instance_of(a, Array)) // true
    console.log(instance_of(b, Object)) // true
    console.log(instance_of(b, Array)) // false
    console.log(instance_of(a, Object)) // true
    console.log(instance_of(c, Foo)) // true
    console.log(instance_of(d, child)) // true
    

    问题:A instanceof B 和 B.isPrototypeOf(A) 区别
    · A instanceof B :instanceOf运算符用于检测 构造函数(B)的prototype属性是否出现在某个实例对象(A)的原型链上。
    · B.isPrototypeOf(A):检测B对象是否出现于A对象的原型链上
    注:isPrototypeOf()instanceof 运算符不同。在表达式 "object instanceof AFunction"中,object 的原型链是针对 AFunction.prototype 进行检查的,而不是针对 AFunction 本身。
    若使用 isPrototypeOf 检测出来的结果为 true 则 instanceof 一定为true,反之不成立。

    小练1:

    function Person() {
    }
    
    Person.prototype.name = 'Kevin';
    
    var person = new Person();
    
    person.name = 'Daisy';
    console.log(person.name) // Daisy
    
    delete person.name;
    console.log(person.name) // Kevin
    
    

    第一次输出 person.name 自然是 Daisy,但是当我们删除了 person.name 之后,在person对象中读取不到 name 属性,就会从person的原型 person.__ proto__ 中读取,即从 Person.prototype 中读取name。则为 Kevin。

    继承

    原型链是实现继承的一种方式
    String, Number 继承 Object

    String.prototype.__proto__ === Object.prototype    // true
    Number.prototype.__proto__ === Object.prototype  // true
    

    Object 没有继承

    Object.prototype.__proto__ === null
    

    Function继承谁呢?哈哈!!Function.prototype 也是一个对象,所以Function继承Object~~

    Function.prototype.__proto__ === Object.prototype
    

    小练2:

    var F = function() {}
    Object.prototype.a = function() {}
    Function.prototype.b = function() {}
    var f = new F()
    

    问:f.a 和 f.b 那个能拿到???
    答:f.a 能拿到,f.b 不能拿到
    解析:f.a 先去 f 对象中查找 a 发现没有,再去 f.__ proto__中查找 a,即是F.prototype 中查找 a,又没有,F.prototype是对象再接着去 F.prototype的原型,即F.prototype.__ proto__ 上查找,即Object.prototype 上查找,lucky 找到

    补充

    constructor

    function Person() {
    }
    var person = new Person();
    console.log(person.constructor === Person); // true
    

    当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:

    person.constructor === Person.prototype.constructor
    

    __ proto__
    其次是 __ proto__ ,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.__proto __ 时,可以理解成返回了 Object.getPrototypeOf(obj)。

    真的是继承吗?
    最后是关于继承,前面我们讲到“每一个对象都会从原型‘继承’属性”,实际上,继承是一个十分具有迷惑性的说法,引用《你不知道的JavaScript》中的话,就是:
    继承意味着复制操作,然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些

    相关文章

      网友评论

        本文标题:JS原型与原型链

        本文链接:https://www.haomeiwen.com/subject/nmhauhtx.html