值得一說的是對象沒有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了吧?
文章列表