Javascript学习之函数(function)
http://www.cnblogs.com/royalroads/p/4418587.html
在JS中,Function(函數(shù))類型實際上是對象;每個函數(shù)都是Function類型的實例,而且都與其他引用類型一樣具有屬性和方法。由于函數(shù)是對象,因此函數(shù)名實際上也是一個指向函數(shù)對象的指針。
一 函數(shù)的聲明方式
//1.函數(shù)聲明方式function add(num1,num2){return num1+num2;}//2.函數(shù)表達式定義函數(shù)var add= function(num1,num2){ // 通過變量box即可引用函數(shù);return num1+num2;}; // 注意函數(shù)末尾有一個分號,就像聲明其他變量時一樣;var another = add; // 使用不帶圓括號的函數(shù)名是訪問函數(shù)指針;而非調(diào)用函數(shù);console.log(another(10,10)); //3.使用Function構(gòu)造函數(shù)var add = new Function('num1','num2','return num1+num2'); // 第三種方式不推薦,這種語法會導致解析兩次代碼(第一次解析常規(guī)JS代碼,第二次解析傳入構(gòu)造函數(shù)中的字符串),從而影響性能; // 可以通過這種語法來理解"函數(shù)是對象,函數(shù)名是指針"的概念;?
通常來說,在全局作用域內(nèi)聲明一個對象,只不過是對一個屬性賦值而已,比如上例中的add函數(shù),事實上只是為全局對象添加了一個屬性,屬性名為add,而屬性的值是一個對象,即function(x, y){return x+y;},理解這一點很重要,這條語句在語法上跟:
var str = "This is a string";?
并沒有什么區(qū)別。都是給全局對象動態(tài)的增加一個新的屬性,如此而已。
二 作為值的函數(shù)
// JS中的函數(shù)名本身就是變量,所以函數(shù)也可以作為值來使用; // 也就是說,不僅可以像傳參數(shù)一樣把一個函數(shù)傳遞給另一個函數(shù),而且可以將一個函數(shù)作為另一個函數(shù)的結(jié)果返回;function box(sumFunction,num){ // 無論第一個參數(shù)傳遞進來的是什么函數(shù),return sumFunction(num); // 它都會返回執(zhí)行第一參數(shù)后的結(jié)果;}function sum(num){return num+10;}// 傳遞函數(shù)到另一個函數(shù)里;// 要訪問函數(shù)的指針不執(zhí)行函數(shù)的話,須去掉函數(shù)名后的圓括號;var result = box(sum,10); // =>20;?
三、函數(shù)的內(nèi)部屬性
// 函數(shù)內(nèi)部有兩個特殊的對象:arguments和this;// 1.arguments:包含著傳入函數(shù)中的所有參數(shù),arguments并不是一個數(shù)組,只是與數(shù)組相似。除了擁有l(wèi)ength屬性,數(shù)組的所有屬性和方法都不具備。 // arguments這個對象還有一個名叫callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數(shù);function box(num){if(num<=1){return 1;}else{return num*arguments.callee(num-1); // 使用arguments.callee來執(zhí)行box本身;}}// 2.this:引用的是函數(shù)據(jù)以操作的對象,或者說函數(shù)調(diào)用語句所處的作用域; // 當在全局作用域調(diào)用函數(shù)時,this對象引用的就是window;window.color = "red";alert(this.color); // 打印全局的color;=>red;var box = {color:'blue',sayColor:function(){alert(this.color); // 打印局部的color;=>blue;}};四 函數(shù)屬性和方法
// JS中的函數(shù)是對象,因此函數(shù)也有屬性和方法;包含length和prototype;// length屬性:表示函數(shù)希望接收到命名參數(shù)的個數(shù);function box(name,age){alert(name+age);}alert(box.length); // 2s// prototype屬性:它是保存所有實例方法的真正所在,也就是原型; // prototype包含兩個方法:apply()和call(),每個函數(shù)都包含這兩個非繼承而來的方法; // 這兩個方法的用途都在特定的作用域中調(diào)用函數(shù),實際上等于設(shè)置函數(shù)體內(nèi)this對象的值;var color = 'red';var box = {color = 'blue';}function sayColor({alert(this.color);});sayColor(); // 作用域在window;sayColor.call(this); // 作用域在window;sayColor.call(window); // 作用域在window;sayColor.call(box); // 作用域在box,對象冒充;=>red; // 使用call(box)方法的時候,sayColor()方法的運行環(huán)境已經(jīng)變成了box對象里了; // 使用call()或apply()來擴充作用域的最大好處,就是對象不需要與方法發(fā)生任何耦合關(guān)系; // 耦合:相互關(guān)聯(lián)的意思,擴展和維護會發(fā)生連鎖反應(yīng); // 也就是說,box對象和sayColor()方法之間不會有多余的關(guān)聯(lián)操作,比如:box.sayColor = sayColor;function Animal(){ this.name = "Animal"; this.showName = function(){ alert(this.name); } } function Cat(){ this.name = "Cat"; } var animal = new Animal(); var cat = new Cat(); //通過call或apply方法,將原本屬于Animal對象的showName()方法交給對象cat來使用。 //輸入結(jié)果為"Cat" animal.showName.call(cat,","); //animal.showName.apply(cat,[]);函數(shù)返回值(return)
當一個函數(shù)被調(diào)用,通常會從函數(shù)的{開始執(zhí)行到}結(jié)束。如果想提前結(jié)束該函數(shù)的執(zhí)行可以使用return語句,此時,return語句后面的所有語句將永遠不會執(zhí)行。如:
function test(){alert("first");return;alert("second"); // 該語句永遠被不會執(zhí)行 } test(); // 一個函數(shù)總是會返回值,如果沒有使用return返回值,默認返回undefined。如: function test(){alert("first"); } alert(test()); // 輸出:undefined // 如果函數(shù)前使用new方式調(diào)用,且返回值不是一個對象,則返回this(新對象)。如: function test(){alert("first"); } var t = new test(); alert(typeof t); // 輸出:‘object' alert(t instanceof test); // 輸出:true異常(exception)
??? 異常是干擾程序正常流程的非正常事故(可能人為有意的)。當檢查出這樣的事故,應(yīng)當拋出異常。如:
function add(a, b){ // 定義一個加法函數(shù)// 如果傳遞的參數(shù)不是數(shù)字類型,則拋出一個異常信息if(typeof a != 'number' || typeof b != 'number'){throw {'name' : "typeError", // 屬性是自定義的,名字可以任意取'message': "add方法必須使用數(shù)字作為參數(shù)"};}return a + b; } (function(){// 捕獲add方法可能產(chǎn)生的異常try{add(10, "");} catch(e){ // 一個try語句只有一個catch語句,如果要處理多個異常,則通過異常的name屬性來區(qū)別// 判斷異常的類型if(e.name === "typeError"){alert(e.message);}} })();給類型添加方法
??? javascript中允許給基本類型添加方法。如:boolean、string、Number
??? 實例:在Function中添加一個method函數(shù),該函數(shù)為Function添加其他自定義的函數(shù)(避免使用prototype),然后利用method函數(shù)想Function中添加一個add函數(shù),最后測試add函數(shù)在Function中確實存在。該方法將func函數(shù)添加到Function中,以name命名。然后,返回Function的對象
遞歸調(diào)用(arguments.callee)
??? 遞歸調(diào)用就是自己調(diào)用自己。調(diào)用分為:直接調(diào)用和間接調(diào)用下面展示使用遞歸調(diào)用來計算指定值的斐波那契數(shù)列。
函數(shù)的作用域
作用域的概念在幾乎所有的主流語言中都有體現(xiàn),在JavaScript中,則有其特殊性:JavaScript中的變量作用域為函數(shù)體內(nèi)有效,而無塊作用域,我們在Java語言中,可以這樣定義for循環(huán)塊中的下標變量:
public void method(){ for(int i = 0; i < obj1.length; i++){ //do something here; } //此時的i為未定義 for(int i = 0; i < obj2.length; i++){ //do something else; } }而在JavaScript中:
function func(){ for(var i = 0; i < array.length; i++){ //do something here. } //此時i仍然有值,及I == array.length print(i);//i == array.length; }?
再看一個例子
// 在程序中,作用域控制著變量的可見性和生命周期。 var name = "default"; // 全局作用域 function getName(){var name = "getName"; // getName作用域下for(var i=0; i<2; i++){var inName = "inName";}alert(i + "," + inName); // 2,inName 注意:在js中沒有塊級作用域,及if、for、while中聲明的變量是放在塊所在的作用域下return name; } alert(getName()); // getName 注意:js存在函數(shù)作用域,所以在函數(shù)內(nèi)部定義的變量在外部是不可見的 alert(name); // default注意:在現(xiàn)代的很多語言中,推薦將變量盡可能的延遲聲明。如:java而在js中,卻不推薦這樣做,因為js不支持塊級作用域。推薦在函數(shù)的開始就將所有用到的變量進行聲明。
JavaScript的函數(shù)是在局部作用域內(nèi)運行的,在局部作用域內(nèi)運行的函數(shù)體可以訪問其外層的(可能是全局作用域)的變量和函數(shù)。JavaScript的作用域為詞法作用域,所謂詞法作用域是說,其作用域為在定義時(詞法分析時)就確定下來的,而并非在執(zhí)行時確定,如下例:
var str = "global"; function scopeTest(){ print(str); var str = "local"; print(str); } scopeTest();?
運行結(jié)果是什么呢?初學者很可能得出這樣的答案:
global
local
而正確的結(jié)果應(yīng)該是:
undefined
local
因為在函數(shù)scopeTest的定義中,預(yù)先訪問了未聲明的變量str,然后才對str變量進行初始化,所以第一個print(str)會返回undifined錯誤。那為什么函數(shù)這個時候不去訪問外部的str變量呢?這是因為,在詞法分析結(jié)束后,構(gòu)造作用域鏈的時候,會將函數(shù)內(nèi)定義的var變量放入該鏈,因此str在整個函數(shù)scopeTest內(nèi)都是可見的(從函數(shù)體的第一行到最后一行),由于str變量本身是未定義的,程序順序執(zhí)行,到第一行就會返回未定義,第二行為str賦值,所以第三行的print(str)將返回”local”。
函數(shù)上下文
在Java或者C/C++等語言中,方法(函數(shù))只能依附于對象而存在,不是獨立的。而在JavaScript中,函數(shù)也是一種對象,并非其他任何對象的一部分,理解這一點尤為重要,特別是對理解函數(shù)式的JavaScript非常有用,在函數(shù)式編程語言中,函數(shù)被認為是一等的。
函數(shù)的上下文是可以變化的,因此,函數(shù)內(nèi)的this也是可以變化的,函數(shù)可以作為一個對象的方法,也可以同時作為另一個對象的方法,總之,函數(shù)本身是獨立的。可以通過Function對象上的call或者apply函數(shù)來修改函數(shù)的上下文:
call和apply
call和apply通常用來修改函數(shù)的上下文,函數(shù)中的this指針將被替換為call或者apply的第一個參數(shù),我們不妨來看看JavaScript入門之對象與JSON中的例子:
?
//定義一個人,名字為jack var jack = { name : "jack", age : 26 } //定義另一個人,名字為abruzzi var abruzzi = { name : "abruzzi", age : 26 } //定義一個全局的函數(shù)對象 function printName(){ return this.name; } //設(shè)置printName的上下文為jack, 此時的this為jack print(printName.call(jack)); //設(shè)置printName的上下文為abruzzi,此時的this為abruzzi print(printName.call(abruzzi)); print(printName.apply(jack)); print(printName.apply(abruzzi));?
apply和call的區(qū)別
?
// 定一個對象,包含一個add方法,返回a、b的和 var Person = {'add' : function(a, b){return a + b;} }; // 顯示a、b的和 function showInfo(a, b){alert(this.add(a, b)); } // 通過apply方法改變showInfo方法的this指向 //showInfo(1, 3); // 對象不支持次對象 showInfo.apply(Person, [1, 3]); showInfo.call(Person, 1, 3); // 從上面可以看出,apply和call的區(qū)別是apply接受一個數(shù)組作為被調(diào)函數(shù)的參數(shù), // 而call是通過將被調(diào)函數(shù)的所有參數(shù)以逗號分隔的形式展開?
匿名函數(shù)和嵌套函數(shù)
在JavaScript可以聲明一個沒有名稱的函數(shù),稱為匿名函數(shù)(Anonymouse Function)。同時JavaScript還允許在函數(shù)內(nèi)部聲明函數(shù),稱為嵌套函數(shù)(Nested Function),嵌套函數(shù)的作用域為整個父函數(shù)。
在前面函數(shù)聲明的部分就看到了匿名函數(shù)和嵌套函數(shù)的一種用法,由于匿名函數(shù)沒有名稱,不會引入新的變量污染上下文環(huán)境,而且會帶來新的變量作用域,因此匿名函數(shù)常被用來防止全局環(huán)境污染。
JavaScript運行時中有一個特殊的全局環(huán)境(global object),這個對象上面存放全局的函數(shù)和變量,實際開發(fā)中經(jīng)常會使用若干第三方的庫或多個js文件,若不小心在全局對象引入重復的變量或函數(shù)聲明,則會造成代碼執(zhí)行混亂。例如先后引入兩個js文件,分別定義了自己的函數(shù)log作為內(nèi)部使用,則第二引入的函數(shù)會覆蓋第一個的定義且不會拋出任何錯誤,在后續(xù)的執(zhí)行中調(diào)用log函數(shù)可能會造成錯誤。這時候使用一個匿名函數(shù)將整個js內(nèi)的邏輯包裝起來,就可以避免這種錯誤,這種方法已經(jīng)被絕大多數(shù)開源js庫使用。
以上代碼就是一個簡單的示例,log函數(shù)的作用域被限制在這個匿名函數(shù)之內(nèi),而匿名函數(shù)則因為被外面一對小括號()包括起來,形成一個函數(shù)表達式,表達式的值是一個函數(shù),緊接著一對小括號表示立即執(zhí)行這個函數(shù),讓原有的代碼正常執(zhí)行一次。不過,這種方式聲明的函數(shù)、通過var聲明的變量等等都是內(nèi)部的,不能被任何匿名函數(shù)以外的代碼訪問到。如果你需要對外暴露一些函數(shù)作為接口的話有如下幾種方法:
var mylib = (function(global) { function log(msg) { console.log(msg); } log1 = log; // 法一:利用沒有var的變量聲明的默認行為,在log1成為全局變量(不推薦) global.log2 = log; // 法二:直接在全局對象上添加log2屬性,賦值為log函數(shù)(推薦) return { // 法三:通過匿名函數(shù)返回值得到一系列接口函數(shù)集合對象,賦值給全局變量mylib(推薦) log: log}; }(window));高階函數(shù)(High-order Function)
如果函數(shù)作為參數(shù)或返回值使用時,就稱為高階函數(shù),JavaScript中的函數(shù)都可以作為高階函數(shù)來使用,這也是第一類函數(shù)的特征。下面我們就分別分析一下這兩種使用方法。
function negative(n) { return -n; // 取n的相反值 } function square(n) { return n*n; // n的平方 } function process(nums, callback) { var result = []; for(var i = 0, length = nums.length; i < length; i++) { result[i] = callback(nums[i]); // 對數(shù)組nums中的所有元素傳遞給callback進行處理,將返回值作為結(jié)果保存 } return result; } var nums = [-3, -2, -1, 0, 1, 2, 3, 4]; var n_neg = process(nums, negative); // n_neg = [3, 2, 1, 0, -1, -2, -3, -4]; var n_square = process(nums, square); // n_square = [9, 4, 1, 0, 1, 4, 9, 16];以上代碼展示了把函數(shù)作為參數(shù)傳入另一個函數(shù)process調(diào)用的示例,在process函數(shù)的實現(xiàn)中,把callback作為一個黑盒子看待,負責把參數(shù)傳給它,然后獲取返回值,在調(diào)用之前并不清楚callback的具體實現(xiàn)。只有當執(zhí)行到20行和22行時,callback才被分別代表negative或square,分別對每個元素進行取相反值或平方值的操作。
?
function generator() { var i = 0; return function() { return i++; }; } var gen1 = generator(); // 得到一個自然數(shù)生成器 var gen2 = generator(); // 得到另一個自然數(shù)生成器 var r1 = gen1(); // r1 = 0 var r2 = gen1(); // r2 = 1 var r3 = gen2(); // r3 = 0 var r4 = gen2(); // r4 = 1上面的代碼展示了把函數(shù)作為返回值的示例,generator是一個自然數(shù)生成器函數(shù),返回值是一個自然數(shù)生成函數(shù)。每次調(diào)用generator時都會把一個匿名函數(shù)作為結(jié)果返回,這個匿名函數(shù)在被實際調(diào)用時依次返回每個自然數(shù)。在generator里的變量i在每次調(diào)用這個匿名函數(shù)時都會自增1,這其實就是一個閉包。下面我們來介紹一下閉包.
?
類構(gòu)造函數(shù)
JavaScript的函數(shù)同時作為類的構(gòu)造函數(shù),因此只要聲明一個函數(shù)就可以使用new關(guān)鍵字創(chuàng)建類的實例。
在一些面向?qū)ο蟮恼Z言,如Java、C++、PHP中,構(gòu)造函數(shù)是很常見的。在Javascript中構(gòu)造函數(shù)首先是一個普通的函數(shù),它可以使用new 操作符來調(diào)用,并生成一個特殊類型的對象。
function Benjamin(username, sex) {this.username = username;this.sex = sex; } var benjamin = new Benjamin("zuojj", "male"); //Outputs: Benjamin{sex: "male",username: "zuojj"} console.log(benjamin);正如我們所看到的,“Benjamin”構(gòu)造函數(shù)僅僅是接收傳遞過來的參數(shù),并把它們賦值給this對象。這是因為當構(gòu)造函數(shù)被new操作符調(diào)用時,構(gòu)造函數(shù)的this對象賦值為new操作返回的對象。
這意味著上面的代碼等同于:
上面的構(gòu)造函數(shù)比較特別,有返回語句,那么obj1~obj4分別指向什么對象呢?實際結(jié)果是這樣的:
obj1 = MyClass對象 obj2 = 'foo' obj3 = {} obj4 = {}?
具體原因這篇文章有解釋,本文不再贅述,由于帶返回值的構(gòu)造函數(shù)會產(chǎn)生奇怪的結(jié)果,因此不要在構(gòu)造函數(shù)中調(diào)用有返回值的返回語句(空return可以)。
為什么使用構(gòu)造函數(shù),有以下幾個方面的原因:
1.使用構(gòu)造函數(shù),意味著所有的這些對象,都可以使用相同的基本結(jié)構(gòu)創(chuàng)建
2.使用構(gòu)造函數(shù),意味著“benjamin”對象被明確的標記為“Benjamin”函數(shù)的實例
3.使用構(gòu)造函數(shù),意味著我們可以在原型上定義公共方法,供多個實例共享
function Benjamin(username, sex) {this.username = username;this.sex = sex; } Benjamin.prototype.getName = function() {return this.username; } var benjamin = new Benjamin("zuojj", "male"); var ben = new Benjamin("lemon", "female"); //Outputs: zuojj console.log(benjamin.getName()); //Outputs: lemon console.log(ben.getName());1.new 關(guān)鍵字
在實例化構(gòu)造函數(shù)的時候一定不要忘了使用new關(guān)鍵字,是否使用new關(guān)鍵字,對this對象的影響很大,不用new關(guān)鍵字的情況下,this對象會指向全局對象(window in browser and global in node)。因此定義構(gòu)造函數(shù)時,建議函數(shù)名稱首字母大寫。
2.如果被調(diào)用的函數(shù)沒有顯式的 return 表達式,則隱式的會返回 this 對象 – 也就是新創(chuàng)建的對象,否則將會影響返回的結(jié)果,但僅限于返回的是一個對象
我們需要注意的是:
a) new Bar() 返回的是新創(chuàng)建的對象,而不是數(shù)字的字面值 2。 因此 new Bar().constructor === Bar,但是如果返回的是數(shù)字對象,結(jié)果就不同了;
b) 這里得到的 new Test()是函數(shù)返回的對象,而不是通過new關(guān)鍵字新創(chuàng)建的對象,如下所示:
?
閉包
var myObject = {value : 0,increment : function(inc){this.value = typeof inc === 'number' ? inc : 1;},getValue : function(){return this.value;} }; myObject.increment(10); alert(myObject.value); alert(myObject.getValue()); // 上面使用字面常量方式定義了一個myObject對象。但是value變量可以被外部對象訪問 var myObject = function(){var value = 0;return {increment: function(inc){value += typeof inc === 'number' ? inc : 1;},getValue : function(){return value;}}; }(); myObject.increment(10); alert(myObject.value); // 不能被外部對象訪問 alert(myObject.getValue()); // 10 // 漸變body的背景色(黃色到白色) var fade = function(node){var level = 1;var step = function(){var hex = level.toString(16);node.style.backgroundColor = '#FFFF' + hex + hex;if(level < 15){level += 1;setTimeout(step, 500); // 如果level小于15,則內(nèi)部函數(shù)自我調(diào)用}};setTimeout(step, 1); // 調(diào)用內(nèi)部函數(shù) }; fade(document.body); // 下面是一個很糟糕的例子 <a href="#" name="test">點擊我...</a><br> // 點擊時顯示3 <a href="#" name="test">點擊我...</a><br> // 點擊時顯示3 <a href="#" name="test">點擊我...</a><br> // 點擊時顯示3 var add_the_handlers = function(nodes){var i;for(i = 0; i < nodes.length; i += 1) {nodes[i].onclick = function(e){ // 函數(shù)構(gòu)造時的:ialert(i);};} }; var objs = document.getElementsByName("test"); add_the_handlers(objs); // 造成上面的原因是:a標簽的事件函數(shù)綁定了變量i,則不是函數(shù)在構(gòu)造時的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(i); // 輸出的i是構(gòu)造函數(shù)傳遞進來的i,不是事件處理綁定的i。};}(i);} }; var objs = document.getElementsByName("test"); add_the_handlers(objs);?
回調(diào)
// data表示參數(shù),而call_function則表示回調(diào)函數(shù) function sendRequest(data, call_function){// setTimeout來模仿客戶端請求服務(wù)端中傳輸數(shù)據(jù)的時間。// 當3秒鐘后就調(diào)用回調(diào)函數(shù)(有客戶端實現(xiàn)回調(diào)函數(shù))setTimeout(function(){call_function(data); // 調(diào)用回調(diào)函數(shù)}, 3000); } // 測試sendRequest函數(shù) sendRequest("參數(shù)", function(context){alert("context=" + context); });?
模塊
模塊是一個提供接口而隱藏狀態(tài)和實現(xiàn)的函數(shù)或?qū)ο蟆?/span>
??? 一般形式:一個定義了私有變量和函數(shù)的函數(shù);利用閉包創(chuàng)建可以訪問私有變量和函數(shù)的特權(quán)函數(shù);最后返回這個特權(quán)函數(shù),或者把他們保存到一個可以被訪問到的地方。
注:模塊模式通常結(jié)合單例模式使用,JavaScript的單例模式就是用對象字面量方式創(chuàng)建的對象,對象的屬性值可以是數(shù)值或函數(shù),并且屬性值在該對象的生命周期中不會發(fā)生變化。
級聯(lián)(鏈式操作)
??? 對于一些不返回值的方法,我們返回this,而不是undefined,那么我們就可以啟動以級聯(lián)(鏈式)去操作該對象。如下:
套用
??? 所謂套用就是將函數(shù)與傳遞給它的參數(shù)相結(jié)合,產(chǎn)生一個新的函數(shù)。如:下面代碼中定義一個add()函數(shù),該函數(shù)能夠返回一個新的函數(shù),并把參數(shù)值傳遞給這個新函數(shù),從而實現(xiàn)連加操作。
?
記憶
??? 函數(shù)可以用對象去記住先前操作的結(jié)果,從而能避免無謂的運算。這種優(yōu)化被稱為記憶。
自更新函數(shù)(Self-update Function)
在很多語言中,函數(shù)一旦聲明過就不能再次聲明同名函數(shù),否則會產(chǎn)生語法錯誤,而在JavaScript中的函數(shù)不僅可以重復聲明,而且還可以自己更新自己。自己吃自己的妖怪來了!
使用函數(shù)
前面已經(jīng)提到,在JavaScript中,函數(shù)可以
◆ 被賦值給一個變量
?
//聲明一個函數(shù),接受兩個參數(shù),返回其和 function add(x, y){ return x + y; } var a = 0; a = add;//將函數(shù)賦值給一個變量 var b = a(2, 3);//調(diào)用這個新的函數(shù)a print(b);?
這段代碼會打印”5”,因為賦值之后,變量a引用函數(shù)add,也就是說,a的值是一個函數(shù)對象(一個可執(zhí)行代碼塊),因此可以使用a(2, 3)這樣的語句來進行求和操作。
◆ 被賦值為對象的屬性
事實上,這個例子與上個例子的本質(zhì)上是一樣的,第一個例子中的a變量,事實上是全局對象(如果在客戶端環(huán)境中,表示為window對象)的一個屬性。而第二個例子則為obj對象,由于我們很少直接的引用全局對象,就分開來描述。
◆ 作為參數(shù)被傳入別的函數(shù)
?
//高級打印函數(shù)的第二個版本 function adPrint2(str, handler){ print(handler(str)); } //將字符串轉(zhuǎn)換為大寫形式,并返回 function up(str){ return str.toUpperCase(); } //將字符串轉(zhuǎn)換為小寫形式,并返回 function low(str){ return str.toLowerCase(); } adPrint2("Hello, world", up); adPrint2("Hello, world", low);?
運行此片段,可以得到這樣的結(jié)果:
HELLO, WORLD
hello, world
應(yīng)該注意到,函數(shù)adPrint2的第二個參數(shù),事實上是一個函數(shù),將這個處理函數(shù)作為參數(shù)傳入,在adPrint2的內(nèi)部,仍然可以調(diào)用這個函數(shù),這個特點在很多地方都是有用的,特別是,當我們想要處理一些對象,但是又不確定以何種形式來處理,則完全可以將“處理方式”作為一個抽象的粒度來進行包裝(即函數(shù))。
◆ 作為函數(shù)的結(jié)果被返回
?
function currying(){ return function(){ print("curring"); } }?
函數(shù)currying返回一個匿名函數(shù),這個匿名函數(shù)會打印”curring”,簡單的調(diào)用currying()會得到下面的結(jié)果:
function (){print("curring");}
如果要調(diào)用currying返回的這個匿名函數(shù),需要這樣:
currying()();
第一個括號操作,表示調(diào)用currying本身,此時返回值為函數(shù),第二個括號操作符調(diào)用這個返回值,則會得到這樣的結(jié)果:
currying
2、函數(shù)的四種調(diào)用模式及this的初始化
第一種:方法調(diào)用模式
??? 以下事例證明通過方法調(diào)用模式調(diào)用時,this綁定到擁有該方法的對象。如:
第二種:函數(shù)調(diào)用模式
??? 以下事例證明通過函數(shù)調(diào)用模式調(diào)用時,this綁定到全局對象上。如:
第三種:構(gòu)造器調(diào)用模式
// 定義一個Person的構(gòu)造器,在調(diào)用時一定要用new調(diào)用 var Person = function(name){this.name = name; } // 添加一個方法到Person Person.prototype.getName = function(){return this.name; }; // 構(gòu)造一個Person對象 var person = new Person("zhangsan"); alert(person.getName()); // 調(diào)用getName獲取person對象中name屬性的值第四種:Apply調(diào)用模式
<script type="text/javascript">// 定一個累加方法。如sum(1,2,3,4...)// 該方法位于window執(zhí)行環(huán)境中。var displayName = function(){alert("sum的執(zhí)行環(huán)境: " + typeof(this));alert("Name: " + this.name); // 取出當前執(zhí)行環(huán)境中name屬性}// 定一個Person對象var Person = {name: "zhangsan"};displayName.apply(Person); </script>轉(zhuǎn)載于:https://www.cnblogs.com/dlgood/p/6560820.html
總結(jié)
以上是生活随笔為你收集整理的Javascript学习之函数(function)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringMVC搭建+实例
- 下一篇: 《Java技术》第二次作业计科1501赵