文章出處

值得一說的是對象沒有prototype屬性,只有函數有prototype屬性。

var a = function(){};
a.prototype.d = function(){
    console.log(1);
}

prototype相當于給函數a添加了一個屬性。

var a = function(){};
a.prototype.d = function(){
    console.log(1);
}

var b = new a();
b.d(); //1

用prototype添加的屬性,實例化后這個函數的對象也可以繼承這個屬性。

那為什么要用prototype添加屬性呢?來看看

var a = function(){
    var f = function(){
        console.log(2);
    }
};

var b = new a();
b.f(); //報錯

  為什么報錯?先看一下call方法和new對象的關系這篇文章,看完你就明白b可以繼承函數a的prototype屬性了。

  注意我那篇文章只說的了new可以繼承prototype屬性,但是沒有說它可以繼承函數里面的內容。所以為什么解決這個為什么我們就會用到prototype了,當然有時為了一些優化的原因也會這樣用。

  其實不只是prototype可以解決這個問題,還有this也是可以解決這個問題的,就像我們使用構造函數一樣,我們都是用的this對吧,因為new以后就會改變這個this的指向,然后這個屬性就會變成你創建出來的那個對象的屬性。  對于this的指向問題可以看徹底理解js中this的指向,不必硬背。

function Fn(){
    this.num = 10;
}
var a = new Fn();
console.log(a.num); //10

  那么__proto__是什么?為了更好的理解__proto__建議你先看什么是作用域鏈這篇文章。

  __proto__和作用域的行為類似,只不過__proto__是對于對象的屬性來說的,而作用域鏈是對于變量來說的,什么意思?就是說一個對象如果要打印這個對象的某個屬性,那么它會先在自己的對象中查找,如果沒有找到那么它就會__proto__中找,看看有沒有這個屬性。那么__proto__中到底有哪些屬性?

  你一開始創建的對象__proto__指向了obj.__proto__,也就說明我們創建的任何對象都可以調用obj.__proto__里面的屬性和方法,而obj的__proto__為null,也就是說到obj的__proto__就到頭了。這也就是說如果我們沒有做任何的操作,這個對象只能繼承obj.__proto__的屬性,這里沒有算上obj的__proto__是因為,obj的__proto__為null。

  但是如果我們用了new操作符實例化了一個函數,那么這個new出來的對象就又多了一個繼承對象,那就是那個構造函數。而這個構造函數如果用prototype添加屬性同樣的,這個實例化的對象也可以繼承它的屬性。

  還有一點就是如果這個對象本身就有這個屬性就不會去繼承,繼承只有在這個對象沒有找到的時候才會繼承,就和我們學css的繼承樣式一樣。

function Fn(){
    
}
Fn.prototype.num = 10;
var a = new Fn();
a.num = 20;
console.log(a.num); //20

如果這個對象沒有這個屬性才會繼承,并且這個對象有多個__proto__那么它也只是繼承最近的那個屬性。

function Fn(){
    
}
Fn.prototype.num = 10;
var a = new Fn();
console.log(a.num);

在這段代碼中Fn的__proto__離對象a最近所以繼承它的,而不是obj的。

補充一點:

function Foo() {};
var foo = new Foo();
Foo.prototype.num = 52;
console.log(foo.num); //52
console.log(Foo.num); //undefined

再看

function Foo() {};
var foo = new Foo();
Foo.prototype.num = 52;
console.log(foo.num); //52
console.log(Foo.prototype.num); //52

對,你沒有猜錯,num只是prototype的屬性,而prototype是Foo的屬性,自然只能通過Foo.prototype.num來訪問這個屬性,那么為什么new出來的對象可以不用加prototype就可以訪問num呢?

實際上new出來的對象是這樣的。

var fn = function(a){
    this.a = a;
}
var obj = {};
繼承
obj.__proto__ = fn.prototype;
改變this指向
fn.call(obj);

看到沒有,已經寫了fn.prototype,自然就可以在后面點那個屬性了。ok了吧?


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()