一、前言
在js中,this关键字重要,很多同学工作几年了,依然对this问题很模糊,通过这篇文章希望能够帮助到大家,深刻理解this。
二、this的本质是什么?
在js中,所有的函数(除了箭头函数),内部都会有一个属性this,当调用函数的方式不同时,this的指向也有所不同。
三、绑定this的方式有哪些?
绑定this的方式一般包含一下几种:
- 默认绑定(一般this指向window)
- 隐式绑定(谁调用,指向谁,存在隐式丢失问题)
- 显式绑定(call、apply、bind 能改变this指向)
- new 实例化
- es6中箭头函数(内部没有this属性,输出的是父级上下文的this)
绑定this的优先级:箭头函数 > new > 显式绑定 > 隐式绑定 > 默认绑定
四、this的默认绑定
代码:
function foo(){
console.log(this);
}
foo() // Window
解读:当函数被直接调用时,this默认指向window。
五、this的隐式绑定
代码:
function foo(){
console.log(this);
}
let obj = {
name:1,
foo:foo
}
// 隐式绑定,对象调用,谁调用,指向谁
obj.foo(); // {name: 1, foo: ƒ}
// 赋值给一个变量,再调用,隐式绑定丢失
let temp = obj.foo;
temp(); // Window
解读:1、函数foo,被obj以属性的方式调用时,属于隐式绑定规则,谁调用,this就会指向谁,所以this指向obj;
2、存在隐式绑定丢失情况,如以上代码,将obj.foo赋值给一个新的变量,此时调用等同于直接调用,所以this指向window。
六、this的显式绑定
代码:
function foo(params){
this.age = params
console.log(this);
}
let obj = {
foo:foo
}
let obj1 = {
name:1,
}
let obj2 = {
name:2,
}
let obj3 = {
name:3,
}
obj.foo.call(obj1,18) // {name: 1, age: 18}
obj.foo.apply(obj2,[19]) // name: 2, age: 19}
obj.foo.bind(obj3,20)() // {name: 3, age: 20}
obj.foo.call(null,21) // Window
解读:通过call、apply、bind都可以显式的改变this指向,并且优先级高于隐式绑定。
七、new关键字实例化
代码:
function foo(params){
this.age = params;
console.log(this); // foo {age: 18}
}
let obj = {
foo: foo
}
let obj1 = {
name:1
}
let temp = obj.foo.bind(obj1)
let foo1 = new temp(18)
console.log(foo1); // foo {age: 18}
console.log(obj1); // {name: 1}
解读:先使用bind改变this指向obj1,在使用new实例化一个对象,通过输出可以看出,当前this指向是foo1,并不是指向obj1,故,this绑定,new关键字优先于显式绑定
八、特殊案例“箭头函数”
代码:
let obj = {
foo:()=>{
console.log(this)
}
}
let obj1 = {
name:1,
}
obj.foo.call(obj1) // Window
// 箭头函数和new关键字,在一起如何呢?
let temp = obj.foo.bind(obj1)
let foo1 = new temp() // 报错:temp is not a constructor
解读:1、箭头函数内部没有this,输出的this是父级上下文的this,所以即使用call也无法改变,最终还是指向Window;
2、当new关键字和箭头函数一起使用时会报错:is not a constructor,所以箭头函数不能被当做构造函数
练习
var name = 'window'
let obj1 = {
name:1,
fn1: function(){
console.log(this.name)
},
fn2: ()=>console.log(this.name),
fn3: function () {
return function(){
console.log(this.name)
}
},
fn4:function () {
return ()=>console.log(this.name)
}
}
let obj2 = {
name:2
}
obj1.fn1(); // 1
obj1.fn1.call(obj2); //2
obj1.fn2(); // 'window'
obj1.fn2.call(obj2); // 'window'
obj1.fn3()(); // 'window'
obj1.fn3().call(obj2); // 2
obj1.fn3.call(obj2)(); // 'window'
obj1.fn4()(); // 1
obj1.fn4().call(obj2); // 1
obj1.fn4.call(obj2)(); //2
大家做对了吗? 欢迎大家留言评论