Javascript原型及閉包
一.函數與對象的愛恨情仇
一切皆為對象,但並不是所有的都是對象,其中undefined, number, string, boolean)屬於簡單的值類型,不是對象。剩下的幾種情況——函數、數組、對象、null或者new一個對象,都是對象,他們都是引用類型。
1.對象是屬性的集合(important!!!!!)
對象裏面的一切都是屬性,只有屬性,沒有方法--方法也是一種屬性,因為它的屬性表示為鍵值對的形式。關於函數與數組對象定義屬性是以其他形式定義的。
反正一切(引用類型)是對象,對象是屬性的集合
2.對象都是函數創建的,函數也是對象,有一種雞生蛋蛋生雞的邏輯(別急後面會理清這種關系的)
---關於對象都是函數創建的如:
以上代碼的本質
而且 Object 和 Array 都是函數:
console.log(typeof (Object)); // function
console.log(typeof (Array)); // function
---函數也是對象,也是屬性的集合
每個函數都有一個prototype屬性(這就是為什麽函數是對象了,因為它裏面已經事先有一個屬性了,而對象又是屬性的集合,邏輯是不是很對!沒毛病!)指向該函數的原型對象(既然是對象,也是屬性的集合!!!),只要是對象就有一個__proto__ 屬性指向構造函數
3.關於對象:
i本人理解如果用構造函數的方法創造對象,形如就是先創建一個模型,其中Fn函數裏定義了很多屬性,既然Fn是函數,那麽Fn就有prototype屬性指向該函數的原型對象。該函數的原型對象你可以自己在裏面定義一些屬性,該函數的原型對象裏有一個constructor屬性指向該構造函數。如果你要想要繼承我這些屬性,可以通過new關鍵字,new出一個新的對象。
ii只要new出f1新對象了,那麽f1對象就會繼承函數裏的所有屬性,既然f1是對象,那麽就有__proto__屬性指向構造函數的原型即。
iii上文說過Object 和 Array 都是函數
iiii這裏先講一下new的機制為下面的原型鏈做下鋪墊。
(這裏我覺得new時,不僅把構造函數的原型對象賦給創造出來的對象,而且還繼承了構造函數裏定義的屬性)
iiiii這裏還有一個邏輯問題,關於前文說的對象都是函數創建的,函數也是對象,那麽函數是怎麽出來的,不可能是石頭裏蹦出來的吧!且看如下代碼:
4.原型及原型鏈就以圖解形式
每每看到這些圖,我都有一種殺人的沖動,沖動是魔鬼,理解了以後才會明白很多問題:
(這裏解釋一下構造函數,所謂構造函數就是用來new對象的函數。其實嚴格來說,所有的函數都可以new一個對象,但是有些函數的定義是為了new一個對象,而有些函數則不是。另外註意,構造函數的函數名第一個字母大寫(規則約定)例如:Object、Array、Function等)
function fn(){};
var test = new fn();
這裏new的機制就是把test.__proto__=fn.prototype,實現原型繼承。要想使用一個對象的屬性,首先在自身查找這個屬性,如果沒有找到就在原型鏈上查找,直到為空為止。
5.this的指向問題
i在函數中this到底取何值,是在函數真正被調用執行的時候確定的,函數定義的時候確定不了。
ii 構造函數情況241行中的this在沒有new時this指的是window,當new以後指向函數函數本身(也是對象)。
iii函數作為對象一個屬性時
1.如果函數作為對象的一個屬性時,並且作為對象的一個屬性被調用時,函數中的this指向該對象。
2.註意,如果fn函數不作為obj的一個屬性被調用,會是什麽結果呢?
iiii特殊情況
Javascript沒有塊(這裏的塊指的是{})級作用域的概念,javascript除了全局作用域之外,只有函數可以創建作用域。所以這裏的f()還是一個普通的函數,是在全局作用域下運行的。
二.作用域及閉包的問題
1.且看下面例題:
兩句話特別重要:1.變量聲明提前,但不會賦值2.函數聲明優與變量聲明
alert(a)
a();var a=3; function a(){
alert(10)
}
alert(a)
a=6;
a();
------------分割線------------------
alert(a)
a();var a=3;var a=function(){
alert(10)
}
alert(a)
a=6;
a();
第一題等價於:
第二題等價於:
2.尋找作用域問題
這裏取x的值時,就需要到另一個作用域中取,有人說過要到父作用域中取,其實有時候這種解釋會產生歧義,要到創建這個函數的那個作用域中取值——是“創建”,而不是“調用”。
上面描述的只是跨一步作用域去尋找。
如果跨了一步,還沒找到呢?——接著跨!——一直跨到全局作用域為止。要是在全局作用域中都沒有找到,那就是真的沒有了。
這個一步一步“跨”的路線,我們稱之為——作用域鏈。
我們拿文字總結一下取自由變量時的這個“作用域鏈”過程:(假設a是自由量)
第一步,現在當前作用域查找a,如果有則獲取並結束。如果沒有則繼續;
第二步,如果當前作用域是全局作用域,則證明a未定義,結束;否則繼續;
第三步,(不是全局作用域,那就是函數作用域)將創建該函數的作用域作為當前作用域;
第四步,跳轉到第一步。
3.閉包
只要知道應用的兩個情況就可以了:
第一:函數作為返回值
第二:函數作為參數傳遞
這裏也用到跨作用域了,在執行到11行時,尋找max在自己的作用域找不到時,就跨到全局作用域去找。
本文參考:http://www.cnblogs.com/wangfupeng1988/p/3977924.html
感想:本文是在2017年11月下旬面試總結下來的,個人感覺學知識,學技術,不能知其然,不知其所以然,不能抱著僥幸的心理。
Javascript原型及閉包