摘要:在定義函數(shù)的作用域外調(diào)用,得到的返回仍然是函數(shù)創(chuàng)建時(shí)所在的作用域的局部變量。這是因?yàn)樗诘哪涿瘮?shù)的閉包中存放的是第一行的,而不是在循環(huán)中獲得的的當(dāng)前值。
原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Function.html
源代碼: https://github.com/RobinQu/Programing-In-Javascript/blob/master/chapters/JavaScript_Core/JavaScript_Basics/Function.md
本文存在批注,但該網(wǎng)站的Markdown編輯器不支持,所以無法正常展示,請到原文參考。
函數(shù)Javascript中,要記住函數(shù)是first-class citizen。
定義
函數(shù)聲明語句
function plus(x ,y) { }
函數(shù)定義表達(dá)式
var plus = function (x, y) { }函數(shù)調(diào)用
作為函數(shù)調(diào)用
function a(){}; a();
作為方法調(diào)用
a={}; a.x = function(){}; a.x();
通過call和apply間接調(diào)用函數(shù)(改變this)
call 和 apply帶有多個(gè)參數(shù),call和apply把當(dāng)前函數(shù)的this指向第一個(gè)參數(shù)給定的函數(shù)或?qū)ο笾?,并傳遞其余所有的參數(shù)作為當(dāng)前函數(shù)的參數(shù)。
var O = function () { this.foo = "hello"; this.hello = function () { return "world"; } }; var fn = function () { console.log("call", this); }; var o = new O(); fn.call(o);//此時(shí)fn的this指向o
call和apply的不同之處,在于call傳遞的參數(shù)是作為arguments依次傳入的,例如
fn.call(o, 1, 2, 3);
而apply傳遞的參數(shù)是以一個(gè)數(shù)組的方式傳入的,例如
fn.apply(o, [1, 2, 3]);
當(dāng)傳入?yún)?shù)少于函數(shù)聲明的參數(shù)時(shí),留空的參數(shù)的值是undefined。
Javascript允許傳入?yún)?shù)的個(gè)數(shù)大于聲明時(shí)制定的參數(shù)個(gè)數(shù)??梢杂?b>arguments來訪問這些參數(shù)
function f(){ var i; for( i = 0; i < arguments.length ; i++) { console.log(arguments[i]); } } f(1,2,3,4,5,6);
函數(shù)通過取得arguments的長度得到傳入?yún)?shù)的個(gè)數(shù),使用一個(gè)循環(huán)獲取每一個(gè)參數(shù)。
arguments還有兩個(gè)屬性,callee和caller
callee表示正在執(zhí)行的function對象,
caller表示調(diào)用當(dāng)前function的function
例如
function f(){ console.log(arguments.callee);//[Function: f] console.log(arguments.callee.caller);[Function: g] var i; for( i = 0; i < arguments.length ; i++) { console.log(arguments[i]); } } function g(){ f(1,2,3,4,5,6); } g();
callee 的重要用法之一是在匿名函數(shù)中實(shí)現(xiàn)遞歸
var result = function (x) { if (x <= 1) return 1; return x * arguments.callee(x - 1); }(3); console.log(result);
上例使用了一個(gè)匿名函數(shù)和callee實(shí)現(xiàn)了一個(gè)階乘。
作為值的函數(shù)javascript中的函數(shù)可以作為值來傳遞
function square(x) { return x * x; } var s = square; s(4);作為命名空間的函數(shù)
(function() { }());閉包
Javascript函數(shù)對象的內(nèi)部狀態(tài)不僅包含著函數(shù)的代碼邏輯,還引用當(dāng)前的作用域鏈。函數(shù)對象通過作用域鏈相互關(guān)聯(lián)起來,函數(shù)體內(nèi)部變量包含在函數(shù)作用域內(nèi),這就叫閉包。
例如
var scope = "global scope"; function checkscope() { var scope = "local scope"; function f() { return scope; } return f; } checkscope()();
這段checkscope聲明了一個(gè)局部變量,定義了一個(gè)函數(shù)f,函數(shù)f返回了這個(gè)局部變量的值,最后返回了這個(gè)函數(shù)f。在定義函數(shù)f的作用域外調(diào)用f,得到的返回仍然是函數(shù)f創(chuàng)建時(shí)所在的作用域的局部變量scope。
又例如
var counter = (function() { var count = 0; return function () { return count++ ; } }());
代碼定義了一個(gè)立即執(zhí)行函數(shù)并返回給counter,這個(gè)函數(shù)定義了一個(gè)局部變量count,返回了一個(gè)子函數(shù),該子函數(shù)每次調(diào)用,都會(huì)吧count加一并返回。
閉包的注意事項(xiàng)
觀察下面的示例:
var add_the_handlers = function (nodes) { var i; for (i = 0; i < nodes.length; i += 1) { nodes[i].onclick = function (e) { alert(i); }; } };
這個(gè)函數(shù)期望的結(jié)果,是在運(yùn)行的時(shí)候?yàn)槊總€(gè)node在onclick的時(shí)候alert出各自的序號(hào),但是實(shí)際運(yùn)行的結(jié)果卻不同:所有的node在單擊的時(shí)候alert出來的數(shù)字總是同一個(gè)。
這是因?yàn)閍lert所在的匿名函數(shù)的閉包中存放的i是第一行的i,而不是在循環(huán)中獲得的i的當(dāng)前值。
所以如果希望達(dá)到預(yù)期結(jié)果,應(yīng)該在循環(huán)中創(chuàng)建多個(gè)閉包,在閉包中存放當(dāng)前循環(huán)的i的值:
var add_the_handlers = function (nodes) { var i; for (i = 0; i < nodes.length; i += 1) { nodes[i].onclick = function (i) { return function(e){ alert(e); }; }(i); } };
這里使用一個(gè)立即執(zhí)行函數(shù)并傳遞當(dāng)前的i的值,返回一個(gè)新生成的函數(shù)。在這個(gè)新生成的函數(shù)的閉包中就保存了當(dāng)前的i的值。
函數(shù)中的this對象在一個(gè)對象中的this始終引用當(dāng)前對象,但是在函數(shù)中,特別是在閉包中,this有一些特殊的行為。
函數(shù)中的this對象始終綁定在函數(shù)運(yùn)行時(shí)的上下文環(huán)境上。所以在普通模式下調(diào)用一個(gè)全局函數(shù),this始終指向window(客戶端),在嚴(yán)格模式下調(diào)用一個(gè)全局函數(shù),this始終是undefined
示例
var name = "The Window"; var object = { name: "My Object", getNameFunc: function () { return function () { return this.name; }; }, getName : function () { return this.name; } }; console.log(object.getNameFunc()()); console.log(object.getName());
getNameFunction()返回了一個(gè)匿名函數(shù),這個(gè)匿名函數(shù)在調(diào)用的時(shí)候,上下文是window(瀏覽器中),所以在瀏覽器中輸出的是the Window
而getName()調(diào)用的時(shí)候上下文是object,所以成功輸出object的name
其實(shí)以上代碼中
object.getNameFunc()()
等效于
var fnc = object.getNameFunc();//這時(shí)候的fnc已經(jīng)脫離了object對象
fnc();
所以如果想要getNameFunction()正確返回Object的Name,需要在返回的匿名函數(shù)的閉包中保存在函數(shù)聲明時(shí)的this,
getNameFunc: function () { var that = this; return function () { return that.name; }; },
這樣就可以了。。
函數(shù)柯里化函數(shù)柯里化是指,把接受多個(gè)參數(shù)的函數(shù)轉(zhuǎn)換成接受一個(gè)單一參數(shù)的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。
示例
var add1 = add.curry(1); console.log(add1(2));
其中,add是接受兩個(gè)參數(shù)的函數(shù),add調(diào)用了curry返回一個(gè)只接受一個(gè)參數(shù)的新函數(shù),之后調(diào)用add1便等效于調(diào)用add(1, 2);
javascript并不原生支持curry,可以用prototype來模擬
Function.prototype.curry = function () { var slice = Array.prototype.slice, args = slice.apply(arguments), that = this; return function () { return that.apply(null, args.concat(slice.apply(arguments))); }; }; function add(n1, n2) { return n1 + n2; } var add1 = add.curry(1); console.log(add1(2));
curry創(chuàng)建了一個(gè)新函數(shù),在新函數(shù)的閉包中保存了原先傳遞的參數(shù)。
函數(shù)的屬性和方法length 函數(shù)的length表示函數(shù)實(shí)參的數(shù)量,是只讀的
prototype 指向一個(gè)該函數(shù)的原型對象的引用
toString 返回一個(gè)字符串
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/78111.html
摘要:基礎(chǔ)語法區(qū)分大小寫是一種區(qū)分大小寫的語法,意味著的關(guān)鍵字變量名函數(shù)名以及其他一切的字符表示都要使用一致的大小寫形式?;镎Z化物語空格和換行會(huì)忽略代碼中出現(xiàn)的空格換行制表符。如果不用花括號(hào)獨(dú)立獨(dú)立編寫一個(gè)語句,語法并不報(bào)錯(cuò),但不推薦。 JavaScript基礎(chǔ)語法 區(qū)分大小寫 JavaScript是一種區(qū)分大小寫的語法,意味著JavaScript的關(guān)鍵字、變量名、函數(shù)名以及其他一切的字符...
摘要:數(shù)組創(chuàng)建數(shù)組數(shù)組字面量使用構(gòu)造函數(shù)數(shù)組本質(zhì)上是所以要判斷是不是數(shù)組,需要通過判斷。數(shù)組長度使用屬性獲取元素的個(gè)數(shù)。例如函數(shù)的對象就是這樣 原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Array.html 源代碼: https://github.com/RobinQu/Programing-In-...
摘要:創(chuàng)建對象對象直接量構(gòu)造函數(shù)原型繼承類繼承對象擁有自有屬性和繼承屬性。遍歷順序是以廣度優(yōu)先遍歷所以使用便可以判斷是否是對象自有的屬性。可執(zhí)行對象通過如下方法可以創(chuàng)建一個(gè)可執(zhí)行對象既可以當(dāng)作對象來使用有原型鏈,也可以當(dāng)作函數(shù)來直接調(diào)用 原文: http://pij.robinqu.me/Javascript_Core/Javascript_Basics/Objects.html ...
摘要:多數(shù)運(yùn)算符都是由標(biāo)點(diǎn)符號(hào)表示,比如和。通常會(huì)根據(jù)需要對操作數(shù)進(jìn)行類型轉(zhuǎn)換左值是一個(gè)古老的屬于,它是指表達(dá)式只能出現(xiàn)在賦值運(yùn)算符的左側(cè)。也稱為嚴(yán)格相等運(yùn)算符,它用來檢測兩個(gè)操作數(shù)是否嚴(yán)格相等。運(yùn)算符的檢測規(guī)則是和運(yùn)算符的求反。 源代碼: https://github.com/RobinQu/Programing-In-Javascript/blob/master/chapters/...
摘要:瀏覽器只是實(shí)現(xiàn)的宿主環(huán)境之一,其他宿主環(huán)境包括和。年月,版發(fā)布,成為國際標(biāo)準(zhǔn)。事件定義了事件和事件處理的接口。對于已經(jīng)正式納入標(biāo)準(zhǔn)的來說,盡管各瀏覽器都實(shí)現(xiàn)了某些眾所周知的共同特性,但其他特性還是會(huì)因?yàn)g覽器而異。 JavaScript 是面向 Web 的編程語言,絕大多數(shù)現(xiàn)代網(wǎng)站都使用了 JavaScript,并且所有的現(xiàn)代 Web 瀏覽器(電腦,手機(jī),平板)均包含了 JavaScri...
閱讀 2447·2021-11-15 11:36
閱讀 1189·2019-08-30 15:56
閱讀 2252·2019-08-30 15:53
閱讀 1050·2019-08-30 15:44
閱讀 663·2019-08-30 14:13
閱讀 1005·2019-08-30 10:58
閱讀 485·2019-08-29 15:35
閱讀 1307·2019-08-29 13:58