原型和原型链

作者: 羽晞yose | 来源:发表于2020-06-28 00:58 被阅读0次

    prototype

    原型,每一个函数都有一个prototype属性,也叫原型对象

    __proto__

    原型链,每一个对象都有一个__proto__属性,指向它的构造函数的prototype属性,也叫继承属性

    上面两个定位不太准确,因为根据MDN文档,其实一个叫原型对象,一个“是”继承属性(也不是prototype属性的名称),具体真要说原型是哪个,我也找不到准确的定义,但MDN上说了__proto__指向一个原型对象的链,所以就是所谓的原型链,而我们开发时经常说原型上的属性,所以我就将其认为是原型(如果有具体说明的文章请给我留言,好涨点知识)

    代码图示说明

    function Animal () {
        this.type = '动物';
    }
    
    Animal.prototype.type = '哺乳类';
    
    let cat = new Animal();
    
    console.log(cat.__proto__ === Animal.prototype); // true
    
    原型与原型链
    • 每一个函数定义的时候都会有一个prototype属性,prototype里会有一个constructor属性,保存该函数指向
    • 当构造函数Animal通过new关键字实例出一个对象时,该对象cat会有一个__proto__属性,指向原函数的prototype
    • 假如cat中有某个属性不在自己的实例上,那么就会通过原型链向上查找(下面是伪代码)
    cat.__proto__ -> Animal.prototype
    
    • 如果构造函数的原型上也没找到,那么会通过原型的__proto__继续向上查找(因为prototype也是对象),那么就会去到Object(下面是伪代码)
    cat.__proto__ -> Animal.prototype -> Animal.prototype.__proto__ -> Object.prototype
    
    • 当Object的原型上也找不到了的时候,就会通过Object的原型的__proto__继续查找。但原型链并不是无穷无尽的,Object.prototype.proto就是原型链的顶层,所以此时返回null
      console.log(Object.prototype.__proto__); // null

    验证:删除cat自身属性type,那么它会往上层继续查找,所以会输出哺乳类

    console.log(cat.type); // 动物
    delete cat.type;
    console.log(cat.type); // 哺乳类
    

    特别说明

    一般对象和函数都遵循上面说法,但有个比较特殊,那就是FunctionObject之间在原型链上的关系,因为他们既是对象也是函数,所以有定义

    • Function.prototype === Function.__proto__
    • Object.__proto__ === Function.prototype
    • Object.__proto__ === Function.__proto__
    console.log(Function.prototype === Function.__proto__); // true
    console.log(Object.__proto__ === Function.prototype); // true
    console.log(Object.__proto__ === Function.__proto__); // true
    

    hasOwnProperty 和 in 关键字

    这两个都是用来查找对象属性的,区别在于:

    • Object.hasOwnProperty()只会查看是否存在当前实例上
    • in关键字会查找是否属于原型 或 实例上的属性
    function Animal() {}
    Animal.prototype.type = '动物';
    
    let cat = new Animal();
    
    console.log(cat.hasOwnProperty('type')); // false
    console.log('type' in cat); // true
    

    Object.getPrototypeOf() 和 Object.setPrototypeOf()

    虽然很多浏览器都实现了__proto__,但是__proto__并非javascript标准,所以ES6新增了Object.getPrototypeOf()Object.setPrototypeOf()方法来获取原型链

    相关文章

      网友评论

        本文标题:原型和原型链

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