1,
首先call()、apply()、bind() 都是用來重定義 this 這個對象的
例子1:
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>call</title>
</head>
<body>
</body>
<script>
? ? var name="蓋倫";
? ? var sex="男";
? ? var character={
? ? ? ? name: "艾希",
? ? ? ? character_sex: "女",
? ? ? ? say:function(){
? ? ? ? ? ? console.log(this.name + " "+ this.sex)
? ? ? ? }
? ? }
? ? console.log(character.name)
? ? character.say();
</script>
</html>
結果:

如果把say里面的console.log改以下
console.log(this.name + " "+ this.character_sex)
結果:

這樣的結果是因為this的指向問題,say里面this的指向是character這個對象,然后character.里沒有定義sex。call和apply()、bind()都可改變this指向
列子:
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>call</title>
</head>
<body>
</body>
<script>
? ? var gailun={
? ? ? ? name:"蓋倫",
? ? ? ? sex:"男"
? ? }
? ? var character={
? ? ? ? name: "艾希",
? ? ? ? character_sex: "女",
? ? ? ? say:function(){
? ? ? ? ? ? console.log(this.name + " "+ this.sex)
? ? ? ? }
? ? }
? ? character.say.call(gailun)
</script>
</html>
結果:
通過call()就將原來指向character的this變成指向gailun,bind(),apply(),通用會改變this指向。

2,call()和apply()的區(qū)別
call()方法接受的是一個參數(shù)列表,而apply()方法接受的是一個包含多個參數(shù)的數(shù)組。
列子:
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>call</title>
</head>
<body>
</body>
<script>
? ? var gailun={
? ? ? ? name:"蓋倫",
? ? ? ? sex:"男"
? ? }
? ? var timo={
? ? ? ? name:"提莫",
? ? ? ? sex:"未知"
? ? }
? ? var character={
? ? ? ? name: "艾希",
? ? ? ? character_sex: "女",
? ? ? ? say:function(from){
? ? ? ? ? ? console.log(this.name + " "+ this.sex+" "+"來自"+from)
? ? ? ? }
? ? }
? ? character.say.call(gailun,"德瑪西亞");
? ? character.say.apply(timo,["班德爾城"]);
</script>
</html>
結果:

假如apply()參數(shù)不是array類型,會報以下錯誤。
TypeError: second argument to Function.prototype.apply must be an array
假如:character.say.apply(null,["班德爾城"]);這樣寫,那么this指向了window。
我們?nèi)绻趙indow下這樣定義:
?? var name="cc"
? ? var sex ="男"
那么結果應該會這樣:
cc 男 來自班德爾城
3,bind()
bind()方法和call,apply不一樣的地方在于它返回的是一個函數(shù)
列子:
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>call</title>
</head>
<body>
</body>
<script>
? ? var name="cc"
? ? var sex ="男"
? ? var gailun={
? ? ? ? name:"蓋倫",
? ? ? ? sex:"男"
? ? }
? ? var timo={
? ? ? ? name:"提莫",
? ? ? ? sex:"未知"
? ? }
? ? var character={
? ? ? ? name: "艾希",
? ? ? ? sex: "女",
? ? ? ? say:function(from){
? ? ? ? ? ? console.log(this.name + " "+ this.sex+" "+"來自"+from)
? ? ? ? }
? ? }
? ? character.say.call(gailun,"德瑪西亞");
? ? character.say.apply(timo,["班德爾城"]);
? ? console.log(character.say.bind(gailun,"德瑪西亞"))
</script>
</html>
結果:

理解call(),apply(),bind()并不困難,但是面試中許多面試官都會問,“能自己模擬實現(xiàn)這三個函數(shù)嗎?”,生活所迫那么自己實現(xiàn)一下。
參考:https://github.com/mqyqingfeng/Blog/issues/11
實踐寫一個call(),其他參考上面的地址
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>myCall</title>
</head>
<body>
</body>
<script>
? ? var a=1;
? var bar={
? ? ? a:1
? }
? var bar2={
? ? ? a:2
? }
function testCall(argA,argB){
? return {
? ? ? ? argA:argA,
? ? ? ? argB:argB,
? ? ? ? value:this.a
? }
}
testCall.call(bar,"c","cheng")
Function.prototype.myCall=function(context){
? ? var context = context || window
? ? context.fn=this
? ? let args=[]
? ? for(let i =1;i<arguments.length;i++){
? ? ? ? args.push("arguments["+i+']')
? ? }
? ? var res = eval('context.fn('+args+')')
? ? delete context.fn
? ? return res
}
console.log(testCall.myCall(bar2,"c","cheng"))
console.log(testCall.myCall(null))
</script>
</html>
理解:
首先改變this指向
Function.prototype.call2=function(context) {
????? context.fn=this;context.fn();
????? delete context.fn;
}
如果context為空,則需要把context改成window對象
所以改進一下
Function.prototype.call2=function(context) {
????? var context = context || window;
???? context.fn=this;context.fn();
????? delete context.fn;
}
然后處理參數(shù),
?? let args=[]
? ? for(let i =1;i<arguments.length;i++){
? ? ? ? args.push("arguments["+i+']')
? ? }
???? var res = eval('context.fn('+args+')')
到此完成了 call ()的模擬實現(xiàn)