zoukankan      html  css  js  c++  java
  • js之原型及原型链

    构造函数创建对象
    function Person() {
    
        }
        let person1 = new Person()
        let person2 = new Person()
        person1.name = 'james'
        person2.name = 'kobe'
        console.log(person1);
        console.log(person2);
    

    我们通过new来创建一个person实例,我们可以看到不同的实例拥有自己的属性。

    proto

    我们可以看到每个对象下都会有__proto__的属性,这个属性会指向该对象的原型

        function Person() {
    
        }
        Person.prototype.name = 'chris'
        let person = new Person()
        let person1 = new Person()
        let person2 = new Person()
        person1.name = 'james'
        person2.name = 'kobe'
        console.log(person);
        console.log(person1);
        console.log(person2);
    


    我们看到__proto__下会出现prototype的name属性,那么__proto__与prototype关系又是什么呢?

    prototype

    每个函数都有具有 prototype属性,就是我们经常在用到的prototype

    Person.prototype.name = 'chris‘
    

    那么问题来了,那这个函数的 prototype 属性到底指向的是什么呢?是这个函数的原型吗?
    其实,函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是这个例子中的 person1 和 person2 的原型。

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

    通过实例的__proto__和构造函数的prototype的对比,我们不难发现person 和 Person.prototype 的关系

    person.__proto__ === Person.prototype  //true
    

    既然实例对象和构造函数都可以指向原型,那么原型是否有属性指向构造函数或者实例呢?

    constructor

    不难发现,每个构造函数都有 constructor这个属性, 通过控制台我们会发现constructor 属性指向关联的构造函数

    这样我们就了解了构造函数、实例原型、和实例之间的关系,接下来我们讲讲实例和原型的关系:

    实例下的原型

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

        function Person() {
    
        }
        console.log(Person.prototype.name);   //underfind
        Person.prototype.name = 'chris';
    
        var person = new Person();
    
        person.name = 'james';
        console.log(person.name) // james 拿到实例的name属性
    
        delete person.name;
        console.log(person.name) // chris 拿到原型的name属性
    

    但是万一还没有读取到呢?原型下的原型又是什么呢?

    原型下的原型

    通过上面的知识我们知道person.__proto__与Person.protype相等,那么Person.prototype.proto__下又是什么呢?很显然就是对象实例的__proto

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

        let obj = new Object();
        obj.__proto__.name = 'chris'
        obj.name = 'Kevin'
        console.log(obj.name) // Kevin
        delete obj.name
        console.log(obj.name) // chris
    
    原型链

    既然我们知道Object的原型,那 Object.prototype的原型呢?

    我们可以看到返回一个null,表达的就是已经没有原型了。
    最终就是原型和原型链的结构

    一些补充

    关于 Funtion 中的原型 我们可以会发现 Function.prototype 有些特殊

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

    这样看上去实例的原型和原型的原型是相等的,即是鸡也是蛋。 我们可以参考MDN关于__proto__的解释:

    __proto__的读取器(getter)暴露了一个对象的内部  [[Prototype]] 。对于使用对象字面量创建的对象,这个值是  Object.prototype。对于使用数组字面量创建的对象,这个值是 Array.prototype。对于functions,这个值是Function.prototype。对于使用 new fun 创建的对象,其中fun是由js提供的内建构造器函数之一(ArrayBooleanDateNumberObjectString 等等),这个值总是fun.prototype。对于用js定义的其他js构造器函数创建的对象,这个值就是该构造器函数的prototype属性。

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

    引用冴羽的理解

    至于为什么Function.proto === Function.prototype,我认为有两种可能:一是为了保持与其他函数一致,二是就是表明一种关系而已。
    简单的说,就是先有的Function,然后实现上把原型指向了Function.prototype,但是我们不能倒过来推测因为Function.proto === Function.prototype,所以Function调用了自己生成了自己。

    总结

    1、实例对象的__proto__始终指向构造函数的prototype

    2、只有构造函数才拥有prototype属性,对象(除了null)都拥有__proto__属性

    3、每一个原型对象都有一个constructor属性指向它们的构造函数

    4、要读取属性时,先读取实例上的属性,读取不到会在原型链上寻找相应属性

    5、原型链按照__proto__的指向下一级对象

    6、原型链的尽头始终是null

    7、构造函数实例化以后,既是构造函数函数,也是对象

    function Foo() {
    }
    const obj = new Foo()
    
    Foo.prototype === obj.__proto__                          //true
    obj.constructor === Foo                                        //true
    Foo.prototype.__proto__ === Object.prototype   //true
    Object.prototype.__proto__ === null                   //true
    Object.constructor === Function                         //true
    

    原文:https://juejin.im/post/5d0606286fb9a07ecb0ba713

  • 相关阅读:
    css 计数器
    页面自动刷新的几种方式
    jq的“钉”插件--jquery.pin.js
    CSS3之Transform(变形)一
    css3之Transition(转换)
    常用css+css3集锦
    JQuery需要手动回收xmlHttpRequest对象
    javascript 闭包暴露句柄和命名冲突的解决方案
    firefox浏览器删除插件
    jQuery中的.bind()、.live()和.delegate()之间区别分析
  • 原文地址:https://www.cnblogs.com/jessie-xian/p/11596113.html
Copyright © 2011-2022 走看看