重新的標(biāo)題為:執(zhí)行功能()

重新的標(biāo)題為:執(zhí)行功能()

函數(shù)是代碼語句的容器,可以使用括號 () 運(yùn)算符調(diào)用。調(diào)用時可以在括號內(nèi)傳遞參數(shù),以便函數(shù)調(diào)用時函數(shù)中的語句可以訪問某些值。

在以下代碼中,我們使用 new 運(yùn)算符創(chuàng)建 addNumbers 函數(shù) objectone 的兩個版本,另一個版本使用更常見的文字模式。兩者都需要兩個參數(shù)。在每種情況下,我們都調(diào)用該函數(shù),并在括號中傳遞參數(shù) () 運(yùn)算符。

示例:sample76.html

 <script>  	var addNumbersA = new Function('num1', 'num2', 'return num1 + num2');  	console.log(addNumbersA(2, 2)); // Logs 4.  	// Could also be written the literal way, which is much more common. 	var addNumbersB = function (num1, num2) { return num1 + num2; };  	console.log(addNumbersB(2, 2)); // Logs 4.  </script>

函數(shù)可用于返回值、構(gòu)造對象或作為簡單運(yùn)行代碼的機(jī)制。 JavaScript 對函數(shù)有多種用途,但就其最基本的形式而言,函數(shù)只是可執(zhí)行語句的唯一范圍。


函數(shù)() 參數(shù)

Function() 構(gòu)造函數(shù)采用無限數(shù)量的參數(shù),但 Function() 構(gòu)造函數(shù)期望的最后一個參數(shù)是一個字符串,其中包含構(gòu)成函數(shù)體的語句。在最后一個之前傳遞給構(gòu)造函數(shù)的任何參數(shù)都可用于正在創(chuàng)建的函數(shù)。還可以以逗號分隔的字符串形式發(fā)送多個參數(shù)。

在下面的代碼中,我將 Function() 構(gòu)造函數(shù)的用法與實(shí)例化函數(shù)對象的更常見模式進(jìn)行了對比。

示例:sample77.html

 <script>  	var addFunction = new Function('num1', 'num2', 'return num1 + num2');  	/* Alternately, a single comma-separated string with arguments can be  	the first parameter of the constructor, with the function body following. */ 	var timesFunction = new Function('num1,num2', 'return num1 * num2');  	console.log(addFunction(2, 2), timesFunction(2, 2)); // Logs '4 4'  	// Versus the more common patterns for instantiating a function: 	var addFunction = function (num1, num2) { return num1 + num2; }; // Expression form. 	function addFunction(num1, num2) { return num1 + num2; } // Statement form.  </script>

不建議或通常不直接利用 Function() 構(gòu)造函數(shù),因?yàn)?JavaScript 將使用 eval() 來解析包含函數(shù)邏輯的字符串。許多人認(rèn)為 eval() 是不必要的開銷。如果使用它,則代碼設(shè)計中很可能存在缺陷。

使用 Function() 構(gòu)造函數(shù)而不使用 new 關(guān)鍵字與僅使用構(gòu)造函數(shù)創(chuàng)建函數(shù)對象具有相同的效果(new Function(‘x’,’return x’) 與 函數(shù)((‘x’,’返回x’))。

直接調(diào)用 Function() 構(gòu)造函數(shù)時不會創(chuàng)建閉包。


Function() 屬性和方法

函數(shù)對象具有以下屬性(不包括繼承的屬性和方法):

屬性(Function.prototype;):

  • 原型

函數(shù)對象實(shí)例屬性和方法

函數(shù)對象實(shí)例具有以下屬性和方法(不包括繼承的屬性和方法):

實(shí)例屬性 (var myFunction = function(x, y, z) {}; myFunction.length;):

  • 參數(shù)
  • 構(gòu)造函數(shù)
  • 長度

實(shí)例方法 (var myFunction = function(x, y, z) {}; myFunction.toString();):

  • apply()
  • call()
  • toString()

函數(shù)總是返回一個值

雖然可以創(chuàng)建一個函數(shù)來簡單地執(zhí)行代碼語句,但函數(shù)返回一個值也很常見。在以下示例中,我們從 sayHi 函數(shù)返回一個字符串。

示例:sample78.html

 <script>  	var sayHi = function () { 		return 'Hi'; 	};  	console.log(sayHi()); // Logs "Hi".  </script>

如果函數(shù)沒有指定返回值,則返回 undefined。在以下示例中,我們調(diào)用 yelp 函數(shù),該函數(shù)將字符串“yelp”記錄到控制臺,而不顯式返回值。

示例:sample79.html

 <script>  	var yelp = function () { 		console.log('I am yelping!'); 		// Functions return undefined even if we don't. 	}  	/* Logs true because a value is always returned, even if we don't specifically return one. */ 	console.log(yelp() === undefined);  </script>

這里要記住的概念是,即使您沒有顯式提供要返回的值,所有函數(shù)都會返回一個值。如果不指定返回值,則返回值為 undefined。


函數(shù)是一等公民(不僅僅是語法,還有值)

在 JavaScript 中,函數(shù)就是對象。這意味著函數(shù)可以存儲在變量、數(shù)組或?qū)ο笾小4送猓瘮?shù)可以傳遞給函數(shù)或從函數(shù)返回。函數(shù)具有屬性,因?yàn)樗且粋€對象。所有這些因素使得函數(shù)成為 JavaScript 中的一等公民。

