1. 程式人生 > >Javascript原型及閉包

Javascript原型及閉包

傳遞 感想 有一種 第一個 type 構造 關系 16px 本質

一.函數與對象的愛恨情仇

一切皆為對象,但並不是所有的都是對象,其中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 都是函數

,因為要創造此類型對象要new一個出來,說明他們也是構造函數,形如function Object(){}和function 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原型及閉包