call與apply與bind異同
- 作用:均爲改變this指向
- call/bind傳參爲多個參數,apply傳參爲一個參數數組
- bind的時候function函數不執行,需手動執行,call/apply的時候函數自動執行
例子
function Person(name, age) {
this.name = name;
this.age = age;
}
Person('doudou', 28); //執行時,Person內this指向window,執行完後,window.name 就等於doudou
var stu1 = new Person('feifei',29); //執行時,Person內this指向stu1,執行完後,stu1.name 等於feifei
var stu2 = {};
Person.call(stu2, 'fangfang', 27); //改變this指向,Person內this指向stu2,執行完後,stu2.name 等於fangfang
Person.apply(stu2, ['liaoliao', 27]);//改變this指向,Person內this指向stu2,執行完後,stu2.name 等於liaoliao
Person.bind(stu2, ['xiaoxiao', 26])();////改變this指向,Person內this指向stu2,執行完後,stu2.name 等於xiaoxiao
實戰
call和apply可以用來借用別人的函數來完成自己的功能
//別人寫好的函數
function Person(name, age) {
this.name = name;
this.age = age;
}
//借過來用
function Student(name, age, grade, score) {
Person.call(this, name, age);
this.grade = grade;
this.score = score;
}
var stu = new Student('doudou', 28, 2, 99)
call與apply與bind的源碼實現
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>手寫apply/bind/call</title>
</head>
<body>
<script>
Function.prototype.myApply = function (obj, arr) {
let context = obj || window;
// 此處this指向調用者,Person,誰調用,指向誰,給obj增加Person函數,Person函數裏面的this,指向obj
context.func = this;
// 執行函數即可
// 利用擴展運算符,將一個數組轉爲用逗號分隔的參數序列
context.func(...arr);
// 刪除函數
delete context.func;
}
// 利用擴展運算符,函數剩餘參數轉爲一個數組
Function.prototype.myCall = function (obj, ...arr) {
let context = obj || window;
context.func = this;
// 利用擴展運算符,將一個數組轉爲用逗號分隔的參數序列
context.func(...arr);
delete context.func;
}
Function.prototype.myBind = function (obj, arr) {
let context = obj || window;
let self = this;
// 將apply執行作爲函數內返回,要執行這個函數才執行
return function() {
// 此中的this爲函數的執行環境
return self.apply(context, arr);
}
}
function Person(name, age) {
this.name = name;
this.age = age;
}
let stu1 = {}, stu2 = {}, stu3 = {};
Person.myApply(stu1, ['liaoliao', 1]);
Person.myCall(stu2, 'feifei', 2);
Person.myBind(stu3, ['xiongxiong', 3])();
console.log(stu1);
console.log(stu2);
console.log(stu3);
</script>
</body>
</html>