示例:sample80.html

 <script>  	// Functions can be stored in variables (funcA), arrays (funcB), and objects (funcC). 	var funcA = function () { }; // Called like so: funcA() 	var funcB = [function () { } ]; // Called like so: funcB[0]() 	var funcC = { method: function () { } }; // too.method() or funcC['method']()  	// Functions can be sent to and sent back from functions. 	var funcD = function (func) { 		return func 	};  	var runFuncPassedToFuncD = funcD(function () { console.log('Hi'); });  	runFuncPassedToFuncD();  	// Functions are objects, which means they can have properties. 	var funcE = function () { }; 	funcE.answer = 'yup'; // Instance property. 	console.log(funcE.answer); // Logs 'yup'.  </script>

認(rèn)識到函數(shù)是一個對象,因此也是一個值,這一點(diǎn)至關(guān)重要。它可以像 JavaScript 中的任何其他表達(dá)式一樣傳遞或增強(qiáng)。


將參數(shù)傳遞給函數(shù)

參數(shù)是在調(diào)用函數(shù)時將值傳遞到函數(shù)作用域的工具。在下面的示例中,我們調(diào)用 addFunction()。由于我們已預(yù)定義它采用兩個參數(shù),因此在其范圍內(nèi)可以使用兩個附加值。

示例:sample81.html

 <script>  	var addFunction = function (number1, number2) { 		var sum = number1 + number2; 		return sum; 	}  	console.log(addFunction(3, 3)); // Logs 6.  </script>

與其他一些編程語言相比,在 JavaScript 中省略參數(shù)是完全合法的,即使函數(shù)已被定義為接受這些參數(shù)。缺少的參數(shù)僅被賦予值 undefined。當(dāng)然,如果省略參數(shù)值,該函數(shù)可能無法正常工作。

如果向函數(shù)傳遞意外參數(shù)(創(chuàng)建函數(shù)時未定義的參數(shù)),則不會發(fā)生錯誤。并且可以從 arguments 對象訪問這些參數(shù),該對象可用于所有函數(shù)。


this 和 arguments 值可用于所有函數(shù)

在所有函數(shù)的范圍和主體內(nèi),this 和 arguments 值可用。

arguments 對象是一個類似數(shù)組的對象,包含傳遞給函數(shù)的所有參數(shù)。在下面的代碼中,即使我們在定義函數(shù)時放棄指定參數(shù),我們也可以依賴傳遞給函數(shù)的 arguments 數(shù)組來訪問在調(diào)用時發(fā)送的參數(shù)。

示例:sample82.html

 <script>  	var add = function () { 		return arguments[0] + arguments[1]; 	};  	console.log(add(4, 4)); // Returns 8.  </script>

this 關(guān)鍵字,傳遞給所有函數(shù),是對包含該函數(shù)的對象的引用。正如您所期望的,對象中包含的作為屬性(方法)的函數(shù)可以使用 this 來獲取對父對象的引用。當(dāng)函數(shù)定義在全局作用域時,this 的值為全局對象。查看以下代碼并確保您了解 this 返回的內(nèi)容。

示例:sample83.html

 <script>  	var myObject1 = { 		name: 'myObject1', 		myMethod: function () { console.log(this); } 	};  	myObject1.myMethod(); // Logs 'myObject1'.  	var myObject2 = function () { console.log(this); };  	myObject2(); // Logs window.  </script>

