閱讀431 返回首頁    go 阿裏雲 go 技術社區[雲棲]


JS中的call()和apply()方法總結

在js中每個函數都包含兩個非繼承而來的方法:call()和apply()

call和apply的作用都是在特定的作用域中將函數綁定到另外一個對象上去運行,即可以用來重新定義函數的執行環境,兩者僅在定義參數方式上有所區別

它們接收參數方麵不同:call和apply的第一個參數都是需要調用的函數對象,在函數體內這個參數就是this的值,剩餘的參數是需要傳遞給函數的值,call與apply的不同就是call傳的值可以是任意的,而apply傳的剩餘值必須為數組

call方法

語法:

Function.call(obj,param1,param2...)

obj:這個對象將替代Function類裏的this對象

params:這是一個參數列表

注意: 調用call的對象必須是一個函數對象,因為 call這個方法是在Function的prototype裏的

定義:

調用一個對象的一個方法,以另一個對象替換當前對象

關於call的定義很拗口。我的理解:a.call(b,arg1,arg2..)就是a對象的方法應用到b對象上

function add(a,b){
    alert(a+b);
}
function reduce(a,b){
    alert(a-b);
}
add.call(reduce,1,3) //將add方法運用到reduce,結果為4

這個例子中的意思就是用 add 來替換 reduce,add.call(reduce,3,1) == add(3,1) ,所以運行結果為:alert(4); // 注意:js中的函數其實是對象,函數名是對 Function 對象的引用

window.firstName = "diz"; 
window.lastName = "song"; 
var myObject = { firstName: "my", lastName: "Object" }; 
function HelloName() { 
    console.log("Hello " + this.firstName + " " + this.lastName, " glad to meet you!"); 
} 
HelloName.call(window);    //Hello diz song glad to meet you!
HelloName.apply(myObject);    //Hello my Object glad to meet you! 

在例子中,我們發現apply()和call()的真正用法是能夠擴充函數賴以運行的作用域,如果我們想用傳統的方法實現,請見下麵的代碼:

window.firstName = "diz"; 
window.lastName = "song"; 
var myObject = { firstName: "my", lastName: "Object" }; 
function HelloName() { 
    console.log("Hello " + this.firstName + " " + this.lastName, " glad to meet you!"); 
} 
HelloName();    //Hello diz song glad to meet you! 
myObject.HelloName = HelloName; 
myObject.HelloName();    //Hello my Object glad to meet you! 

我們發現,要想讓HelloName()函數的作用域在對象myObject上,我們需要動態創建myObject的HelloName屬性,此屬性作為指針指向HelloName()函數,這樣,當我們調用myObject.HelloName()時,函數內部的this變量就指向myObject,也就可以調用該對象的內部其他公共屬性了

<input type="text"    value="input text">
<script>
   function Obj(){this.value="對象!";}
   var value="global 變量";
   function Fun1(){alert(this.value);}
   window.Fun1();      //global 變量
   Fun1.call(window);     //global 變量
   Fun1.call(document.getElementById('myText'));  //input text
   Fun1.call(new Obj());      //對象!
   window.Fun1();    //global 變量
</script>

call可以改變this指向

function Animal(){
    this.name=”animal”;
    this.showName=function(){
        alert(this.name)
    }
}
function Cat(){
    this.name=”cat”;
}
var animal = new Animal();
var cat = new Cat();
animal.showName();    //結果為animal
animal.showName.call(cat);    //通過call方法將原本屬於Animal對象的showName()方法交給對象cat來使用,輸入結果為"Cat" 

call 的意思是把 animal 的方法放到cat上執行,原來cat是沒有showName() 方法,現在是把animal 的showName()方法放到 cat上來執行,所以this.name 應該是 Cat

bind()方法

支持此方法的瀏覽器有IE9+、Firefox4+、Safari5.1+、Opera12+、Chrome。它屬於ECMAScript5的方法:

