深入理解下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.htmljavascript

一、使用Dog.prototype.__proto__ html

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。java

dog自己的Dog.prototype沒有被覆蓋,一個標準的prototype,包括constructor和__proto__,咱們只覆蓋了這個標準的prototype的__proto__而已。chrome

若是不加__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);

 返回this

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

 

 第二種原型鏈沒有創建,沒有constructor,只是簡單的把方法賦值過來了。上面用 console.log(dog instanceof Animal ) 都返回ture。spa

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了。prototype

2,使用newcode

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__中了。orm

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 (){};
} 
相關文章
相關標籤/搜索