arguments.callee 屬性

arguments 對象有一個名為 callee 的屬性,它是對當(dāng)前正在執(zhí)行的函數(shù)的引用。此屬性可用于從函數(shù)范圍內(nèi)引用該函數(shù) (arguments.callee)a 自引用。在下面的代碼中,我們使用此屬性來獲取對調(diào)用函數(shù)的引用。

示例:sample84.html

 <script>  	var foo = function foo() { 		console.log(arguments.callee); // Logs foo() 		// callee could be used to invoke recursively the foo function (arguments.callee()) 	} ();  </script>

當(dāng)需要遞歸調(diào)用函數(shù)時,這非常有用。


函數(shù)實(shí)例 length 屬性和 arguments.length

arguments 對象具有唯一的 length 屬性。雖然您可能認(rèn)為這個 length 屬性將為您提供已定義參數(shù)的數(shù)量,但它實(shí)際上提供了在調(diào)用期間發(fā)送到函數(shù)的參數(shù)數(shù)量。

示例:sample85.html

 <script>  	var myFunction = function (z, s, d) { 		return arguments.length; 	};  	console.log(myFunction()); // Logs 0 because no parameters were passed to the function.  </script>

使用所有 Function() 實(shí)例的 length 屬性,我們實(shí)際上可以獲取函數(shù)期望的參數(shù)總數(shù)。

示例:sample86.html

 <script>  	var myFunction = function (z, s, d, e, r, m, q) { 		return myFunction.length; 	};  	console.log(myFunction()); // Logs 7.  </script>

arguments.length 屬性在 JavaScript 1.4 中已棄用,但可以從函數(shù)對象的 length 屬性訪問發(fā)送到函數(shù)的參數(shù)數(shù)量。接下來,您可以通過利用 callee 屬性來首先獲取對正在調(diào)用的函數(shù)的引用 (arguments.callee.length) 來獲取長度值。


重新定義函數(shù)參數(shù)

函數(shù)參數(shù)可以直接在函數(shù)內(nèi)部重新定義,也可以使用 arguments 數(shù)組。看一下這段代碼:

示例:sample87.html

 <script>  	var foo = false; 	var bar = false;  	var myFunction = function (foo, bar) { 		arguments[0] = true; 		bar = true; 		console.log(arguments[0], bar); // Logs true true. 	}  	myFunction();  </script>

請注意,我可以使用 arguments 索引或直接為參數(shù)重新分配新值來重新定義 bar 參數(shù)的值。


在函數(shù)完成之前返回函數(shù)(取消函數(shù)執(zhí)行)

通過使用帶或不帶值的 return 關(guān)鍵字,可以在調(diào)用期間隨時取消函數(shù)。在下面的示例中,如果參數(shù)未定義或不是數(shù)字,我們將取消 add 函數(shù)。

示例:sample88.html

 <script>  	var add = function (x, y) { 		// If the parameters are not numbers, return error. 		if (typeof x !== 'number' || typeof y !== 'number') { return 'pass in numbers'; } 		return x + y; 	} 	console.log(add(3, 3)); // Logs 6. 	console.log(add('2', '2')); // Logs 'pass in numbers'.  </script>

這里要講的概念是,您可以在函數(shù)執(zhí)行過程中的任何時刻使用 return 關(guān)鍵字來取消函數(shù)的執(zhí)行。


定義函數(shù)(語句、表達(dá)式或構(gòu)造函數(shù))

函數(shù)可以用三種不同的方式定義:函數(shù)構(gòu)造函數(shù)、函數(shù)語句或函數(shù)表達(dá)式。在下面的示例中,我演示了每種變體。

示例:sample89.html

 <script>  	/* Function constructor: The last parameter is the function logic,  	everything before it is a parameter. */ 	var addConstructor = new Function('x', 'y', 'return x + y');  	// Function statement. 	function addStatement(x, y) { 		return x + y; 	}  	// Function expression. 	var addExpression = function (x, y) { 		return x + y; 	};  	console.log(addConstructor(2, 2), addStatement(2, 2), addExpression(2, 2)); // Logs '4 4 4'.  </script>

有人說函數(shù)還有第四種類型的定義,稱為“命名函數(shù)表達(dá)式”。命名函數(shù)表達(dá)式只是一個包含名稱的函數(shù)表達(dá)式(例如, var add = function add(x, y) {return x+y})。


調(diào)用函數(shù)(函數(shù)、方法、構(gòu)造函數(shù)或 call() 和 apply())

使用四種不同的場景或模式調(diào)用函數(shù)。

  • 作為函數(shù)
  • 作為一種方法
  • 作為構(gòu)造函數(shù)
  • 使用 apply() 或 call()

在下面的示例中,我們將檢查每種調(diào)用模式。

示例:sample90.html

 <script>  	// Function pattern. 	var myFunction = function () { return 'foo' }; 	console.log(myFunction()); // Logs 'foo'.  	// Method pattern. 	var myObject = { myFunction: function () { return 'bar'; } } 	console.log(myObject.myFunction()); // Logs 'bar'.  	// Constructor pattern. 	var Cody = function () { 		this.living = true; 		this.age = 33; 		this.gender = 'male'; 		this.getGender = function () { return this.gender; }; 	} 	var cody = new Cody(); // Invoke via the Cody constructor. 	console.log(cody); // Logs the cody object and properties.  	// apply() and call() pattern. 	var greet = { 		runGreet: function () { 			console.log(this.name, arguments[0], arguments[1]); 		} 	}  	var cody = { name: 'cody' }; 	var lisa = { name: 'lisa' };  	// Invoke the runGreet function as if it were inside of the cody object. 	greet.runGreet.call(cody, 'foo', 'bar'); // Logs 'cody foo bar'.  	// Invoke the runGreet function as if it were inside of the lisa object. 	greet.runGreet.apply(lisa, ['foo', 'bar']); // Logs 'lisa foo bar'.  	/* Notice the difference between call() and apply() in how parameters are sent to the function being invoked. */  </script>

確保您了解所有四種調(diào)用模式,因?yàn)槟鷮⒂龅降拇a可能包含其中任何一種。


匿名函數(shù)

匿名函數(shù)是沒有給出標(biāo)識符的函數(shù)。匿名函數(shù)主要用于將函數(shù)作為參數(shù)傳遞給另一個函數(shù)。

示例:sample91.html

 <script>  	// function(){console.log('hi');}; // Anonymous function, but no way to invoke it.  	// Create a function that can invoke our anonymous function. 	var sayHi = function (f) { 		f(); // Invoke the anonymous function. 	}  	// Pass an anonymous function as a parameter. 	sayHi(function () { console.log('hi'); }); // Logs 'hi'.  </script>

自調(diào)用函數(shù)表達(dá)式

函數(shù)表達(dá)式(實(shí)際上是除從 Function() 構(gòu)造函數(shù)創(chuàng)建的函數(shù)之外的任何函數(shù))可以在定義后使用括號運(yùn)算符立即調(diào)用。在以下示例中,我們創(chuàng)建 sayWord() 函數(shù)表達(dá)式,然后立即調(diào)用該函數(shù)。這被認(rèn)為是一個自調(diào)用函數(shù)。

示例:sample92.html

 <script>  	var sayWord = function () { console.log('Word 2 yo mo!'); } (); // Logs 'Word 2 yo mo!'  </script>

自調(diào)用匿名函數(shù)語句

可以創(chuàng)建自調(diào)用的匿名函數(shù)語句。這稱為自調(diào)用匿名函數(shù)。在下面的示例中,我們創(chuàng)建了幾個立即調(diào)用的匿名函數(shù)。

示例:sample93.html

 <script>  	// Most commonly used/seen in the wild. 	(function (msg) { 		console.log(msg); 	})('Hi');  	// Slightly different, but achieving the same thing: 	(function (msg) { 		console.log(msg) 	} ('Hi'));  	// The shortest possible solution. 	!function sayHi(msg) { console.log(msg); } ('Hi');  	// FYI, this does NOT work! 	// function sayHi() {console.log('hi');}();  </script>

根據(jù) ECMAScript 標(biāo)準(zhǔn),如果要立即調(diào)用函數(shù),則需要在函數(shù)兩邊加上括號(或?qū)⒑瘮?shù)轉(zhuǎn)換為表達(dá)式的任何內(nèi)容)。


