JavaScript 表單、物件、函式
JavaScript表單
javaScript 表單驗證
HTML 表單驗證可以通過 JavaScript 來完成。
資料驗證
典型的資料驗證有:
必需欄位是否有輸入?
使用者是否輸入了合法的資料?
在數字欄位是否輸入了文字?
HTML 約束驗證
HTML 輸入屬性
CSS 偽類選擇器
DOM 屬性和方法
約束驗證 HTML 輸入屬性
disabled 規定輸入的元素不可用
max 規定輸入元素的最大值
min 規定輸入元素的最小值
pattern 規定輸入元素值的模式
required 規定輸入元素欄位是必需的
type 規定輸入元素的型別
約束驗證 CSS 偽類選擇器
選擇器 描述
:disabled 選取屬性為 “disabled” 屬性的 input 元素
:invalid 選取無效的 input 元素
:optional 選擇沒有"required"屬性的 input 元素
:required 選擇有"required"屬性的 input 元素
:valid 選取有效值的 input 元素
JavaScript 表單驗證
驗證表單資料是否為空?
驗證輸入是否是一個正確的email地址?
驗證日期是否輸入正確?
驗證表單輸入內容是否為數字型?
JavaScript 驗證 API
1.獲取表單
獲取表單元素
以Document物件中forms屬性來獲取當前HTML頁面所有表單集合
以Document物件中表單的name屬性值來獲取表單元元素
<body>
<form action="#">
<input type="submit">
</form>
<form name="mylove" action="#">
<input type="submit">
</form>
<script>
console.log(document.forms);
// 獲取當前HTML頁面所有表單元素
console.log(document.mylove);
// document表單名稱-有些新瀏覽器是不支援
</script>
</body>
獲取表單元件元素
以HTMLFormElement物件的elements屬性來獲取表單元件的集合
<body>
<form action="#">
<input type="text" name="username">
<input type="submit">
</form>
<script>
var form = document.forms[0];
console.log(form.elements);
</script>
</body>
2.表單操作
文字內容的選擇
以HTMLElement物件和HTMLTextAreaElement物件中select()方法來獲取文字框所有文字框的內容
<body>
<form action="#">
<input type="text" id="username" value="請輸入你使用者名稱">
<!---->
<input type="submit">
<!--定義提交按鈕-->
</form>
<script>
var username = document.getElementById(username);
// 獲取ID屬性
username.addEventListener('focus',function(){
username.select();
})
username.addEventListener('select',function () {
console.log(username.selectionStart.username.selectionEnd);
var value = username.getAttribute('value');
var result = value.substring(username.selectionStart,username.selectionEnd);
console.log(result);
})
</script>
</body>
設定文字內容
在HTML5新增中setSelectionRange()方法,來獲取一個焦點文字框的文字內容
<body>
<form action="#">
<input type="text" id="username" value="請輸入你使用者名稱">
<!---->
<input type="submit">
<!--定義提交按鈕-->
</form>
<script>
var username = document.getElementById(username);
// 獲取ID屬性
username.addEventListener('focus',function(){
username.select();
})
username.addEventListener('select',function () {
console.log(username.selectionStart.username.selectionEnd);
var value = username.getAttribute('value');
var result = value.substring(username.selectionStart,username.selectionEnd);
console.log(result);
})
</script>
</body>
操作剪下板
以copy;cut,paste 來設定 操作剪下板的複製,剪下和貼上
<body>
<form action="#">
<input type="text" id="username" value="請輸入你使用者名稱">
<input type="text" id="username1">
<input type="submit">
</form>
<script>
var username = document.getElementById('username');
username.addEventListener('copy',function (event) {
var data = event.clipboardData || window.clipboardData;
console.log(data);
console.log('這是複製操作');
var value = username.value;
var result = value.substring(selectionStart,username.selectionEnd);
console.log(result);
data.setData('text',result);
});
username.addEventListener('cut',function () {
console.log('這是個剪下操作');
});
var username1 = document.getElementById('username1');
username1.addEventListener('paste',function (event) {
event.preventDefault();
var data = event.clipboardData || window.clipboardData;
var result = data.getData('text');
/*得到DataTransfer物件
* geData()方法-獲取資料內容*/
if (result === '使用者名稱') {
result ='***';
}
username1.value = result;
})
</script>
</body>
下拉選單的操作
是以select和option物件來建立病提供一些屬性和方法
<form action="#">
<select id="yx">
<option id="dj" value="dj">單機</option>
<option value="wy">網頁</option>
<option value="dy">端遊</option>
</select>
<select id="cyx1" multiple size="5">
<option value="dj">單機</option>
<option value="wy">網頁</option>
<option value="dy">端遊</option>
</select>
</form>
<script>
var yx = document.getElementById('yx');
// HTMLSelectElement物件
console.log(yx.length);
console.log(yx.options);
console.log(yx.selectedIndex);// 被選中<option>的索引值
// 屬性
var yx1 = document.getElementById('yx1');
// size屬性預設值是 0
console.log(yx1.size);
console.log(yx1.item(1));
yx1.remove(2);
var dj = document.getElementById('dj');
console.log(dj.index);
console.log(dj.selected);
console.log(dj.text);
console.log(dj.value);
</script>
3.表單驗證
以checkValidity()如元素值不存在驗證問題,會是true,如不是則返回false
以setCustomValidity(message)會為元素自定義個錯誤資訊,如果設定了,該元素未無效,並顯示
<body>
<form action="#">
<input type="text" id="username">
<input type="submit">
</form>
<script>
var username = document.getElementById('username');
username.addEventListener('blur',function () {
var value = username.value;
if (value === '' || value === undefined || vaiue === null) {
console.log('請輸入你使用者名稱');
}
});
</script>
</body>
4.表單提交
submit事件
以submit表示提交表單
<body>
<form action="#">
<input type="text" id="username">
<input type="submit">
</form>
<script>
var form = document.forms[0];
form.addEventListener('submit',function (event) {
console.log('該表單已被提交');
});
</script>
</body>
submit()方法
以submit表示提交表單,並用使用任意普通按鈕即可完成提交
<body>
<form action="#">
<input type="text" id="username">
<input id="qyc" type="button" value="提交">
</form>
<script>
var qyc = document.getElementById('qyc');
qyc.addEventListener('click',function () {
var form = document.forms[0];
form.submit();//提交表單
});
</script>
</body>
JavaScript物件
在 JavaScript 中,幾乎“所有事物”都是物件
- 布林是物件(如果用 new 關鍵詞定義)
- 數字是物件(如果用 new 關鍵詞定義)
- 字串是物件(如果用 new 關鍵詞定義)
- 日期永遠都是物件
- 算術永遠都是物件
- 正規表示式永遠都是物件
- 陣列永遠都是物件
- 函式永遠都是物件
- 物件永遠都是物件
所有 JavaScript 值,除了原始值,都是物件。
JavaScript原始值
原始值指的是沒有屬性或方法的值
原始資料型別指的是擁有原始值的資料
JavaScript定義了5種原始資料型別:
- string
- number
- boolean
- null
- undefined
原始值是一成不變的(它們是硬編碼的,因此不能改變)
假設 x = 3.14,您能夠改變 x 的值。但是您無法改變 3.14 的值
JavaScript物件是易變的
物件是易變的:它們通過引用來定址,而非值。
如果 person 是一個物件,下面的語句不會建立 person 的副本:
var x = person; // 這不會建立 person 的副本。
物件 x 並非 person 的副本。它就是 person。x 和 person 是同一個物件。
對 x 的任何改變都將改變 person,因為 x 和 person 是相同的物件。
var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"}
var x = person;
x.age = 10; // 這將同時改變 both x.age 和 person.age
注意:JavaScript變數不是易變的,只有JavaScript物件如此
JavaScript物件屬性
for…in
語句可以遍歷物件的屬性
for (variable in object) {
要執行的程式碼
}
var person = {fname:"Bill", lname:"Gates", age:62};
for (x in person) {
txt += person[x];
}
刪除屬性
// delete關鍵詞可以從物件中刪除屬性
var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};
delete person.age; // 或 delete person["age"];
// delete關鍵詞會同時刪除屬性的值和屬性本身
JavaScript物件原型
原型繼承
所有JavaScript物件都從原型繼承屬性和方法,例如:
日期物件繼承自Date.prototype
,陣列物件繼承自Array.prototype
,Person物件繼承自Person.protype
Object.prototype位於原型繼承鏈的頂端:
日期物件、陣列物件和 Person 物件都繼承自 Object.prototype
JavaScript prototype
屬性允許為物件構造器新增新屬性和新方法:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
// 新增新屬性
Person.prototype.nationality = "English";
// 新增新方法
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
JavaScript函式
函式定義
一般函式定義的形式有以下幾種:
- 函式宣告法
function factorial(x) {
if(x <= 1) return 1;
return x * factorial(x - 1);
}
注意:函式宣告語句”被提前”到指令碼的頂部,所以可以在定義之前的程式碼呼叫函式。
- 函式賦值法(可定義為匿名函式)
var square = function(x) { return x*x; }
注意:變數的宣告是可以提前的,但是給變數的賦值不會提前,所以這種方式的函式在定義之前無法呼叫。
- 函式定義後立即執行
var tensquared = (function(x) { return x*x; }(10));
注意: function左邊的左括號是必需的,因為如果不寫左括號,JavaScript直譯器會將關鍵字function解析為函式宣告語句。使用左括號後,JavaScript直譯器才會正確地將其解析為函式定義表示式。
- 巢狀函式
function hypotenuse(a, b) {
function square(x) { return x*x; }
return Math.sqrt( square(a) + square(b) );
}
注意:巢狀函式中,注意作用域的使用。
函式呼叫
有4種方式可以呼叫JavaScript函式:
- 作為函式
- 作為方法
- 作為建構函式
- 通過call()和apply()方法間接呼叫
作為函式呼叫
函式呼叫就是直接通過function物件來呼叫函式。
var probability = factorial(5) / factorial(13);
根據ECMAScript3和非嚴格的ECMAScript5的規定,函式呼叫的上下文(this的值)是全域性物件(window)。在ECMAScript 5的嚴格模式下,呼叫上下文是undefined。
作為方法呼叫
- 方法呼叫是通過物件的屬性來呼叫函式。
- 方法呼叫和函式呼叫最大的一個區別是:呼叫上下文。方法呼叫的上下文是呼叫它的物件,可以通過this關鍵字引用該物件。
- this是一個關鍵字,不是變數,也不是屬性名。JavaScript不允許給this賦值。
var calculator = {
operand1: 1,
operand2: 2,
add: function() {
this.result = this.operand1 + this.operand2;
}
};
calculator.add(); // 方法呼叫
calculator["add"](); // 另一種形式的方法呼叫
calculator.result; // 2,物件屬性新增成功
- 如果巢狀函式作為函式呼叫,則this值不是全域性物件就是undefined。
var o = {
m: function() {
var self = this;
console.log(this === o); // true
f(); // 作為函式呼叫
function f() {
console.log(this === o); // false
console.log(this === window); // true
}
}
}
- 如果巢狀函式作為方法呼叫,則this值指向呼叫它的物件。
var o = {};
function outer() {
var inner = function() {
console.log(this === o);
};
o.m = inner;
}
outer();
o.m(); // 輸出: true,作為方法呼叫
作為建構函式呼叫
- 如果函式或方法呼叫之前帶有關鍵字new,它就構成建構函式呼叫。
- 建構函式呼叫和普通的函式呼叫以及方法呼叫在實參處理、呼叫上下文和返回值方面都有不同。
- 建構函式呼叫會建立一個新的空物件,這個物件繼承自建構函式的prototype屬性。建構函式使用這個新建立的物件作為呼叫上下文,並可以使用this關鍵字引用這個新建立的物件。
var o = {
m: function() {
console.log(this === o);
}
};
o.m(); // true,方法呼叫
var s = new o.m(); // false,建構函式呼叫
間接呼叫
- JavaScript中的函式也是物件,函式物件也可以包含方法。其中的2個方法call()和apply()可以用來間接地呼叫函式。
- 兩個方法允許顯式指定呼叫所需的this值,也就是說,任何函式可以作為任何物件的方法來呼叫,哪怕這個函式不是那個物件的方法。
- 在ECMAScript3和非嚴格模式中,傳入的null和undefined都會被全域性物件代替,而其他原始值則會被相應的包裝物件所替代。
f.call(o);
f.apply(o);
函式的實參和形參
JavaScript中的函式定義並未指定函式形參的型別,函式呼叫也未對傳入的實參值做任何型別檢查。實際上,JavaScript函式呼叫甚至不檢查傳入形參的個數。函式對於未傳入的引數賦值為undefined,對於多餘的引數忽略。
可選形參
由於呼叫函式傳入的實參個數可以比形參個數少,所以函式應當對此有一個較好的適應性,給省略的引數賦一個合理的預設值。
function getPropertyNames(o, /* optional */ a) {
if (a === undefined) a = []; // 如果未定義,則使用新陣列
for (var property in o)
a.push(property);
return a;
}
var a = getPropertyNames(o); // 將o的屬性儲存到一個新陣列中
getPropertyNames(p, a); // 將p的屬性追加到陣列a中
其中第一個if判斷語句可簡寫為:
a = a || [];
實參物件(arguments)
- 實參物件是一個類陣列物件,可以通過數字下標訪問傳入函式的實參值,而不用非要通過形參名字來得到實參。
下面的函式可以接收任意數量的實參:
function max(/* ... */) {
var max = Number.NEGATIVE_INFINITY;
// 遍歷實參,查詢並記住最大值
for(var i = 0; i < arguments.length; i++)
if(arguments[i] > max) max = arguments[i];
return max;
}
- 在非嚴格模式下,實參物件的陣列元素是函式形參所對應實參的別名,可以通過實參物件修改實參的值。
- 在非嚴格模式下,arguments僅僅是一個識別符號,在嚴格模式中,它變成了一個保留字。嚴格模式中的函式無法使用arguments作為形參名或區域性變數名,也不能給arguments賦值。
function f(x) {
console.log(x); // 輸出實參的初始值
arguments[0] = null; // 修改實引數組元素同樣會修改x的值
console.log(x); // 輸出"null"
}
callee和caller屬性
- 除了陣列元素,實參物件還定義了callee和caller屬性。
- callee屬性指代當前正在執行的函式。caller指代呼叫當前正在執行的函式的函式。
在匿名函式中,可通過callee來遞迴地呼叫自身:
var factorial = function(x) {
if (x <= 1) return 1;
return x * arguments.callee(x-1);
}
將物件屬性用做實參
當一個函式包含超過3個形參時,對於程式設計師說,要記住呼叫函式中實參的正確順序比較困難。最好通過名/值對的形式來傳入引數,這樣引數的順序就無關緊要了。
function arraycopy(/* array */ from, /* array */ to, /* integer */ length) {
// 邏輯程式碼
}
// 使用物件當引數
function easycopy(args) {
arraycopy(args.from, args.to, args.length);
}
var a = [1,2,3,4], b = [];
easycopy({ from: a, to: b, length: 4});
實參型別校驗
JavaScript會在必要的時候進行型別轉換,如果期望的實參是一個字串,那麼實參值無論是原始值還是物件都可以很容易地轉換成字串。但是當期望的實參是一個陣列時,就無法對非陣列物件進行轉換了,所以有必要對實參進行校驗。
function flexisum(a) {
var total = 0;
for (var i=0; i < arguments.length; i++) {
var element = arguments[i], n;
if (element == null) continue; // 忽略null和undefined實參
if (isArray(element))
n = flexisum.apply(this, element); // 如果是陣列,遞迴計算累加和
else if (typeof element === "function")
n = Number(element()); // 如果是函式,呼叫它並做型別轉換
else
n = Number(element);
if (isNaN(n))
throw Error("flexisum(): can't convert" + element + " to number.");
total += n;
}
return total;
}
作為值的函式
在JavaScript中,函式不僅是一種語法,也是值,也就是說,可以將函式賦值給變數,儲存在物件的屬性或陣列的元素中,作為引數傳入另外一個函式等。
// 宣告一個函式
function square(x) { return x*x; }
var s = square; // 賦值給變數
s(4); // => 16
var o = { m: square }; // 賦值給物件
o.m(5); // => 25
var a = [square, 6]; // 賦值給陣列
a[0](a[1]); // => 36
自定義函式的屬性
函式是一種特殊的物件,所以可以為函式定義屬性以完成特殊的需求。
可以通過函式屬性實現”靜態”變數的需求。
// 由於函式宣告被提前了,因此可以在宣告之前賦值
uniqueInteger.counter = 0;
function uniqueInteger() {
return uniqueInteger.counter++;
}
var a = uniqueInteger(); // 0
a = uniqueInteger(); // 1
a = uniqueInteger(); // 2
作為名稱空間的函式
不在任何函式內宣告的變數是全域性變數,在整個JavaScript程式中都是可見的。基於這個原因,我們常常簡單地定義一個函式用做臨時的名稱空間,在這個名稱空間內定義的變數都不會汙染到全域性名稱空間。
function mymodule() {
// 這個模組所使用的所有變數都是區域性變數
// 而不會汙染全域性名稱空間
}
閉包
JavaScript也採用詞法作用域,也就是說,函式的執行依賴於變數作用域,這個作用域是在函式定義時決定的,而不是呼叫時決定的。為了實現這種詞法作用域,JavaScript函式物件的內部狀態不僅包含函式的程式碼邏輯,還包含函式定義時的作用域鏈。
函式體內部的變數都可以儲存在函式作用域內,看起來是函式將變數”包裹”起來了,這種特性稱為”閉包”。
var scope = "global scope";
function checkscope() {
var scope = "local scope";
// 定義時使用區域性變數
function f() { return scope; }
return f(); // 返回函式的呼叫結果
}
checkscope(); // => "local scope"
如果更改下checkscope定義,將返回值更改為函式定義,如下:
var scope = "global scope";
function checkscope() {
var scope = "local scope";
// 定義時使用區域性變數
function f() { return scope; }
return f; // 返回函式的定義
}
checkscope()(); // => "local scope"
雖然呼叫函式的作用域變了,但是函式的輸出結果依然不變,因為函式儲存了自己的作用域鏈。
通過閉包,可以實現一個更好的計數器類,將變數包裹起來:
function counter() {
var n = 0;
return {
count: function() { return n++; }
reset: function() { n = 0; }
};
}
var c = counter();
c.count(); // => 0
c.count(); // => 1
c.reset(); // => 0
函式屬性、方法和建構函式
length屬性
arguments.length表示傳入函式的實參的個數。函式的length屬性表示函式形參的個數,這個屬性是隻讀的。
可以通過這個屬性對函式的引數個數進行校驗:
function check(args) {
var actual = args.length;
var expected = args.callee.length; // 形參個數
if (actual != expected) {
throw Error("Expected " + expected + "args; got " + actual);
}
}
prototype屬性
這個屬性指向一個物件的引用,這個物件稱做”原型物件”。每一個函式都包含不同的原型物件。當將函式用做建構函式的時候,新建立的物件會從原型物件上繼承屬性。
call()和apply()方法
這2個方法屬於函式的方法屬性,在前面已經有介紹,不再重複介紹。
bind()方法
bind()是在ECMAScript5中新增的方法,這個方法的主要作用就是返回一個新的函式,這個函式將bind的物件作為呼叫上下文。
function f(y) { return this.x + y; }
var o = { x: 1 };
var g = f.bind(o); // bind返回一個函式
g(2); // =>1,以物件o作為呼叫上下文執行f(y)
可以通過如下程式碼來實現簡單的bind():
function bind(f, o) {
if (f.bind) return f.bind(o);
else return function() {
// 此處的arguments為呼叫bind返回函式時傳遞的引數
// 上例中為2(g(2))
return f.apply(o, arguments);
}
}
但ECMAScript5中的bind()方法不僅僅是將函式繫結至一個物件,它還能將實參也繫結至this,這種程式設計技術, 有時被稱為”柯里化“(currying)。參照下面的例子:
function f(y,z) { return this.x + y + z; };
var g = f.bind({x: 1}, 2); // 繫結this和y
g(3); // =>6,this.x繫結到1,y繫結到2,z繫結到3
下面的程式碼給出了更標準的bind()方法,將這個方法另存為Function.prototye.bind:
if( !Function.prototye.bind) {
Function.prototye.bind = function(o /*, args */) {
// 將this和arguments的值儲存在變數中
// 以便在後面巢狀的函式中使用
var self = this, boundArgs = arguments;
// bind()返回一個函式
return function() {
// 建立一個實參列表,儲存傳入的所有實參
var args = [], i;
for(i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]);
for(i = 0; i < arguments.length; i++) args.push(arguments[i]);
// 以繫結物件o作為上下文來呼叫函式self
// 並傳遞所有的實參args
return self.apply(o, args);
};
};
}
ECMAScript5定義的bind()方法有一些特性是上述程式碼無法模擬的:
- 真正的bind()方法返回的函式,length屬性是繫結函式的形參個數減去繫結的實參個數。
- 真正的bind()方法可以建立建構函式,如果bind()返回的函式用做建構函式,將忽略bind()傳入的this,但是實參會正常繫結。
- 由bind()方法返回的函式並不包含prototype屬性,如果返回函式用做建構函式,則建立的物件從原始的未繫結建構函式中繼承prototype,同時,使用instanceof運算子,繫結建構函式和未繫結建構函式並無兩樣。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return this.x + ',' + this.y;
};
var p = new Point(1, 2);
p.toString(); // '1,2'
var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// 以下這行程式碼在 polyfill 不支援,
// 在原生的bind方法執行沒問題:
//(譯註:polyfill的bind方法如果加上把bind的第一個引數,即新繫結的this執行Object()來包裝為物件,Object(null)則是{},那麼也可以支援)
// var YAxisPoint = Point.bind(null, 0/*x*/);
// 繫結函式的length屬性 = 形參個數 - 繫結實參個數
console.log(YAxisPoint.length); // =>1,(2-1)
// 繫結函式不包含prototype屬性
console.log(Point.prototype); // "Point { toString-function()}"
console.log(YAxisPoint.prototype); // undefined
// 繫結函式用做建構函式
// this指代新建立的物件
var axisPointA = new YAxisPoint();
console.log(axisPointA.toString()); // '0,undefined'
var axisPoint = new YAxisPoint(5);
console.log(axisPoint.toString()); // '0,5'
// 使用instanceof時,繫結建構函式和未繫結建構函式並無兩樣
console.log(axisPoint instanceof Point); // true
console.log(axisPoint instanceof YAxisPoint); // true
console.log(new Point(17, 42) instanceof YAxisPoint); // true
toString()方法
和所有的JavaScript物件一樣,函式也有toString()方法。實際上,大多數(非全部)的toString()方法的實現都返回函式的完整原始碼。內建函式往往返回一個類似”[native code]”的字串。
Function()建構函式
前面已經介紹,函式可以通過定義語句或直接量表示式來定義。函式還可以通過Function()建構函式來定義。
Function()建構函式可以傳入任意數量的實參,最後一個實參表示的是函式體。
Function()建構函式並不需要通過傳入實參以指定函式名。Function()會構造一個匿名函式。
var f = new Function("x", "y", "return x*y;");
// 這個定義與下面的函式定義等價
var f = function(x, y) { return x*y; }
Function()建構函式有以下幾個特點:
- Function()在執行時動態地建立並編譯函式。
- 每次呼叫Function()建構函式都會解析函式體,並建立新的函式物件。
- Function()建構函式建立的函式並不使用詞法作用域,函式體程式碼的編譯總是在頂層函式執行。
var scope = "global";
function constructFunction() {
var scope = "local";
return new Function("return scope"); // 無法捕獲區域性作用域
}
constructFunction()(); // => "global"
可呼叫物件(callable object)
可呼叫物件是一個物件,可以在函式呼叫表示式中呼叫這個物件。所有的函式都是可呼叫的,但並非所有的可呼叫物件都是函式。
- IE8之前的版本實現了客戶端方法(諸如window.alert()和Document.getElementsById()),使用了可呼叫的宿主物件,而不是內建函式物件。IE9將它們實現為真正的函式,因此此類可呼叫的物件越來越罕見。
- 另外一個常見的可呼叫物件是RegExp物件,但程式碼最好不要對可呼叫的RegExp物件有太多依賴,對RegExp執行typeof運算的結果並不統一,在有些瀏覽器中返回”function”,在有些返回”object”。
檢測一個物件是否是真正的函式物件:
function isFunction() {
return Object.prototye.toString.call(x) === "[object Function]";
}
函數語言程式設計
和Lisp、Haskell不同,JavaScript並非函數語言程式設計語言,但可以像操控物件一樣操控函式,也就是說,JavaScript中可以應用函數語言程式設計技術。
使用函式處理陣列
使用函數語言程式設計,簡潔地實現計算平均值、標準差:
// 首先定義2個函式物件
var sum = function(x,y) { return x+y; }
var square = function(x) { return x*x; }
// 使用函數語言程式設計計算平均數、標準差
var data = [1,1,3,5,5];
// 計算平均數
var mean = data.reduce(sum) / data.length;
// 計算標準差
var deviations = data.map(function(x) { return x-mean; });
var stddev = Math.sqrt(deviations.map(square).reduce(sum) / (data.length-1));
高階函式(higher-order function)
高階函式就是操作函式的函式,它接收一個或多個函式作為引數,並返回一個新函式。
function mapper(f) {
return function(a) { return a.map(f); } // 注意: 此處沒有對引數a進行陣列驗證
}
var increment = function(x) { return x+1; }
var incrementer = mapper(increment);
incrementer([1,2,3]); // => [2,3,4]
不完全函式(partial function)
不完全函式是一種函式變換技巧,即把一次完整的函式呼叫拆成多次函式呼叫,每次傳入的實參都是完整實參的一部分,每個拆分開的函式叫做不完全函式,每次函式呼叫叫做不完全呼叫(partial application)。
// 實現一個工具函式,將類陣列物件轉換為真正的陣列
function array(a, n) { return Array.prototye.slice.call(a, n || 0); }
// 將第1次呼叫的實參放在左側
function partialLeft(f /* , ... */ ) {
var args = arguments;
return function() {
var a = array(args, 1); // 獲取第1個引數之後所有的實參
a = a.concat(array(arguments));
return f.apply(this, a);
};
}
// 將第1次呼叫的實參放在右側
function partialRight(f /* , ... */ ) {
var args = arguments;
return function() {
var a = array(arguments);
a = a.concat(array(args, 1));
return f.apply(this, a);
};
}
// 將第1次呼叫實參中的undefined值替換成第2次呼叫的實參
function partial(f /* , ... */ ) {
var args = arguments;
return function() {
var a = array(args, 1);
var i = 0, j = 0;
for(; i < a.length; i++) {
if(a[i] === undefined) a[i] = arguments[j++];
}
a = a.concat(array(arguments, j));
return f.apply(this, a);
};
}
// 這個函式帶有3個引數
var f = function(x, y, z) { return x * (y - z); };
partialLeft(f, 2)(3, 4); // => -2 [2 * (3 - 4)]
partialRight(f, 2)(3, 4); // => 6; [3 * (4 -2)]
partial(f, undefined)(3, 4); // => -6; [3 * (2 - 4)]
相關文章
- JavaScript 函式引數解構物件JavaScript函式物件
- 對JavaScript中函式物件的理解JavaScript函式物件
- 《JavaScript物件導向精要》之二:函式JavaScript物件函式
- 《JavaScript物件導向精要》之四:建構函式和原型物件JavaScript物件函式原型
- 函式物件、物件、原型函式物件原型
- JavaScript碎片———函式閉包(模擬物件導向)JavaScript函式物件
- JavaScript建構函式,物件導向程式設計JavaScript函式物件程式設計
- javaScript函式JavaScript函式
- JavaScript物件導向之二(建構函式繼承)JavaScript物件函式繼承
- 爬蟲不得不學之 JavaScript 函式物件篇爬蟲JavaScript函式物件
- JavaScript進階知識點——函式和物件詳解JavaScript函式物件
- JavaScript 匿名函式JavaScript函式
- JavaScript function 函式JavaScriptFunction函式
- JavaScript睡眠函式JavaScript函式
- JavaScript Generator 函式JavaScript函式
- javascript函式(5)JavaScript函式
- javascript-函式表示式JavaScript函式
- Javascript函式引數求值——Thunk函式JavaScript函式
- js函式,arguments物件JS函式物件
- 函式物件、裝飾器、閉包函式函式物件
- [React]antd表單校驗函式寫法React函式
- JavaScript函式宣告和函式表示式區別JavaScript函式
- JavaScript中的compose函式和pipe函式JavaScript函式
- C++中函式指標與函式物件C++函式指標物件
- javascript常用函式大全JavaScript函式
- javascript函式全解JavaScript函式
- JavaScript裡的函式JavaScript函式
- JavaScript 回撥函式JavaScript函式
- JavaScript 建構函式JavaScript函式
- JavaScript | 函式與方法JavaScript函式
- JavaScript 箭頭函式JavaScript函式
- JavaScript回撥函式JavaScript函式
- JavaScript 函式語法JavaScript函式
- javascript函式有哪些JavaScript函式
- Javascript 高階函式JavaScript函式
- 前端筆記之JavaScript物件導向(一)Object&函式上下文&建構函式&原型鏈前端筆記JavaScript物件Object函式原型
- javascript變數物件函式呼叫棧作用域閉包等細解!JavaScript變數物件函式
- js的函式和物件JS函式物件