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

    function Fn() {
        this.foo = ‘haha’;
    } // Fn为构造函数
    var f1 = new Fn(); // f1是Fn构造函数创建的对象

    __proto__属性:

    在创建对象的时候,都会有一个属性__proto__,它指向构造函数的原型对象prototype。

    console.log(f1.__proto__ === Fn.prototype); // true

    原型对象:

    每个函数下都有一个子对象prototype,它称为原型对象。它就是指代该构造函数的原型。只有函数才有prototype。当通过new创建一个实例对象的时候,prototype对象的成员都会成为实例化对象的成员。

    console.log(Fn.prototype.constructor === f1.constructor); // true

    扩展

    基础知识明白之后,继续扩展:

    在prototype中,也同样有__proto__属性
    1. 构造函数里的prototype的__proto__,指向Object的prototype
    console.log(Fn.prototype.__proto__ === Object.prototype);//true
    1. Object里的prototype的__proto__,为null
    console.log(Object.prototype.__proto__);//null
    console.log(Fn.prototype.__proto__.__proto__);//null
    1. 函数对象(注意不是用户自定义的Fn)的prototype与__proto__相等
    console.log(Function.prototype === Function.__proto__);//true
    1. Object.__proto__与Function.prototype相等
    console.log(Object.__proto__ === Function.__proto__);//true
    console.log(Function.prototype.__proto__ === Object.prototype); // true
    Object.constructor === Function; // true

    原型对象的作用:

    主要作用用于继承。我们可通过对prototype设置一个函数对象的属性,使得后续通过该函数创建的对象,获得这个属性。例如

    var person = function(name) {
        this.name = name;
    }
    person.prototype.getName = function() {
        return this.name;
    }
    var zhangsan = new person(‘Zhang san’);
    zhangsan.getName(); // Zhang san

    原型链:

    定义:原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链。

    原型链如何允许对象之间继承特性、prototype 属性?如何通过它来向构造器添加方法?

    1. 如何允许对象之间继承特性、prototype 属性?

    function Fn() {
        
    }
    console.log(Fn.prototype);
    运行上述程序,可以看到,prototype原型对象中有constructor和__proto__。
    {
        constructor: ƒ Fn(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }

    添加属性到prototype中:

    function Fn() {
        
    }
    Fn.prototype.foo = 'bar';
    console.log(Fn.prototype)
    结果:
    { foo:
    "bar", constructor: ƒ Fn(), __proto__: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } }

    通过Fn函数创建一个对象,并添加新的属性:

    function Fn() {
      
    }
    Fn.prototype.foo = 'bar';
    var f = new Fn();
    f.type = 'rangle';
    console.log(f);

    结果:

    {
        type: "rangle",
        __proto__: {
            foo: "bar",
            constructor: ƒ Fn(),
            __proto__: {
                constructor: ƒ Object(),
                hasOwnProperty: ƒ hasOwnProperty(),
                isPrototypeOf: ƒ isPrototypeOf(),
                propertyIsEnumerable: ƒ propertyIsEnumerable(),
                toLocaleString: ƒ toLocaleString(),
                toString: ƒ toString(),
                valueOf: ƒ valueOf()
            }
        }
    }

    __proto__指向的是Fn构造函数,在创建f对象之前,通过构造函数的prototype原型赋给了foo属性,那么如果执行f.foo,能否获得对应的值呢?

    function Fn() {
      
    }
    Fn.prototype.foo = 'bar';
    var f = new Fn();
    f.type = 'rangle';
    console.log(f.foo);
    console.log(f.type)

    结果:

    bar
    rangle

    当访问一个对象的属性时,浏览器首先会查找该对象是否有这个属性,如果没有在该对象中找到,则会在它的__proto__中去找,如果这个__proto__也没有,则又在__proto__的__proto__去找,以此类推,最终的Object.__proto__是null,原型链上面的所有的__proto__都被找完了, 浏览器所有已经声明了的__proto__上都不存在这个属性,然后就得出结论,这个属性是 undefined。
    示例:

    function Fn() {
      
    }
    Fn.prototype.foo = 'bar';
    var f = new Fn();
    f.type = 'rangle';
    console.log(f.foo);
    console.log(f.type);
    var f2 = new Fn();
    console.log(f2.foo);
    console.log(f2.type);

    结果:

    bar
    rangle
    bar
    undefined

    2. 如何通过它来向构造器添加方法?
    每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数。

    事实上,一种极其常见的对象定义模式是,在构造器(函数体)中定义属性、在 prototype 属性上定义方法。如此,构造器只包含属性定义,而方法则分装在不同的代码块,代码更具可读性。我们可以通过prototype,向构造器添加方法, 例如:

    // 构造器及其属性定义
    
    function Test(a,b,c,d) {
      // 属性定义
    };
    
    // 定义第一个方法
    
    Test.prototype.x = function () { ... }
    
    // 定义第二个方法
    
    Test.prototype.y = function () { ... }
  • 相关阅读:
    php分享三十:php版本选择
    php分享二十九:命名空间
    高性能mysql读书笔记(一):Schema与数据类型优化
    php分享二十八:mysql运行中的问题排查
    php分享二十七:批量插入mysql
    php分享二十六:读写日志
    Python | 一行命令生成动态二维码
    Python-获取法定节假日
    GoLang-字符串
    基础知识
  • 原文地址:https://www.cnblogs.com/yangwenbo/p/11447560.html
Copyright © 2011-2022 走看看