函數形參實參的理解


在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] }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM