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()的区别
call()方法接受的是一个参数列表,而apply()方法接受的是一个包含多个参数的数组。
列子:
<!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()参数不是array类型,会报以下错误。
TypeError: second argument to Function.prototype.apply must be an array
假如:character.say.apply(null,["班德尔城"]);这样写,那么this指向了window。
我们如果在window下这样定义:
var name="cc"
var sex ="男"
那么结果应该会这样:
cc 男 来自班德尔城
3,bind()
bind()方法和call,apply不一样的地方在于它返回的是一个函数
列子:
<!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()并不困难,但是面试中许多面试官都会问,“能自己模拟实现这三个函数吗?”,生活所迫那么自己实现一下。
参考: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;
}
然后处理参数,
let args=[]
for(let i =1;i<arguments.length;i++){
args.push("arguments["+i+']')
}
var res = eval('context.fn('+args+')')
到此完成了 call ()的模拟实现