JavaScript | 函式與方法
Reference : JavaScript教程 - 廖雪峰的官方網站
JavaScript函式基礎
定義函式
在JavaScript中,定義函式的方式如下:
function abs (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
定義函式abs(x)
:
-
function
關鍵字指明這是函式定義 -
abs
是函式名稱 -
(x)
括號內列出函式的引數,多個引數以,
分隔 -
{...}
之間的程式碼是函式體
沒有return
的函式返回undefined
由於JavaScript的函式也是一個物件,上述定義的abs(x)
函式實際上是一個函式物件,而函式名abs
可以視為指向該函式的變數。
因此,第二種定義函式的方式為:
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
在這種方式下,function(x) {...}
是一個匿名函式,它沒有函式名。但是,這個匿名函式被賦值給了變數abs
,所以,通過變數abs
即可呼叫該函式。
上述兩種定義完全等價,注意第二種方式按照完整語法需要在函式體末尾加一個;
,表示賦值語句結束。
呼叫函式
JavaScript的函式呼叫不規定傳入引數的數量,可以多,也可以少。如果呼叫abs()
,則函式內引數x
接收到undefined
,計算結果為null
。
為了避免引數為undefined
,可以進行引數檢查:
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
arguments關鍵字
JavaScript的函式內部可以使用arguments
關鍵字,它指向當前函式的呼叫者傳入的所有引數,包括多處的不需要的引數。
-
arguments.length
獲取引數個數 -
arguments[i]
通過下標索引引數 -
arguments
的操作類似Array
,但實際不是Array
arguments
最常見的用法是判斷傳入引數的個數,從而在函式體內進行適當的操作(如設定預設值)。例如以下求圓面積函式,當引數pi
不傳入時,預設為3.14。
function area_of_circle(r, pi) {
if (arguments.length == 0) {
return null;
} else if (arguments.length == 1) {
pi = 3.14;
}
return pi * r * r;
}
rest引數[ES6]
定義函式如下:
function foo (a, b, ...rest) {
// ...
}
則rest
引數以陣列的形式獲取arguments
從下標為2開始至結束的所有引數,此時arguments[0]
被傳給a
,arguments[1]
被傳給b
。
如果沒有多餘的引數,或者連指明的引數個數都不滿足,則rest
接收空陣列。
rest
引數可以用來定義引數長度可變的函式,例如下面的求和函式:
function sum(...rest) {
var i;
var res = 0;
for (i = 0; i < rest.length; i ++) {
res += rest[i];
}
return res;
}
深入學習:高階函式 - 廖雪峰的官方網站
深入學習2:箭頭函式 - 廖雪峰的官方網站
物件方法
在一個物件中繫結函式,稱為這個物件的方法。例如:
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年呼叫是25,明年呼叫就變成26了
在方法中,this
關鍵字指向當前物件。從更一般的意義講,函式體中的this
指向呼叫函式的物件(這是JavaScript的大坑,接下來將重點理解這一點)
this關鍵字
要點1:this
關鍵字的值動態地確定:
我們可以把方法寫在物件的外面
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25, 正常結果
getAge(); // NaN
單獨呼叫getAge()
返回NaN
,這是因為單獨呼叫的語句等價於window.getAge()
,此時this
指向呼叫者window
物件,因此結果是NaN
。
進一步地,如果以下面的形式呼叫:
var fn = xiaoming.age; // 拿到xiaoming物件的age函式控制程式碼
fn(); // NaN
結果依然是NaN
。所以想要保證this
指向正確,必須用obj.xxx()
的形式呼叫!
這是一個巨大的設計錯誤,為了修復它,ESMA決定在strict模式下讓函式的this
指向undefined
,因此,在strict模式下呼叫fn()
會得到錯誤:
Uncaught TypeError: Cannot read property 'birth' of undefined
但這個辦法治標不治本,this
還是沒有指向正確的位置。
更進一步,採用下面的方式定義方法:
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth;
}
return getAgeFromBirth();
}
};
xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
這樣this
物件依然無法指向xiaoming
物件。對於這種情況,解決的辦法很簡單:在方法的開頭獲取this
,如報錯在that
變數中,此時that
具有整個函式體的作用域,這樣在方法內定義的函式中,就可以用that
代替this
,而不會產生任何錯誤了。
apply
apply
是任何函式自帶的一個方法,使用它,我們可以控制函式體內this
的指向!我們可以靠它根本地解決上述的this
指向問題。
apply
有兩個引數,第一個引數是this
指向的物件,第二個引數是Array
類的物件,表示函式本身的引數。
回到上面的例子,我們用apply
來修復報錯:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 引數為空
call
與apply
類似的方法是call
,唯一的區別是:
-
apply
把引數打包成Array
再傳入; -
call
把引數按順序傳入。
比如呼叫Math.max(3, 5, 4)
,分別用apply
和call
實現如下:
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
對於普通函式呼叫,我們通常讓this
指向null
。
裝飾器
利用apply()
,我們還可以動態改變函式的行為。
JavaScript的所有物件都是動態的,即使內建的函式,我們也可以重新指向新的函式。例如:
現在假定我們想統計一下程式碼一共呼叫了多少次parseInt()
,可以把所有的呼叫都找出來,然後手動加上count += 1
,不過這樣做太傻了。最佳方案是用我們自己的函式替換掉預設的parseInt()
:
'use strict';
var count = 0;
var oldParseInt = parseInt; // 儲存原函式
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 呼叫原函式
};
// 測試:
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3
相關文章
- JavaScript方法和函式區別JavaScript函式
- JavaScript的迭代函式與迭代函式的實現JavaScript函式
- JavaScript:鉤子函式與回撥函式的區別JavaScript函式
- JavaScript 匿名函式與具名函式執行效率比較JavaScript函式
- TypeScript 中函式的理解?與 JavaScript 函式的區別?TypeScript函式JavaScript
- Scala 的方法與函式函式
- javascript 的函式宣告與表示式對比JavaScript函式
- JavaScript 變數與函式宣告前置JavaScript變數函式
- javaScript函式JavaScript函式
- scala語法 - 方法與函式函式
- 學習Scala 方法與函式函式
- javascript之變數提升與函式提升JavaScript變數函式
- javascript之函式防抖與節流JavaScript函式
- JavaScript 匿名函式JavaScript函式
- JavaScript function 函式JavaScriptFunction函式
- JavaScript睡眠函式JavaScript函式
- JavaScript Generator 函式JavaScript函式
- javascript函式(5)JavaScript函式
- 你不知道的JavaScript--Item8 函式,方法,建構函式呼叫JavaScript函式
- javascript-函式表示式JavaScript函式
- Javascript函式引數求值——Thunk函式JavaScript函式
- 5-函式與物件的方法函式物件
- JavaScript函式宣告和函式表示式區別JavaScript函式
- JavaScript中的compose函式和pipe函式JavaScript函式
- javascript常用函式大全JavaScript函式
- javascript函式全解JavaScript函式
- JavaScript裡的函式JavaScript函式
- JavaScript 回撥函式JavaScript函式
- JavaScript 建構函式JavaScript函式
- JavaScript 箭頭函式JavaScript函式
- JavaScript回撥函式JavaScript函式
- JavaScript 函式語法JavaScript函式
- javascript函式有哪些JavaScript函式
- Javascript 高階函式JavaScript函式
- C語言函式指標與回撥函式使用方法C語言函式指標
- [JavaScript]原型、原型鏈、建構函式與繼承JavaScript原型函式繼承
- 方法(函式)的定義與引數函式
- 【譯】JavaScript 工廠函式 vs 建構函式JavaScript函式