• JS 原型以及原型链


     // 原型链图
        /**
         * 原型对象
         * 无论什么时,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性
         * 这个属性指向该函数的原型对象。默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)
         * 属性,这个属性包含一个指向 prototype 属性所在函数的指针。当构造函数创建一个新实例后,
         * 该实例的内部包含一个指针[[Prototype]](内部属性),指向构造函数的原型对象。
         */
    
        /**
         * 如:
         * 创建一个函数 A:function A(){}
         * function A(){} 会有一个属性: prototype 属性
         * function A(){} 的原型对象为: A.prototype
         * function A(){} 的原型对象会自动获得一个 constructor 属性: A.prototype.constructor
         * 那么:
         * function A(){} 中的 prototype 属性 ---(指向)---> A.prototype (function A(){} 的原型对象)
         * A.prototype.constructor (constructor属性) ---(指向)---> function A(){} (函数 A)
         */
        function A(){}
        console.log(A.prototype.constructor==A);//true 可见原型对象中的 constructor 指向函数A
    
        /**
         * 如:
         * 使用 new 关键字结合 A() 函数来创建实例 obj
         * 则 obj 这个实例会有一个 [[Prototype]] 内部属性指向 A 的原型对象 A.prototype
         * Firefox、Safari 和Chrome 在每个对象上都支持一个属性 __proto__ ,它就相当于 [[Prototype]]
         */
    
        var obj=new A();
        console.log(obj.__proto__==A.prototype);//true 可见实例中的 [[Prototype]] 指向函数原型 A.prototype
        
        A.prototype.name="guang";//给A的原型对象增加一个name:"guang"属性
        A.prototype.sayName=function(){return this.name};//给A的原型对象增加一个sayName方法
        var obj=new A();
        console.log(obj.sayName());//guang

    原型

        // 上图展示了A 构造函数、A 的原型属性以及A 现有的实例 obj之间的关系。
        // 在此,A.prototype 指向了原型对象,而A.prototype.constructor 又指回了A。
        // 原型对象中除了包含constructor 属性之外,还包括后来添加的其他属性。A 的每个实例—
        // 都包含一个内部属性,该属性仅仅指向了 A.prototype原型对象,而构造函数没有直接的关系。
        // 虽然这 obj实例不包含属性和方法,但却可调用 A.sayName(),这是通过查找对象属性的过程来实现的。
    
        // 每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先
        // 从对象实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,
        // 则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。如果在原型对象中找到了这
        // 个属性,则返回该属性的值。
    
        // 对于上面的例子而言,在调用A.sayName()的时候,会先后执行两次搜索
        // 首先,解析器会问:“实例A 有sayName 属性吗?”答:“没有。”然后,它继续搜索,再
        // 问:“A 的原型有sayName 属性吗?”答:“有。”于是,它就读取那个保存在原型对象中的函数。
        // 而这正是多个对象实例共享原型所保存的属性和方法的基本原理。
        /**
         * 原型链
         * 每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
         * 当一个原型对象是另一个原型对象的实例时,该原型对象将包含一个指向另一个原型的指针。相应地,另一个原型中也包含着一个指向
         * 另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条
         */
    
        function SuperType(){
            this.property = true;
        }
        SuperType.prototype.getSuperValue = function(){
                return this.property;
        };
        function SubType(){
            this.subproperty = false;
        }
        //继承了SuperType
        SubType.prototype = new SuperType();
        SubType.prototype.getSubValue = function (){
            return this.subproperty;
        };
        var instance = new SubType();
        console.log(instance.getSuperValue()); //true
          console.log(instance.constructor == SubType,instance.constructor == SuperType); //false true
    //以上代码定义两个类型:SuperType、SubType。通过创建 SuperType的实例,原型对象 SubType.prototype 继承了SuperType的属性
    //本质上是通过重写原型对象实现继承。如图:

    原型链

    // 在上面的代码中,并没有使用SubType 默认提供的原型,而是给它换了一个新原型;这个新原型
    // 就是SuperType 的实例。于是,新原型不仅具有作为一个SuperType 的实例所拥有的全部属性和方法,
    // 而且其内部还有一个指针,指向了SuperType 的原型。
    // 最终结果就是这样的:instance 指向SubType的原型, SubType 的原型又指向SuperType 的原型。
    // getSuperValue() 方法仍然还在 SuperType.prototype 中,但property 则位于SubType.prototype 中。
    // 这是因为property 是一个实例属性,而getSuperValue()则是一个原型方法。既然SubType.prototype 现在是SuperType
    // 的实例,那么property 当然就位于该实例中了。此外,要注意instance.constructor 现在指向的
    // 是SuperType,这是因为SubType 的原型指向了另一个对象——>SuperType 的原型,而这个原型对象的constructor 属性指向的是SuperType。
    // 在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。就拿上面的例子来说,调用
    // instance.getSuperValue()会经历三个搜索步骤:1>搜索实例;2>搜索SubType.prototype;3>搜索SuperType.prototype,
    // 4>最后一步才会找到该方法。在找不到属性或方法的情况下,搜索过程总是要一环一环地前行到原型链末端才会停下来。
    // 事实上,因为所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的。
    // 因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承toString()、valueOf()等方法的根本原因。对该例子来说完整的原型链应该如下:

    完整的原型链

  • 相关阅读:
    Delphi 与 C/C++ 数据类型对照表
    JAVA中堆和栈的区别
    关于Column '*' not found 解决方案 Hibernate使用SQL查询返回实体类型,即返回某个类,或实体类
    Oracle笔记
    oracle时间运算
    struts2中iterator标签的相关使用
    url传中文,转码
    表格的css,细线表格
    使用struts 2 获取服务器数据 ongl表达式 标签
    struts 2 Commons FileUpload文件上传
  • 原文地址:https://www.cnblogs.com/go4it/p/9906306.html
Copyright © 2020-2023  润新知