# 你所不知道的 JS 讀書筆記-03-入門-作為值的函式、this 識別字、原型 p.50 ~ p.57  ## 作為值的函式 一個函式應該被當作一個**運算式**(expression)。 ```javascript var foo = function() { // .. }; var x = function bar() { // .. }; ``` 第一個函式運算式是**匿名的**,第二個是**具名的**。兩者各有所好。 ### 即刻調用的函式運算式(IIFE) 載入程式碼的當下直接執行該程式。 ```javascript (function foo(){ console.log("Hello IIFE"); })(); /* 以上相當於下段程式碼 */ function foo() { console.log("Hello IIFE"); } foo(); ``` 外層的`(..)`避免`foo()`被視為一個普通的函式宣告,是 Javascript 的一種語法。後方結尾處的`()`實際執行前面所參考的函式運算式。 IIFE 會建立變數範疇,內部的變數宣告不會影響到外部的變數。 IIFE 也能`return`值。 ## 閉包(closure) 函式執行完畢之後,記住並持續存取一個函式範疇以及其變數的方式。 ```javascript function makeAdder(x) { function add(y) { return x + y } return add; } // 簡寫 var makeAdder = x => y => x + y ``` 呼叫外層`makeAdder()`時回傳的內層`add()`函式都能記住傳入`makeAdder()`的參數`x`是什麼值。 > 內層函式`add()`用到屬於外層的`x`,於是`add()`閉關包含了`x`。 ```javascript var plusOne = makeAdder(1); var plusTen = makeAdder(10); console.log(plusOne(3)); // 4 console.log(plusTen(3)); // 13 ``` 宣告`plusOne`呼叫`makeAdder(1)`時,取得內層`add()`一個參考,`add()`藉由`makeAdder()`知道參數`x`為 1 。 宣告`plusTen`呼叫`makeAdder(10)`時,取得內層`add()`一個參考,`add()`藉由`makeAdder()`知道參數`x`為 10 。 透過`console.log()`呼叫`plusOne(3)`時,`plusOne(3)`把 3 作為內層的參數`y`,使其與`x`(這裡為 1 )相加,故得 4。 透過`console.log()`呼叫`plusTen(3)`時,`plusOne(3)`把 3 作為內層的參數`y`,使其與`x`(這裡為 10 )相加,故得 13。 ## 模組(module) 閉包的常見用法,模組能隱蔽程式碼的實作細節,提供一個可從外部取用的公開 API。 ```javascript function User() { var username, password; function doLogin( user, pw ) { username = user; password = pw; // 進行其餘的登入作業 } var publicAPI = { login: doLogin }; return publicAPI; } var fred = User() // 建立一個宣告為 fred 的模組實體 fred.login( "fred", "123qwe" ) ``` fred 是一個獨立實體,有一整個新的範疇被建立,包括了`User()`外層範疇、他的變數`username`與`password`、內部範疇`doLogin()`,而且都無法從外部的世界存取。如果宣告 jenny 為`User()`也會建立一個與 fred 完全無關的獨立實體,有自己的範疇與上述內容。 > 內層函式`doLogin()`用到屬於外層的`username`與`password`,於是`doLogin()`閉關包含了`username`與`password`。 publicAPI 是一個物件,帶著`login`特性,對內層的`doLogin()`函式有一個參考。 ## this 識別字 如果一個函式內有一個`this`參考,這個`this`通常指向一個物件(不是參考函式本身),指向哪個物件取決於函式被呼叫的方法。 --- 1. 當`this`在函式內時,`this`為全域物件 ```javascript function foo() { console.log( this.bar ); } var bar = "global" foo(); // "global" ``` `foo()`將`this`設為全域物件,但在 strict 模式中會是`undefined`。 --- 2. 當`this`在函式內且在一個物件內被調用時,`this`為該物件 ```javascript function foo() { console.log( this.bar ); } var obj1 = { bar: "obj1", foo: foo }; obj1.foo() // "obj1" ``` `obj1.foo()`啟用`foo()`函式,位置在`obj1`物件內,所以指向的物件是`obj1`。 --- 3. 將物件以參數帶入函式時,`this`為該參數 ```javascript function foo() { console.log( this.bar ); } var obj2 = { bar: "obj1", }; foo.call(obj2) // "obj2" ``` 使用給定的`this`參數(與其他參數)來呼叫`foo`這個函數。指向的物件是`obj2`。 --- 4. 以 new 設立新的空物件並調用函式,`this`為該空物件 ```javascript function foo() { console.log( this.bar ); } var bar = "global" new foo(); // undefined ``` new foo() 把 this 指向一個全新的空物件。 > 原則:檢視目標函式被呼叫的方法,來判斷`this`的指向 ## 原型 當你參考一個物件上的某個特性,如果該特性不存在,Javascript 會自動使用該物件內部的原型參考,在另外類似的物件尋找該特性,作為後備機制。 ```javascript var foo = { a: 42 }; var bar = Object.create( foo ); bar.b = "hello world"; bar.b; // "hello world" bar.a; // 42 ``` `a`特性不存在於`bar`物件上,但`bar`的原型連結到`foo`,所以會自動在`foo`物件上找`a`。 ###### tags: `javascript` `你所不知道的JS`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up