在js中,函數本身屬於對象的一種,因此可以定義、賦值,作為對象的屬性或者成為其他函數的參數。函數名只是函數這個對象類的引用。
函數定義
一、3種函數定義方式
【1】函數聲明語句
使用function關鍵字,后跟一組參數以及函數體
function funcname([arg1 [,arg2 [...,argn]]]){ statement; }
【2】函數定義表達式
以表達式方式定義的函數,函數的名稱是可選的
var functionName = function([arg1 [,arg2 [...,argn]]]){ statement; } var functionName = function funcName([arg1 [,arg2 [...,argn]]]){ statement; }
匿名函數(anonymous function)也叫拉姆達函數,是function關鍵字后面沒有標識符的函數
通常而言,以表達式方式定義函數時都不需要名稱,這會讓定義它們的代碼更加緊湊。函數定義表達式特別適合用來定義那些只會使用一次的函數
var tensquared = (function(x) {return x*x;}(10)); //定義同時進行調用
而一個函數定義表達式包含名稱,函數的局部作用域將會包含一個綁定到函數對象的名稱。實際上,函數的名稱將成為函數內部的一個局部變量
var test = function fn(){ return fn; } console.log(test);//fn(){return fn;} console.log(test());//fn(){return fn;} console.log(test()());//fn(){return fn;}
個人理解,對於具名的函數表達式來說,函數名稱相當於函數對象的形參,只能在函數內部使用;而變量名稱相當於函數對象的實參,在函數內部和函數外部都可以使用
var test = function fn(){ return fn === test; } console.log(test());//true console.log(test === fn);//ReferenceError: fn is not defined
函數定義了一個非標准的name屬性,通過這個屬性可以訪問到給定函數指定的名字,這個屬性的值永遠等於跟在function關鍵字后面的標識符,匿名函數的name屬性為空
//IE11-瀏覽器無效,均輸出undefined //chrome在處理匿名函數的name屬性時有問題,會顯示函數表達式的名字 function fn(){}; console.log(fn.name);//'fn' var fn = function(){}; console.log(fn.name);//'',在chrome瀏覽器中會顯示'fn' var fn = function abc(){}; console.log(fn.name);//'abc'
【3】Function構造函數
Function構造函數接收任意數量的參數,但最后一個參數始終都被看成是函數體,而前面的參數則枚舉出了新函數的參數
var functionName = new Function(['arg1' [,'arg2' [...,'argn']]],'statement;');
[注意]Function構造函數無法指定函數名稱,它創建的是一個匿名函數。
從技術上講,這是一個函數表達式。但不推薦使用,因為這種語法會導致解析兩次代碼。第一次是解析常規javascript代碼,第二次解析傳入構造函數中的字符串,影響性能。
var sum = new Function('num1','num2','return num1 + num2'); //等價於 var sum = function(num1,num2){ return num1+num2; }
Function()構造函數創建的函數,其函數體的編譯總是會在全局作用域中執行。於是,Function()構造函數類似於在全局作用域中執行的eval()
var test = 0; function fn(){ var test = 1; return new Function('return test'); } console.log(fn()());//0
[注意]並不是所有的函數都可以成為構造函數
var o = new Math.min();//Uncaught TypeError: Math.min is not a constructor
二、函數聲明順序
函數聲明,相對於變量會優先加載。所以不用擔心函數聲明在調用前還是調用后。
調用函數時會先在本機活動對象中查詢,即當前js文件中查詢,如果沒有才會向上查詢,所以若在兩個js文件中定義相同函數名,這兩個js文件內部調用各自的函數,其他js文件中調用最后聲明的函數。
三、重復
變量的重復聲明是無用的,不會覆蓋之前同一作用域聲明的變量,但函數的重復聲明會覆蓋前面的聲明的同名函數或同名變量。
//變量的重復聲明無用 var a = 1; var a; console.log(a);//1
//覆蓋同名變量 var a; function a(){ console.log(1); } a();//1
//覆蓋同名函數 a();//2 function a(){ console.log(1); } function a(){ console.log(2); }
四、刪除
函數聲明語句創建的變量無法刪除,這一點和變量聲明一樣。
function foo(){ console.log(1); } delete foo;//false console.log(foo());//1
函數返回值
所有函數都有返回值,沒有return語句時,默認返回內容為undefined,和其他面向對象的編程語言一樣,return語句不會阻止finally子句的執行。
function testFinnally(){ try{ return 2; }catch(error){ return 1; }finally{ return 0; } } testFinnally();//0
如果函數調用時在前面加上了new前綴,且返回值不是一個對象,則返回this(該新對象)。
function fn(){ this.a = 2; return 1; } var test = new fn(); console.log(test);//{a:2} console.log(test.constructor);//fn(){this.a = 2;return 1;}
如果返回值是一個對象,則返回該對象。
function fn(){ this.a = 2; return {a:1}; } var test = new fn(); console.log(test);//{a:1} console.log(test.constructor);//Object() { [native code] }
函數調用
javascript一共有4種調用模式:函數調用模式、方法調用模式、構造器調用模式和間接調用模式。
【1】函數調用模式
當一個函數並非一個對象的屬性時,那么它就是被當做一個函數來調用的。對於普通的函數調用來說,函數的返回值就是調用表達式的值。
function add(x,y){ return x+y; } var sum = add(3,4); console.log(sum)//7
使用函數調用模式調用函數時,非嚴格模式下,this被綁定到全局對象;在嚴格模式下,this是undefined
function add(x,y){ console.log(this);//window } add();
function add(x,y){ 'use strict'; console.log(this);//undefined } add();//window
因此,’this’可以用來判斷當前是否是嚴格模式
var strict = (function(){return !this;}());
重寫
因為函數調用模式的函數中的this綁定到全局對象,所以會發生全局屬性被重寫的現象
var a = 0; function fn(){ this.a = 1; } fn(); console.log(this,this.a,a);//window 1 1
【2】方法調用模式
當一個函數被保存為對象的一個屬性時,我們稱它為一個方法。當一個方法被調用時,this被綁定到該對象。如果調用表達式包含一個提取屬性的動作,那么它就是被當做一個方法來調用。
var o = { m: function(){ console.log(1); } }; o.m();//1
方法可以使用this訪問自己所屬的對象,所以它能從對象中取值或對對象進行修改。this到對象的綁定發生在調用的時候。通過this可取得它們所屬對象的上下文的方法稱為公共方法。
var o = { a: 1, m: function(){ return this; }, n: function(){ this.a = 2; } }; console.log(o.m().a);//1 o.n(); console.log(o.m().a);//2
任何函數只要作為方法調用實際上都會傳入一個隱式的實參——這個實參是一個對象,方法調用的母體就是這個對象,通常來講,基於那個對象的方法可以執行多種操作,方法調用的語法已經很清晰地表明了函數將基於一個對象進行操作
rect.setSize(width,height); setRectSize(rect,width,height);
假設上面兩行代碼的功能完全一樣,它們都作用於一個假定的對象rect。可以看出,第一行的方法調用語法非常清晰地表明這個函數執行的載體是rect對象,函數中的所有操作都將基於這個對象
和變量不同,關鍵字this沒有作用域的限制,嵌套的函數不會從調用它的函數中繼承this。如果嵌套函數作為方法調用,其this的值指向調用它的對象。如果嵌套函數作為函數調用,其this值不是全局對象(非嚴格模式下)就是undefined(嚴格模式下)
var o = { m: function(){ function n(){ return this; } return n(); } } console.log(o.m());//window
var o = { m: function(){ function n(){ 'use strict'; return this; } return n(); } } console.log(o.m());//undefined
如果想訪問這個外部函數的this值,需要將this的值保存在一個變量里,這個變量和內部函數都同在一個作用域內。通常使用變量self或that來保存this
var o = { m: function(){ var self = this; console.log(this === o);//true function n(){ console.log(this === o);//false console.log(self === o);//true return self; } return n(); } } console.log(o.m() === o);//true
【3】構造函數調用模式
如果函數或者方法調用之前帶有關鍵字new,它就構成構造函數調用
function fn(){ this.a = 1; }; var obj = new fn(); console.log(obj.a);//1
如果構造函數調用在圓括號內包含一組實參列表,先計算這些實參表達式,然后傳入函數內
function fn(x){ this.a = x; }; var obj = new fn(2); console.log(obj.a);//2
如果構造函數沒有形參,javascript構造函數調用的語法是允許省略實參列表和圓括號的。凡是沒有形參的構造函數調用都可以省略圓括號
var o = new Object(); //等價於 var o = new Object;
[注意]盡管構造函數看起來像一個方法調用,它依然會使用這個新對象作為調用上下文。也就是說,在表達式new o.m()中,調用上下文並不是o
var o = { m: function(){ return this; } } var obj = new o.m(); console.log(obj,obj === o);//{} false console.log(obj.constructor === o.m);//true
構造函數通常不使用return關鍵字,它們通常初始化新對象,當構造函數的函數體執行完畢時,它會顯式返回。在這種情況下,構造函數調用表達式的計算結果就是這個新對象的值
function fn(){ this.a = 2; } var test = new fn(); console.log(test);//{a:2}
如果構造函數使用return語句但沒有指定返回值,或者返回一個原始值,那么這時將忽略返回值,同時使用這個新對象作為調用結果
function fn(){ this.a = 2; return; } var test = new fn(); console.log(test);//{a:2}
如果構造函數顯式地使用return語句返回一個對象,那么調用表達式的值就是這個對象
var obj = {a:1}; function fn(){ this.a = 2; return obj; } var test = new fn(); console.log(test);//{a:1}
【4】間接調用模式
javascript中函數也是對象,函數對象也可以包含方法。call()和apply()方法可以用來間接地調用函數。
這兩個方法都允許顯式指定調用所需的this值,也就是說,任何函數可以作為任何對象的方法來調用,哪怕這個函數不是那個對象的方法。兩個方法都可以指定調用的實參。call()方法使用它自有的實參列表作為函數的實參,apply()方法則要求以數組的形式傳入參數。
var obj = {}; function sum(x,y){ return x+y; } console.log(sum.call(obj,1,2));//3 console.log(sum.apply(obj,[1,2]));//3
函數參數
arguments
javascript中的函數定義並未指定函數形參的類型,函數調用也未對傳入的實參值做任何類型檢查。實際上,javascript函數調用甚至不檢查傳入形參的個數。
function add(x){ return x+1; } console.log(add(1));//2 console.log(add('1'));//'11' console.log(add());//NaN console.log(add(1,2));//2
同名形參
在非嚴格模式下,函數中可以出現同名形參,且只能訪問最后出現的該名稱的形參。
function add(x,x,x){ return x; } console.log(add(1,2,3));//3
而在嚴格模式下,出現同名形參會拋出語法錯誤
function add(x,x,x){ 'use strict'; return x; } console.log(add(1,2,3));//SyntaxError: Duplicate parameter name not allowed in this context
參數個數
當實參比函數聲明指定的形參個數要少,剩下的形參都將設置為undefined值
function add(x,y){ console.log(x,y);//1 undefined } add(1);
常常使用邏輯或運算符給省略的參數設置一個合理的默認值
function add(x,y){ y = y || 2; console.log(x,y);//1 2 } add(1);
[注意]實際上,使用y || 2是不嚴謹的,顯式地設置假值(undefined、null、false、0、-0、”、NaN)也會得到相同的結果。所以應該根據實際場景進行合理設置
當實參比形參個數要多時,剩下的實參沒有辦法直接獲得,需要使用即將提到的arguments對象
javascript中的參數在內部用一個數組表示。函數接收到的始終都是這個數組,而不關心數組中包含哪些參數。在函數體內可以通過arguments對象來訪問這個參數數組,從而獲取傳遞給函數的每一個參數。arguments對象並不是Array的實例,它是一個類數組對象,可以使用方括號語法訪問它的每一個元素
function add(x){ console.log(arguments[0],arguments[1],arguments[2])//1 2 3 return x+1; } add(1,2,3);
arguments對象的length屬性顯示實參的個數,函數的length屬性顯示形參的個數
function add(x,y){ console.log(arguments.length)//3 return x+1; } add(1,2,3); console.log(add.length);//2
形參只是提供便利,但不是必需的
function add(){ return arguments[0] + arguments[1]; } console.log(add(1,2));//3
對象參數
當一個函數包含超過3個形參時,要記住調用函數中實參的正確順序實在讓人頭疼
function arraycopy(/*array*/from,/*index*/form_start,/*array*/to,/*index*/to_start,/*integer*/length){ //todo }
通過名/值對的形式來傳入參數,這樣參數的順序就無關緊要了。定義函數的時候,傳入的實參都寫入一個單獨的對象之中,在調用的時候傳入一個對象,對象中的名/值對是真正需要的實參數據
function easycopy(args){
arraycopy(args.from,args.from_start || 0,args.to,args.to_start || 0, args.length); } var a = [1,2,3,4],b =[]; easycopy({from:a,to:b,length:4});
以函數為參數
函數本身是一個對象,因此可以將函數作為另一個函數的參數,進而實現函數回調,功能等同於c++中的函數指針。
function printf(str){ dom1.innerText += str.toString()+"\n"; //設置dom1顯示的文字。變量也可以自動調用其他js文件中的dom1變量。dom1會先在當前文件中查詢,然后向之前引用的js文件查詢,再向之后引用的js文件查詢 } function callfunction(myfunction,myargument){ //函數作為其他函數的參數 return myfunction(myargument); //調用回調函數 } callfunction(printf,"hello world");
同步
當形參與實參的個數相同時,arguments對象的值和對應形參的值保持同步
function test(num1,num2){ console.log(num1,arguments[0]);//1 1 arguments[0] = 2; console.log(num1,arguments[0]);//2 2 num1 = 10; console.log(num1,arguments[0]);//10 10 } test(1);
[注意]雖然命名參數和對應arguments對象的值相同,但並不是相同的命名空間。它們的命名空間是獨立的,但值是同步的
但在嚴格模式下,arguments對象的值和形參的值是獨立的
function test(num1,num2){ 'use strict'; console.log(num1,arguments[0]);//1 1 arguments[0] = 2; console.log(num1,arguments[0]);//1 2 num1 = 10; console.log(num1,arguments[0]);//10 2 } test(1);
當形參並沒有對應的實參時,arguments對象的值與形參的值並不對應
function test(num1,num2){ console.log(num1,arguments[0]);//undefined,undefined num1 = 10; arguments[0] = 5; console.log(num1,arguments[0]);//10,5 } test();
內部屬性
【callee】
arguments對象有一個名為callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數
下面是經典的階乘函數
function factorial(num){ if(num <=1){ return 1; }else{ return num* factorial(num-1); } } console.log(factorial(5));//120
但是,上面這個函數的執行與函數名緊緊耦合在了一起,可以使用arguments.callee可以消除函數解耦
function factorial(num){ if(num <=1){ return 1; }else{ return num* arguments.callee(num-1); } } console.log(factorial(5));//120
但在嚴格模式下,訪問這個屬性會拋出TypeError錯誤
function factorial(num){ 'use strict'; if(num <=1){ return 1; }else{ return num* arguments.callee(num-1); } } //TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them console.log(factorial(5));
這時,可以使用具名的函數表達式
var factorial = function fn(num){ if(num <=1){ return 1; }else{ return num*fn(num-1); } }; console.log(factorial(5));//120
【caller】
實際上有兩個caller屬性
【1】函數的caller
函數的caller屬性保存着調用當前函數的函數的引用,如果是在全局作用域中調用當前函數,它的值是null
function outer(){ inner(); } function inner(){ console.log(inner.caller);//outer(){inner();} } outer();
function inner(){ console.log(inner.caller);//null } inner();
在嚴格模式下,訪問這個屬性會拋出TypeError錯誤
function inner(){ 'use strict'; //TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context console.log(inner.caller); } inner();
【2】arguments對象的caller
該屬性始終是undefined,定義這個屬性是為了分清arguments.caller和函數的caller屬性
function inner(x){ console.log(arguments.caller);//undefined } inner(1);
同樣地,在嚴格模式下,訪問這個屬性會拋出TypeError錯誤
function inner(x){ 'use strict'; //TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context console.log(arguments.caller); } inner(1);
函數重載
javascript函數不能像傳統意義上那樣實現重載。而在其他語言中,可以為一個函數編寫兩個定義,只要這兩個定義的簽名(接受的參數的類型和數量)不同即可
javascript函數沒有簽名,因為其參數是由包含0或多個值的數組來表示的。而沒有函數簽名,真正的重載是不可能做到的
//后面的聲明覆蓋了前面的聲明 function addSomeNumber(num){ return num + 100; } function addSomeNumber(num){ return num + 200; } var result = addSomeNumber(100);//300
只能通過檢查傳入函數中參數的類型和數量並作出不同的反應,來模仿方法的重載
function doAdd(){ if(arguments.length == 1){ alert(arguments[0] + 10); }else if(arguments.length == 2){ alert(arguments[0] + arguments[1]); } } doAdd(10);//20 doAdd(30,20);//50
參數傳遞
javascript中所有函數的參數都是按值傳遞的。也就是說,把函數外部的值復制到函數內部的參數,就和把值從一個變量復制到另一個變量一樣
【1】基本類型值
在向參數傳遞基本類型的值時,被傳遞的值會被復制給一個局部變量(命名參數或arguments對象的一個元素)
function addTen(num){ num += 10; return num; } var count = 20; var result = addTen(count); console.log(count);//20,沒有變化 console.log(result);//30
【2】引用類型值
在向參數傳遞引用類型的值時,會把這個值在內存中的地址復制給一個局部變量,因此這個局部變量的變化會反映在函數的外部
function setName(obj){ obj.name = 'test'; } var person = new Object(); setName(person); console.log(person.name);//'test'
當在函數內部重寫引用類型的形參時,這個變量引用的就是一個局部對象了。而這個局部對象會在函數執行完畢后立即被銷毀
function setName(obj){ obj.name = 'test'; console.log(person.name);//'test' obj = new Object(); obj.name = 'white'; console.log(person.name);//'test' } var person = new Object(); setName(person);
函數屬性
【length屬性】
arguments對象的length屬性表示實參個數,而函數的length屬性則表示形參個數
function add(x,y){ console.log(arguments.length)//3 console.log(add.length);//2 } add(1,2,3);
【name屬性】
函數定義了一個非標准的name屬性,通過這個屬性可以訪問到給定函數指定的名字,這個屬性的值永遠等於跟在function關鍵字后面的標識符,匿名函數的name屬性為空
//IE11-瀏覽器無效,均輸出undefined //chrome在處理匿名函數的name屬性時有問題,會顯示函數表達式的名字 function fn(){}; console.log(fn.name);//'fn' var fn = function(){}; console.log(fn.name);//'',在chrome瀏覽器中會顯示'fn' var fn = function abc(){}; console.log(fn.name);//'abc'
[注意]name屬性早就被瀏覽器廣泛支持,但是直到ES6才將其寫入了標准
ES6對這個屬性的行為做出了一些修改。如果將一個匿名函數賦值給一個變量,ES5的name屬性,會返回空字符串,而ES6的name屬性會返回實際的函數名
var func1 = function () {}; func1.name //ES5: "" func1.name //ES6: "func1"
如果將一個具名函數賦值給一個變量,則ES5和ES6的name屬性都返回這個具名函數原本的名字
var bar = function baz() {}; bar.name //ES5: "baz" bar.name //ES6: "baz"
Function構造函數返回的函數實例,name屬性的值為“anonymous”
(new Function).name // "anonymous"
bind返回的函數,name屬性值會加上“bound ”前綴
function foo() {}; foo.bind({}).name // "bound foo" (function(){}).bind({}).name // "bound "
【prototype屬性】
每一個函數都有一個prototype屬性,這個屬性指向一個對象的引用,這個對象稱做原型對象(prototype object)。每一個函數都包含不同的原型對象。將函數用做構造函數時,新創建的對象會從原型對象上繼承屬性
function fn(){}; var obj = new fn; fn.prototype.a = 1; console.log(obj.a);//1
函數方法
【apply()和call()】
每個函數都包含兩個非繼承而來的方法:apply()和call()。這兩個方法的用途都是在特定的作用域中調用函數,實際上等於函數體內this對象的值
要想以對象o的方法來調用函數f(),可以這樣使用call()和apply()
f.call(o); f.apply(o);
假設o中不存在m方法,則等價於:
o.m = f; //將f存儲為o的臨時方法 o.m(); //調用它,不傳入參數 delete o.m; //將臨時方法刪除
下面是一個實際的例子
window.color = "red"; var o = {color: "blue"}; function sayColor(){ console.log(this.color); } sayColor(); //red sayColor.call(this); //red sayColor.call(window); //red sayColor.call(o); //blue
//sayColor.call(o)等價於: o.sayColor = sayColor; o.sayColor(); //blue delete o.sayColor;
apply()方法接收兩個參數:一個是在其中運行函數的作用域(或者可以說成是要調用函數的母對象,它是調用上下文,在函數體內通過this來獲得對它的引用),另一個是參數數組。其中,第二個參數可以是Array的實例,也可以是arguments對象
function sum(num1, num2){ return num1 + num2; } //因為運行函數的作用域是全局作用域,所以this代表的是window對象 function callSum1(num1, num2){ return sum.apply(this, arguments); } function callSum2(num1, num2){ return sum.apply(this, [num1, num2]); } console.log(callSum1(10,10));//20 console.log(callSum2(10,10));//20
call()方法與apply()方法的作用相同,它們的區別僅僅在於接收參數的方式不同。對於call()方法而言,第一個參數是this值沒有變化,變化的是其余參數都直接傳遞給函數。換句話說,在使用call()方法時,傳遞給函數的參數必須逐個列舉出來
function sum(num1, num2){ return num1 + num2; } function callSum(num1, num2){ return sum.call(this, num1, num2); } console.log(callSum(10,10)); //20
至於是使用apply()還是call(),完全取決於采取哪種函數傳遞參數的方式最方便。如果打算直接傳入arguments對象,或者包含函數中先接收到的也是一個數組,那么使用apply()肯定更方便;否則,選擇call()可能更合適
在非嚴格模式下,使用函數的call()或apply()方法時,null或undefined值會被轉換為全局對象。而在嚴格模式下,函數的this值始終是指定的值
var color = 'red'; function displayColor(){ console.log(this.color); } displayColor.call(null);//red
var color = 'red'; function displayColor(){ 'use strict'; console.log(this.color); } displayColor.call(null);//TypeError: Cannot read property 'color' of null
應用
【1】調用對象的原生方法
var obj = {}; obj.hasOwnProperty('toString');// false obj.hasOwnProperty = function (){ return true; }; obj.hasOwnProperty('toString');// true Object.prototype.hasOwnProperty.call(obj, 'toString');// false
【2】找出數組最大元素
javascript不提供找出數組最大元素的函數。結合使用apply方法和Math.max方法,就可以返回數組的最大元素
var a = [10, 2, 4, 15, 9]; Math.max.apply(null, a);//15
【3】將類數組對象轉換成真正的數組
Array.prototype.slice.apply({0:1,length:1});//[1] 或者 [].prototype.slice.apply({0:1,length:1});//[1]
【4】將一個數組的值push到另一個數組中
var a = []; Array.prototype.push.apply(a,[1,2,3]); console.log(a);//[1,2,3] Array.prototype.push.apply(a,[2,3,4]); console.log(a);//[1,2,3,2,3,4]
【5】綁定回調函數的對象
由於apply方法(或者call方法)不僅綁定函數執行時所在的對象,還會立即執行函數,因此不得不把綁定語句寫在一個函數體內。更簡潔的寫法是采用下面介紹的bind方法
var o = {}; o.f = function () { console.log(this === o); } var f = function (){ o.f.apply(o); }; $('#button').on('click', f);
【bind()】
bind()是ES5新增的方法,這個方法的主要作用就是將函數綁定到某個對象
當在函數f()上調用bind()方法並傳入一個對象o作為參數,這個方法將返回一個新的函數。以函數調用的方式調用新的函數將會把原始的函數f()當做o的方法來調用,傳入新函數的任何實參都將傳入原始函數
[注意]IE8-瀏覽器不支持
function f(y){ return this.x + y; //這個是待綁定的函數 } var o = {x:1};//將要綁定的對象 var g = f.bind(o); //通過調用g(x)來調用o.f(x) g(2);//3
兼容代碼
function bind(f,o){ if(f.bind){ return f.bind(o); }else{ return function(){ return f.apply(o,arguments); } } }
bind()方法不僅是將函數綁定到一個對象,它還附帶一些其他應用:除了第一個實參之外,傳入bind()的實參也會綁定到this,這個附帶的應用是一種常見的函數式編程技術,有時也被稱為’柯里化’(currying)
var sum = function(x,y){ return x+y; } var succ = sum.bind(null,1); succ(2); //3,x綁定到1,並傳入2作為實參y function f(y,z){ return this.x + y + z; } var g = f.bind({x:1},2); g(3); //6,this.x綁定到1,y綁定到2,z綁定到3 使用bind()方法實現柯里化可以對函數參數進行拆分
function getConfig(colors,size,otherOptions){ console.log(colors,size,otherOptions); } var defaultConfig = getConfig.bind(null,'#c00','1024*768'); defaultConfig('123');//'#c00 1024*768 123' defaultConfig('456');//'#c00 1024*768 456'
【toString()】
函數的toString()實例方法返回函數代碼的字符串,而靜態toString()方法返回一個類似’[native code]’的字符串作為函數體
function test(){ alert(1);//test } test.toString();/*"function test(){ alert(1);//test }"*/ Function.toString();//"function Function() { [native code] }"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
【toLocaleString()】
函數的toLocaleString()方法和toString()方法返回的結果相同
function test(){ alert(1);//test } test.toLocaleString();/*"function test(){ alert(1);//test }"*/ Function.toLocaleString();//"function Function() { [native code] }"
【valueOf()】
函數的valueOf()方法返回函數本身
function test(){ alert(1);//test } test.valueOf();/*function test(){ alert(1);//test }*/ typeof test.valueOf();//'function' Function.valueOf();//Function() { [native code] }