1. 程式人生 > >js系列教程4-函式、函式引數全解

js系列教程4-函式、函式引數全解

全棧工程師開發手冊 (作者:欒鵬)

在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 =