window.color = "red"; 
var o = { color: "blue" }; 
function sayColor(){ 
    console.log(this.color); 
} 
var OSayColor = sayColor.bind(o); 
OSayColor();    //blue 

這裏,sayColor()調用bind()方法,並傳入o對象,返回了OSayColor()函數,在OSayColor()中,this的值就為o對象

實現繼承

function Animal(name){
    this.name=name;
    this.showName=function(){
        alert(this.name)
    }
}
function Cat(name){
    Animal.call(this,name);  
}
var cat = new Cat(“Black Cat”);
cat.showName();    //瀏覽器彈出Black Cat

Animal.call(this) 的意思就是使用 Animal對象代替this對象,那麼 Cat中不就有Animal的所有屬性和方法了嗎,Cat對象就能夠直接調用Animal的方法以及屬性了

多重繼承

function s1(name){
    this.name = name;
}
var s2 = function(sex){
    this.sex = sex;
}
var s3 = function(age){
    this.age = age;
}
var Student = function(name,sex,age,score){
    s1.call(this,name);
    s2.call(this,sex);
    s3.call(this,age);
    this.score = score;
}
Student.prototype.construction = Student;
var s = new Student('jack','male','12','100');
console.log(s.name); //輸出:jack
console.log(s.sex);  //輸出:male 
console.log(s.age);  //輸出:12
console.log(s.score);//輸出:100

很簡單,使用兩個 call 就實現多重繼承了。當然,js的繼承還有其他方法,例如使用原型鏈

當然還有 apply,這兩個方法基本上是一個意思,區別在於 call 的第二個參數可以是任意類型,而apply的第二個參數必須是數組,也可以是arguments
還有 callee,caller..

apply方法:

語法:

Function.apply(obj,args)

obj:這個對象將代替Function類裏this對象(就是定義函數代碼塊裏麵的this)

args:這個是數組,它將作為參數傳給Function(args-->arguments),這個可以是數組也可以是 arguments

定義:

應用某一對象的一個方法,用另一個對象替換當前對象。

什麼情況下用apply,什麼情況下用call

在給對象參數的情況下,如果參數的形式是數組,比如apply示例裏麵傳遞了參數arguments,這個參數是數組類型,並且在調用Animal的時候參數的列表是對應一致的(也就是Animal和Cat的參數列表前兩位是一致的) 就可以采用 apply , 如果我的Animal的參數列表是這樣的(age,name),而Cat的參數列表是(name,age,kind),這樣就可以用call來實現了,也就是直接指定參數列表對應值的位置(Person.call(this,age,name,kind));

apply的一些其他巧妙用法:

apply可以將一個數組默默的解析成一個一個的參數,可以將一個數組默認的轉換為一個參數列表([param1,param2,param3] 轉換為 param1,param2,param3) ,利用aplly這個特點我們就可以用在一些針對字符串操作的方法了:例如

1.Math.max 可以實現得到數組中最大的一項

因為Math.max 參數裏麵不支持Math.max([param1,param2]) 也就是數組,但是它支持Math.max(param1,param2,param3…),所以可以根據剛才apply的那個特點來解決
var max=Math.max.apply(null,array),這樣輕易的可以得到一個數組中最大的一項 (apply會將一個數組裝換為一個參數接一個參數的傳遞給方法) 這塊在調用的時候第一個參數給了一個null,這個是因為沒有對象去調用這個方法,我隻需要用這個方法幫我運算,得到返回的結果就行,.所以直接傳遞了一個null過去(利用Math方法但是不改變this的指向)

2.Math.max 可以實現得到數組中最小的一項

和 max是一個原理 var min=Math.min.apply(null,array)

3.Array.prototype.push 可以實現兩個數組合並

arr1=new Array("1","2","3");
var arr2=new Array("4","5","6");
Array.prototype.push.apply(arr1,arr2);

最後更新:2017-06-20 17:02:26

  上一篇:go  增強學習與無人駕駛
  下一篇:go  如何做一個高質量的網站頁麵?