zoukankan      html  css  js  c++  java
  • 深刻理解下js的prototype

    参考 http://aralejs.org/class/docs/competitors.html, http://www.iteye.com/topic/248933,http://www.cnblogs.com/qiantuwuliang/archive/2011/01/08/1930548.html

    1、使用Dog.prototype.__proto__ 

    function Animal() {}
    function Dog() {}
    
    // 要让 Dog 继承 Animal, 只需:
    Dog.prototype.__proto__ == Animal.prototype;
    
    // 实例化后
    var dog = new Dog();
    // dog.__proto__ 指向 Dog.prototype
    // dog.__proto__.__proto__ 指向 Animal.prototype
    // 原型链已成功建立起来,而且很清晰
    

      

    function Animal(name) {
       this.name = name;
    }
    Animal.prototype = {
        talk: function() {},
        run: function() {}
    }
    function Dog(age,name) {
       //Animal.call(this,name)  
       this.age=age;
    }
    // 要让 Dog 继承 Animal, 只需:__ 2个_
    Dog.prototype.__proto__ =  Animal.prototype ; // 实例化后
    //Dog.prototype = new  Animal ; //Animal的构造函数和自己的prototype也都放到Dog上
    Dog.prototype.haha = function () {};//
    Dog.prototype.haha.tata = 4;
    var dog = new Dog("sdd","bbb"); 
    var animal = new Animal("aaaa");
    console.log(dog);
    console.log(Dog.prototype);
    console.log(animal.__proto__);
    
    console.log("11 "+(dog instanceof Animal));
    console.log("11 "+(animal instanceof Dog));
    

      

    Dog {name"sdd"talkfunctionrunfunction}
    1. name"sdd"
    2. __proto__Dog
      1. constructorfunction Dog(name) {
        1. argumentsnull
        2. callernull
        3. length1
        4. name"Dog"
        5. prototypeDog
        6. __proto__function Empty() {}
        7. <function scope>
      2. __proto__Object
        1. runfunction () {}
        2. talkfunction () {}
        3. __proto__Object

     __proto__指向了dog本身,并且有constructor,开始循环引用了。dog.__proto__=Dog.prototype。

    dog本身的Dog.prototype没有被覆盖,一个标准的prototype,包括constructor和__proto__,我们只覆盖了这个标准的prototype的__proto__而已。

    如果不加__proto__ 

    function Animal(name) {
       this.name = name;
    }
    Animal.prototype = {
        talk: function() {},
          run: function() {}
    }
    function Dog(name) {
        Animal.call(this,name)    
    }
    // 要让 Dog 继承 Animal, 只需:
    Dog.prototype = Animal.prototype;
    
    // 实例化后
    var dog = new Dog("sdd");
    console.log(dog);

     返回

    Dog {name"sdd"talkfunctionrunfunction}
    1. name"sdd"
    2. __proto__Object
      1. runfunction () {}
      2. talkfunction () {}
      3. __proto__Object

     第二种原型链没有建立,没有constructor,只是简单的把方法赋值过来了。上面用 console.log(dog instanceof Animal ) 都返回ture。

    function Animal(name) {
       this.name = name;
    }
    Animal.prototype = {
        talk: function() {},
      	run: function() {}
    }
    function Dog(name) {
    	Animal.call(this,name)	
    }
    // 要让 Dog 继承 Animal, 只需:
    Dog.prototype = Animal.prototype;//有没有有__proto__都会被覆盖
    Dog.prototype = {
        qqq: function() {},
      	wwww: function() {}	
    }
    
    // 实例化后
    var dog = new Dog("sdd");
    console.log(dog);
    console.log(dog instanceof Animal );
    

      

    Dog {name: "sdd", qqq: function, wwww: function}
    name: "sdd"
    __proto__: Object
      qqq: function () {}
      wwww: function () {}
      __proto__: Object

     Dog.prototype被覆盖了,本身的constructor和__proto__不存在了,变 Animal.prototype了。

    2,使用new

    function Animal(name) {
       this.name = name;
    }
    Animal.prototype = {
        talk: function() {},
        run: function() {}
    }
    function Dog(age,name) {
       //Animal.call(this,name)  
       this.age=age;
    }
    // 要让 Dog 继承 Animal, 只需:__ 2个_
    //Dog.prototype.__proto__ =  Animal.prototype ; // 实例化后
    Dog.prototype = new  Animal ; //Animal的构造函数和自己的prototype也都放到Dog上
    Dog.prototype.haha = function () {};
    var dog = new Dog("sdd","bbb"); 
    var animal = new Animal("aaaa");
    console.log(dog);
    console.log(dog.__proto__);
    console.log(animal.__proto__);
    console.log(dog.__proto__===Dog.prototype);
    

     

    Dog {age: "sdd", name: undefined, haha: function, talk: function, run: function}
    age: "sdd"
    __proto__: Animal
      haha: function () {}
      name: undefined
      __proto__: Object
        run: function () {}
        talk: function () {}
        __proto__: Object

     new 是调用构造函数的,会把构造函数上的属性拿过来,没有constructor,只有new 带构造函数。__proto__是实例化后才有,他代表的原型链,可以共享的原型链,上图中方法haha 也放到__proto__中了。

    Dog.prototype被覆盖了,本身的constructor和__proto__不存在了,变 new Animal了,于是构造函数都传过来了。

    没有继承的情况下,如下图所示,prototype没有被覆盖,constructor保留,是Dog本身这个函数。dog.constructor === Dog.prototype.constructor

    function Dog(age,name) {
       //Animal.call(this,name)  
       this.age=age;
       this.getName = function (){};
    }
    
    var dog = new Dog("sdd","bbb"); 
    
    console.log(dog);
    
     //结果
    
    Dog {age: "sdd", getName: function}
        age: "sdd"
        getName: function (){}
        __proto__: Dog
            constructor: function Dog(age,name) {
            __proto__: Object
    constructor: function Dog(age,name) {
        arguments: null
        caller: null
        length: 2
        name: "Dog"
        prototype: Dog
        __proto__: function Empty() {}
        <function scope>

    按照《悟透javascript》书中说的,new形式创建对象的过程实际上可以分为三步:

    第一步是建立一个新对象(叫A吧);

    第二步将该对象(A)内置的原型对象设置为构造函数(就是Person)prototype 属性引用的那个原型对象;

    第三步就是将该对象(A)作为this 参数调用构造函数(就是Person),完成成员设置等初始化工作。

    其中第二步中出现了一个新名词就是内置的原型对象注意这个新名词跟prototype对象不是一回事,为了区别我叫它inobj,inobj就指向了函数Person的prototype对象。在person的prototype对象中出现的任何属性或者函数都可以在one对象中直接使用,这个就是javascript中的原型继承了

    总结: 1)Dog.prototype =  Animal.prototype 或者Dog.prototype.__proto__ =  Animal.prototype 时,dog instanceof Animal 都是true。Dog.prototype.__proto__ =  Animal.prototype,实际实例化后是      dog.__proto__.__proto__=Animal.prototype。沿着A的原型链查找 如果有一个原型和B.prototype相等 则返回true  , 如:A.__proto__.__proto__ === B.prototype 则返回true 

         js的 instanceof 是根据什么来判断两个对象的继承关系?参考:http://yxc-gdut.iteye.com/blog/1812766 

         js的instanceof是根据prototype来判断两个对象是否存在继承关系,A instanceof B, js会沿着A的原型链查找 直到找到A.__proto__ === B.prototype 返回true。

         一句话__proto__一层层都是指向继承的,最终到基本类型上。没有继承的就是他的protoype,包含constructorfunction () {},__proto__Object,和他自己加的方法。

         下图展示的new方法的,Dog.prototype = new  Animal ;所以dog第一层__proto__有name, new把构造函数有传入了。只有有prototype chrome下才能展示出来下面的结构。

    Dog {age: "sdd", name: undefined, haha: function, talk: function, run: function}
    age: "sdd"
    __proto__: Animal
        haha: function () {}
        name: undefined
        __proto__: Object
            run: function () {}
            talk: function () {}
            __proto__: Object            
    

            2)理解下function ,如下图。function ,包括 arguments, caller,length,name ,prototype,__proto__,他的prototype,又分为constructorfunction () {},__proto__Object,然后constructor这个function 又继续循环。

         __proto__他从别的原型链继承过来可以直接用的,prototype是他要加在自己原型链上的,供别人调用,或者直接实例化后,别人可以直接调用转成__proto__的。

    run: function () {}
    arguments: null
    caller: null
    length: 0
    name: ""
    prototype: Object
        constructor: function () {}
        __proto__: Object
    __proto__: function Empty() {}
    var AAA= function(name) {
        this.name=222;	
    }
    AAA.dhj="123";
    AAA.prototype.www=function(){};
    var aaa=new AAA();
    console.log(aaa);
    

      有继承关系的__proto__他指向的是指定的继承的那个,没有继承关系的__proto__依然保留constructorfunction () {},__proto__Object。

    AAA {name: 222, www: function}
    name: 222
    __proto__: Object
    constructor: function (name) {
    www: function (){}
    __proto__: Object

    按照javascript的说法,function定义的这个是一个Object(对象),而且还是一个很特殊的对象,这个使用function定义的对象与使用new操作符生成的对象之间有一个重要的区别。这个区别就是function定义的对象有一个prototype属性,使用new生成的对象就没有这个prototype属性prototype属性又指向了一个prototype对象,注意prototype属性prototype对象是两个不同的东西,要注意区别。在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身。

    下面分析下constructor 

    function Animal(name) {
       this.name = name;
       var a=1;
    }
    Animal.prototype.talk=function(){};
    var animal = new Animal("aaaa");
    function Dog(age,name) {
       //Animal.call(this,name)  
       this.age=age;
       this.getName = function (){};
    }
    // 要让 Dog 继承 Animal, 只需:__ 2个_
    //Dog.prototype.__proto__ =  Animal.prototype ; // 实例化后
    Dog.prototype = animal ; //注意这里啊,
    Dog.prototype.constructor = Dog;//animal本身也有constructor,animal本身也指定到这里。引用传递。animal已经实例化了 
    var dog = new Dog("sdd","bbb"); console.log(dog); console.log(dog.constructor);; console.log(animal); console.log(animal.constructor);

      

    Dog {age: "sdd", getName: function, name: "aaaa", constructor: function, talk: function}
        age: "sdd"
        getName: function (){}
        __proto__: Animal
     
    
    function Dog(age,name) {
       //Animal.call(this,name)  
       this.age=age;
       this.getName = function (){};
    }
    
    
    Animal {name: "aaaa", constructor: function, talk: function}
        constructor: function Dog(age,name) {
        name: "aaaa"
        __proto__: Animal
    
    
    function Dog(age,name) {
       //Animal.call(this,name)  
       this.age=age;
       this.getName = function (){};
    } 
  • 相关阅读:
    IP地址与域名的关系
    微信公众平台开发
    jquery实现对div的拖拽功能
    js控制表格实时编辑
    删除提示框插件
    基于jquery的bootstrap在线文本编辑器插件Summernote (转)
    从输入网址到显示网页的过程中发生了什么?
    TP框架---thinkphp中ajax分页
    使背景图片适应不同分辨率电脑
    TP框架---验证码
  • 原文地址:https://www.cnblogs.com/danghuijian/p/3747200.html
Copyright © 2011-2022 走看看