zoukankan      html  css  js  c++  java
  • JavaScript深入之——原型与原型链

    很长一段时间对JS的原型与原型链理解的很模糊,而想学好JS,原型与原型链却是绕不开的话题,所以只好进行对其进行一个梳理。

    理解原型和原型链,需理解三个重要的属性: prototype、__proto__、constructor

    prototype

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

    代码示例:

    function Person(){
    
    }
    
    Person.prototype.name = 'zhangsan'
    let person = new Person()
    
    console.log(person.name)    // zhangsan
    

    上面的代码中,创建了一个构造函数Person,并在它的原型上添加一个属性name为zhangsan, 然后再创建了实例对象person,那么这个实例对象上也有name属性,打印输出“zhangsan”

    可以看出:

    Person这个函数的prototype属性指向了一个对象,即:Person.prototype 也是一个对象,这个对象正是调用该构造函数而创建的实例的原型,即person的原型。

    方便理解,我们进行拆解:

    1.创建了构造函数Person
    
    2.使用new关键字进行调用
    
    3.调用得到了实例person
    
    4.实例和原型的关系:person的原型就是Person.prototype
    

      

    那什么是原型呢?可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另外一个对象,这个对象就是我们所说的原型,而每一个对象都会从原型"继承"属性。

    我们用一张图表示构造函数和原型之间的关系:

    构造函数和实例原型之间的关系我们已经梳理清楚了,那怎么表示实例与原型,也就是person和Person.prototype之间的关系呢?

    __proto__

    其实每一个JavaScript对象(除了null)都有一个属性,叫__proto__,这个属性会指向该对象的原型。

    代码示例:

    function Person(){
    
    }
    
    let person = new Person()
    console.log(person.__proto__ === Person.prototype)   // true
    

    构造函数Person的实例对象person,有个属性叫__proto__,这个属性指向原型,即Person.prototype。

    补全上面的关系图:

    Q:原型是否有属性指向构造函数或者实例对象呢?

    constructor

    代码示例:

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

    继续完善关系图:

    原型的constructor指向构造函数,但没有属性指向实例,因为可能有多个实例。

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

    console.log(person.constructor === Person)   // true
    console.log(person.constructor === Person.prototype.constructor)  // true
    

      

      

     实例与原型

    当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。

    代码示例:

     function Person() {
    
    }
    
    Person.prototype.name = 'zhangsan';
    
    let person = new Person();
    
     person.name = 'lisi';
     console.log(person.name) // lisi
    
    delete person.name;
    console.log(person.name) // zhangsan
    

     

    new创建了一个实例对象person,有个属性name值为“lisi”,当我们把删除了这个name属性后,依然能够打印出“zhangsan”,实际情况是从 person 实例对象中找不到 name 属性,就会从 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查找,幸运的是我们找到了 name 属性,结果为 zhangsan

    原型的原型

    代码示例:

    Object.prototype.name = 'wangwu'
    
    function Person(){
    
    }
    
    let person = new Person()
    		
    		
    console.log(person.name)   // wangwu
    

    Person 的实例对象person,本身没有name属性值,所有会去原型上找,Person.prototype上也没有,就去原型的原型上找,即:Object.prototype,有一个name为“wangwu”的属性,所有输出“wangwu”

    其实原型对象就是通过Object构造函数生成的,结合之前我们所说的,实例的__proto__指向构造函数的 prototype 所以我们再丰富一下我们的关系图:

    原型链

    那Object.prototype 的原型呢?Object是根节点的对象,再往上查找就是null,我们可以打印:

      console.log(Object.prototype.__proto__ === null) // true
    

     我们将null也加入关系图,就比较完整了:

     

    上面的person实例对象到null的这条线即为原型链。

    我们还可以把大Function加上

    console.log(Person.constructor === Function)  // true
    console.log(obj.__proto__ === Object.prototype) // true
    console.log(obj.__proto__.constructor === Object) /// true
    console.log(obj.__proto__.constructor.__proto__ === Function.prototype) // true
    console.log(obj.__proto__.constructor.__proto__.constructor === Function) // true
    console.log(Person.__proto__ === Function.prototype) // true console.log(Object.__proto__ === Function.prototype) // true

     从网上找了张图,现在再去理解原型与原型链,就好理解了吧

  • 相关阅读:
    Example [mybatis] 的用法
    开发中可能会用到的几个 jQuery 小提示和技巧
    setInterval 与 clearInterval详解
    15个华丽的扁平风格登录界面
    原生js模拟jquery写法
    纯色扁平化网站
    javascript刷新页面的集中办法
    javascript闭包中循环问题
    20个实用javascript技巧及实践(二)
    20个实用的javascript技巧及实践(一)
  • 原文地址:https://www.cnblogs.com/wangdashi/p/10342112.html
Copyright © 2011-2022 走看看