函數(shù)可以嵌套

函數(shù)可以無限期地嵌套在其他函數(shù)中。在下面的代碼示例中,我們將 goo 函數(shù)封裝在 bar 函數(shù)內(nèi)部,該函數(shù)位于 foo 函數(shù)內(nèi)部。

示例:sample94.html

 <script>  	var foo = function () { 		var bar = function () { 			var goo = function () { 				console.log(this); // Logs reference to head window object. 			} (); 		} (); 	} ();  </script>

這里的簡單概念是函數(shù)可以嵌套,并且嵌套的深度沒有限制。

請記住,嵌套函數(shù)的 this 的值將是 JavaScript 1.5、ECMA-262 第 3 版中的頭對象(Web 瀏覽器中的 window 對象)。


將函數(shù)傳遞給函數(shù)以及從函數(shù)返回函數(shù)

如前所述,函數(shù)是 JavaScript 中的一等公民。由于函數(shù)是一個值,并且函數(shù)可以傳遞任何類型的值,因此函數(shù)可以傳遞給函數(shù)。接受和/或返回其他函數(shù)的函數(shù)有時稱為“高階函數(shù)”。

在下面的代碼中,我們將一個匿名函數(shù)傳遞給 foo 函數(shù),然后立即從 foo 函數(shù)返回。變量 bar 所指向的正是這個匿名函數(shù),因?yàn)?foo 接受并返回匿名函數(shù)。

示例:sample95.html

 <script>  	// Functions can be sent to, and sent back from, functions. 	var foo = function (f) { 		return f; 	}  	var bar = foo(function () { console.log('Hi'); });  	bar(); // Logs 'Hi'.  </script>

因此,當(dāng)調(diào)用 bar 時,它會調(diào)用傳遞給 foo() 函數(shù)的匿名函數(shù),然后從 foo() 函數(shù)傳回并從 bar 引用多變的。所有這些都是為了展示函數(shù)可以像任何其他值一樣傳遞的事實(shí)。


在定義函數(shù)語句之前調(diào)用函數(shù)語句(又名函數(shù)提升)

函數(shù)語句可以在執(zhí)行期間在其實(shí)際定義之前調(diào)用。這有點(diǎn)奇怪,但您應(yīng)該意識到這一點(diǎn),以便您可以利用它,或者至少知道當(dāng)您遇到它時會發(fā)生什么。在下面的示例中,我在定義 sayYo() 和 sum() 函數(shù)語句之前調(diào)用它們。

示例:sample96.html

 <script>  	// Example 1 	var speak = function () { 		sayYo(); // sayYo() has not been defined yet, but it can still be invoked, logs 'yo'. 		function sayYo() { console.log('Yo'); } 	} (); // Invoke  	// Example 2 	console.log(sum(2, 2)); // Invoke sum(), which is not defined yet, but can still be invoked. 	function sum(x, y) { return x + y; }  </script>

發(fā)生這種情況是因?yàn)樵诖a運(yùn)行之前,函數(shù)語句被解釋并添加到執(zhí)行堆棧/上下文中。確保您在使用函數(shù)語句時意識到這一點(diǎn)。

定義為函數(shù)表達(dá)式的函數(shù)不會被提升。僅提升函數(shù)語句。


函數(shù)可以調(diào)用自身(又名遞歸)

函數(shù)調(diào)用自身是完全合法的。事實(shí)上,這經(jīng)常被用在眾所周知的編碼模式中。在下面的代碼中,我們啟動 countDownFrom 函數(shù),然后該函數(shù)通過函數(shù)名稱 countDownFrom 調(diào)用自身。本質(zhì)上,這會創(chuàng)建一個從 5 倒數(shù)到 0 的循環(huán)。

示例:sample97.html

 <script>  	var countDownFrom = function countDownFrom(num) { 		console.log(num); 		num--; // Change the parameter value. 		if (num < 0) { return false; } // If num < 0 return function with no recursion. 		// Could have also done arguments.callee(num) if it was an anonymous function. 		countDownFrom(num); 	};  	countDownFrom(5); // Kick off the function, which logs separately 5, 4, 3, 2, 1, 0.  </script>

您應(yīng)該意識到,函數(shù)調(diào)用自身(也稱為遞歸)或重復(fù)執(zhí)行此操作是很自然的。


結(jié)論

函數(shù)是 JavaScript 最常用的方面之一,希望您現(xiàn)在對如何使用它們有了更好的了解。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊15 分享