this
Bug
年年有,今年特別多
對於JavaScript
這麼靈活的語言來講,少了this
怎麼活!設計模式
function
this
對於沒有實例化的function,咱們稱之爲函數,即沒有用new關鍵字調用的函數,對它們來講,this一概指代全局。
上栗子瀏覽器
var position = "outer"; function test(){ position = "inner"; } console.log(this.position); // outer test(); console.log(this.position); // inner 緣由:內部未用var聲明發生「變量提高」,污染全局變量。
this
對於被實例化的function,咱們稱之爲構造函數,及使用new關鍵字調用的function,對於它們來講,this會被改變,指向實例。
上栗子函數
var name = 'person'; // 全局this賦上屬性name function Person(name){ this.name = name; this.say = function () { console.log('My name is '+this.name); } this.show = function () { console.log(this); } } var william = new Person('william'); //經過new關鍵字建立實例,改變函數內部this指向 console.log(this.name); //person william.say(); //My name is william william.show(); //Person {name: "william", say: ... 註解:經過這個栗子,咱們能夠看出,經過建立構造函數的實例,使得this的指向改變,指向了實例自己。
this
每個函數對象在建立的時候,都會自動添加一個prototype屬性,這個prototype實際上是一個指針,指向這個函數的原型對象。 你能夠經過prototype指針給這個函數對象的原型對象添加屬性,在實例化函數對象後,能夠經過this來訪問原型對象上的屬性。
上栗子this
function Person(){ console.log(this.name); } Person.prototype.name = "william"; //給原型對象上賦name屬性 var person = new Person(); // 經過this.name訪問原型對象上的屬性,打印 "william"
這還不夠,我們爲函數對象直接添加同名,而不在原型對象上添加prototype
function Person(){ this.name = "Jack"; console.log(this.name); } Person.prototype.name = "william"; var person = new Person(); // 打印 "Jack"
這裏有一個值得注意的地方:設計
當你
構造函數
中存在和原型對象
中同名
的屬性
或方法
時,原型對象中的屬性或方法會被隱藏
,你只會訪問到構造函數中的屬性或方法`指針
Object.create
this
經過Object.create建立函數對象實例,而不使用new關鍵字,也就是說它不會去調用構造函數
上栗子code
function Person(name){ this.name = name; this.showName = function () { console.log(this.name + ' in constructor'); } } //在構造函數中的屬性和方法,均同名 Person.prototype.name = "jack"; Person.prototype.showName = function () { console.log(this.name + ' in prototype'); }; //在原型對象中的屬性和方法,均同名 var william = new Person("william"); var jack = Object.create(Person.prototype); william.showName(); // william in constructor jack.showName(); // jack in prototype 註解: - 使用new關鍵字創造的實例調用了構造函數的屬性和方法 - 使用Object.create創造的實例調用了原型對象的屬性和方法
this
原型鏈用於實現繼承,當沒有找到須要屬性或方法時,會順着原型鏈向上繼續尋找。
上栗子對象
function Father(){ this.name = 'father'; } //能夠看作"父類" Father.prototype.showName = function () { console.log(this.name); }; function Son(){ this.name = 'son'; } //能夠看作"子類" Son.prototype = new Father(); //這步是關鍵! var mike = new Son(); mike.showName(); // son 註解: - 首先要強調的是JavaScript中沒有"父類","子類","繼承"這樣的東西,咱們只是經過原型鏈來實現這樣的設計模式。 - 經過這一步 Son.prototype = new Father(); 咱們將"子類"的prototype指針指向了"父類"函數對象
爲何這樣就能實現繼承呢? 首先要想明白爲何實例能訪問構造函數的原型對象 在JavaScript中,有一個內部的屬性,在火狐,谷歌瀏覽器中,將這個內部屬性暴露了出來,就是它 __proto__
上栗子(瀏覽器中)繼承
mike.__proto__ // Father {name: "father", showName: function} Son.prototype //Father {name: "father", showName: function} mike.__proto__ === Son.prototype // true 經過這個內部屬性,咱們能夠訪問到實例的構造函數的原型對象
再來一枚(瀏覽器中)
mike.__proto__.__proto__ //Father {showName: function} Father.prototype //Father {showName: function} mike.__proto__.__proto__ === Father.prototype // true 咱們如今經過__proto__訪問到了"父類"的原型對象! 繼承得以實現!
補充一句:
咱們能夠訪問到Son的name屬性的值,卻訪問不到Father的name屬性的值,是由於 - mike是Son的實例(實例能作什麼...?) - Father中的name沒有對外開放,能夠看作是私有屬性
主要探討了
- function
做爲函數、構造函數、原型對象時,this
的指代狀況
- 擴展了另外一種實例化方式Object.create
- 細說了原型鏈原理和實現,模擬了繼承的設計模式