標籤:另一個 函數的參數 OLE apply() 代碼 分享圖片 ima 變化 win
每個函數都包含兩個非繼承而來的方法:apply()和 call()。這兩個方法的用途都是在特定的範圍中調用函數,實際上等於設定函數體內 this 對象的值。
首先,apply()方法接收兩個參數:一個是在其中運行函數的範圍,另一個是參數數組。其中,第二個參數可以是 Array 的執行個體,也可以是arguments 對象。
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this, arguments); // 傳入 arguments 對象
}
function callSum2(num1, num2){
return sum.apply(this, [num1, num2]); // 傳入數組
}
alert(callSum1(10,10)); //20
alert(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);
}
alert(callSum(10,10)); //20
call()的官方解釋,“調用一個對象的一個方法,以另一個對象替換當前對象。” apply 同理。
call是在 C.A.call(B) B對象中沒有A的方法,但卻想使用A方法,然後就使用call,用B對象替換擁有A方法的C對象。
call 方法的本質實現過程:
對象A.方法.call(對象B,1,2,3)
等價於
對象B.方法 = 對象A.方法;
對象B.方法(1,2,3);
delete 對象B.方法;
上文中 sum.call(this,num1)咋一看 sum 並不是 一個對象的一個方法 但是你可以列印window.sum sum其實是window全域對象的一個方法。
就好比 function Aa(){
this.age=18;
}
Aa(); //我們怎麼才能訪問到這個age屬性呢? 可以 window.age 也就是說aa()中,this=window.
此時可以很自然的引伸與建構函式的不同。
var a=new Aa(); //建構函式最好大寫開頭,利於代碼閱讀
a.age=18;
事實上,傳遞參數並非 apply()和 call()真正的用武之地;它們真正強大的地方是能夠擴充函數
賴以啟動並執行範圍。接下來繼續看call 如何使用:
window.color = "red";
function sayColor(){
alert(this.color);
}
sayColor(); //red
sayColor.call(this); //red 可以列印出來this 為 window對象
sayColor.call(window); //red 這兩個本質上都是以window對象替換window對象。 是不是有點繞?想想下面這兩也會輸出red
window.sayColor.call(window);//red
window.sayColor.call();//red
其實這塊的本質我們並不需要必須以window對象替換window對象,可以以任何對象代替window對象都也可以調用到sayColor方法。
var a={};
window.sayColor.call(a);//undefined a對象調用了window的sayColor方法,但a對象本身沒有color屬性,所以導致 alert(this.color)==undefined
直接在a對象中定義一個color屬性
var a={color:"blue"};
sayColor.call(a);
或者是在一個建構函式的原型對象中添加一個color屬性,然後用這個建構函式執行個體化一個對象。
function Test(){};
Test.prototype.color="blue";
var test=new Test();
sayColor.call(test) //blue
這對於原型和原型鏈有很大協助。先在 test ,沒找見,再去test.__proto__上去找 可以自己列印出來test 和 test.__proto__ 一目瞭然啦!
這裡引申 範圍和範圍鏈
function aa(){
this.name="王文軒";
}
function bb(){
this.sayName= function(){
console.log(this.name)
}
}
var a=new aa();
bb.call(a); 這個call中,a對象擁有了window.bb中所有的方法
a.sayName(); call明明只是調用但卻有了sayName方法。
var a=new aa();
var b =new bb();
b.sayName.call(a);
var a=new aa();
var b =new bb();
var objectSayColor = b.sayName.call(a);分別運行 直接就會輸出結果
var objectSayColor = b.sayName.bind(a);分別運行
objectSayColor(); 才會出來結果。
其實.bind() 產生了一個新的函數,函數內部用到了 .call() / .apply() 。
源碼:
另外附上call 和 bind 的妙用:https://www.zhihu.com/question/40892203 知乎 @蒙娜麗莎;
淺談call、apply、bind