全局 this
定为指向 window
(一般是在浏览器环境讨论)。
默认绑定
函数调用时,没有前缀直接调用的情况,指向全局对象 window fn()
;
隐式绑定
前面存在调用它的对象,这个 this
就会隐式绑定到这个对象 obj.fn()
this 指向 obj
显示绑定
call、bind、apply 都是用来显示改变 this 指向
call
-
语法:fn.call(obj,...args)
-
功能:执行 fn,使 this 为 obj,并将后面的 n 个参数传给 fn
let dog = {
name:"旺财",
sayName(){
console.log("我是"+this.name)
},
eat(food){
console.log(this.name+"喜欢吃"+food);
},
drink(tea1,tea2){
console.log(this.name+"喜欢喝"+tea1+"和"+tea2);
}
}
let cat = {
name:"汤姆"
}
//原本sayName函数中的this指向为dog
dog.sayName() // 函数执行结果为:我是旺财
dog.eat("骨头") // 函数执行结果为:旺财喜欢吃骨头
dog.drink("红茶","绿茶") // 函数执行结果为:旺财喜欢喝红茶和绿茶
//通过call将sayName()函数中的this指向改为cat
dog.sayName.call(cat) // 函数执行结果为:我是汤姆
dog.eat.call(cat,"鱼") //函数执行的结果为:汤姆喜欢吃鱼
dog.drink.call(cat,"红茶","绿茶") //函数的执行结果为:汤姆喜欢喝红茶和绿茶
apply
语法:fn.apply(obj,arr)
功能:执行 fn,使 this 为 obj,并 arr 数组中元素传给 fn
//继续以上面代码为例子
//通过apply将sayName()函数中的this指向改为cat
dog.eat.apply(cat,["鱼"]) //函数执行的结果为:汤姆喜欢吃鱼
dog.drink.apply(cat,["红茶","绿茶"]) //函数的执行结果为:汤姆喜欢喝红茶和绿茶
bind
-
语法:fn.bind(obj,...args)
-
功能:返回一个新函数,给 fn 绑定 this 为 obj,并制定参数为后面的 n 个参数
//继续以上面代码为例子
//通过bind将sayName()函数中的this指向改为cat
let fun1 = dog.eat.bind(cat,"鱼")
let fun2 = dog.drink.bind(cat,"红茶","绿茶")
fun1() //函数执行的结果为:汤姆喜欢吃鱼
fun2() //函数的执行结果为:汤姆喜欢喝红茶和绿茶
注意:bind也可以分多次传入参数
//继续以上面代码为例子
//通过bind将sayName()函数中的this指向改为cat
let fun1 = dog.eat.bind(cat,)
let fun2 = dog.drink.bind(cat)
fun1("鱼") //函数执行的结果为:汤姆喜欢吃鱼
fun2("红茶","绿茶") //函数的执行结果为:汤姆喜欢喝红茶和绿茶
区别 call()/apply()/bind()
-
call(obj,...arg)/apply(obj,arr)::调用函数, 指定函数中的 this 为第一个参数的值
-
bind(obj): 返回一个新的函数, 新函数内部会调用原来的函数, 且 this 为 bind()指定的第一参数的值
-
三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入
new 的绑定
在使用 new 创建对象时也会进行 this 绑定
当使用 new 调用构造函数时,会创建一个新的对象并将该对象绑定到构造函数的 this 上:
function Greeting(message) {
this.message = message
}
var obj = new Greeting('hello,world')
obj.message // "hello,world"
this 的优先级
new绑定 > 显示绑定(apply/call/bind) > 隐式绑定> 默认绑定(独立函数调用)