zoukankan      html  css  js  c++  java
  • JavaScript原型与原型链

    要了解原型和原型链,首先来看看构造函数:

    构造函数

    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    var person1 = new Person('Tom',5);
    var person2 = new Person('Jack',3);

    要创建 Person 的新实例,必须使用 new 操作符。new操作符的原理:

    • 创建一个新对象;

    • 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);

    • 执行构造函数中的代码(为这个新对象添加属性);

    • 返回新对象。

    上面的例子中,person1 和 person2 都是构造函数 Person 的实例,这两个实例都有一个 constructor(构造函数)属性,该属性包含一个指向构造函数 Person 的指针。

    console.log(person1.constructor == Person);//true
    console.log(person2.constructor == Person);//true

    事实上,说实例拥有构造函数不太准确,具体的应该是:

    原型与原型链

    放一张经典的图和我自己的理解:

    只要创建了一个新函数,就会为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。

    所有原型对象都会自动获得一个 constructor (构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。

    当调用构造函数创建一个新实例后,该实例的内部将包含一个指针[[prototype]](内部属性__proto__),指向构造函数的原型对象。

    function Foo(){};
    var f = new Foo();
    console.log(Foo.prototype.constructor == Foo);//true
    console.log(f.__proto__ == Foo.prototype);//true

    所有通过 new Function() 创建的对象都是函数对象,可以理解为 Function 的实例对象,其内部属性__proto__指向Function.prototype。

    function Foo(){};
    var Foo2 = function(){};
    var Foo3 = new Function('str','console.log(str)');
    
    console.log(Foo.__proto__ == Function.prototype);//true
    console.log(Foo2.__proto__ == Function.prototype);//true
    console.log(Foo3.__proto__ == Function.prototype);//true

    var obj = {};

    它等同于下面这样:

    var obj = new Object();

    obj 是构造函数(Object)的一个实例。所以:

    obj.constructor === Object              
    obj.__proto__ === Object.prototype

    创建对象的构造器不仅仅有 Object,我们也可以构造函数来创建 Function、Array、Number、Boolean、String、Date、RegExp对象,这些构造器也是函数对象(用Function构造的是函数):

    console.log(Object.__proto__ == Function.prototype);//true
    console.log(Function.__proto__ == Function.prototype);//true
    console.log(Array.__proto__ == Function.prototype);//true
    console.log(Number.__proto__ == Function.prototype);//true
    console.log(String.__proto__ == Function.prototype);//true
    console.log(Boolean.__proto__ == Function.prototype);//true

    默认的原型:

    所有引用类型默认都继承了 Object,而 这个继承也是通过原型链实现的。

    所有函数的默认原型 prototype 都是 Object 的实例,因此默认原型都会包含一个内部指针__proto__,指向 Object.prototype。这也正是所有自定义类型都会继承 toString()、 valueOf() 等默认方法的根本原因。

    console.log(Foo.prototype.__proto__ == Object.prototype);//true
    
    console.log(Function.prototype.__proto__ == Object.prototype);//true
    console.log(Array.prototype.__proto__ == Object.prototype);//true
    console.log(Number.prototype.__proto__ == Object.prototype);//true
    console.log(String.prototype.__proto__ == Object.prototype);//true
    console.log(Boolean.prototype.__proto__ == Object.prototype);//true
    
    //null是原型链的顶端
    console.log(Object.prototype.__proto__ == null);

    原型链的基本概念:

    每个函数都有一个原型对象,原型对象都自动包含一个指向函数的指针,而实例都包含一个指向原型对象的内部指针。

    假如我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型对象的指针,相应地,另一个原型对象中也包含着一个指向另一个函数的指针。

    假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。

    连接是存在与实例与原型对象之间的,即原型链的实现是通过__proto__实现的

    console.log(Foo.prototype.constructor == Foo);//true
    console.log(f.__proto__ == Foo.prototype);//true
    //下面这个关系是通过原型链的搜索实现的
    console.log(f.constructor == Foo);//true

    实例对象本身是没有 constructor 属性的,实例包含一个内部属性__proto__,该属性仅仅指向了 Person.prototype。对 constructor 的访问是通过查找对象属性的过程来实现的。先搜索实例对象 f 本身,没有找到,则搜索Foo.prototype,在Foo.prototype中找到了constructor属性,该属性指向构造函数Foo。

    红宝书中给出的栗子的关系图:

     

    原型搜索机制:

    访问一个实例属性时,首先会在实例本身中搜索该属性。如果没有找到该属性,则会继续搜索实例的原型。在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。

  • 相关阅读:
    LeetCode "Super Ugly Number" !
    LeetCode "Count of Smaller Number After Self"
    LeetCode "Binary Tree Vertical Order"
    LeetCode "Sparse Matrix Multiplication"
    LeetCode "Minimum Height Tree" !!
    HackerRank "The Indian Job"
    HackerRank "Poisonous Plants"
    HackerRank "Kundu and Tree" !!
    LeetCode "Best Time to Buy and Sell Stock with Cooldown" !
    HackerRank "AND xor OR"
  • 原文地址:https://www.cnblogs.com/3yleaves/p/9609137.html
Copyright © 2011-2022 走看看