引言
this到底指的是哪,这个问题困扰了不少前端工程师。笔者在开发Vue项目的时候,时常因为this碰到各种奇奇怪怪的问题。今天笔者会通过本文细致的剖析this。
在全局中使用this
在浏览器中this指向的是window,大家可以自行测试。
在node环境中,this指向的是{} 。
函数中使用this
开发中,在函数里使用this
但是,开发中很少直接在全局作用于下去使用this,通常都是在函数中使用。所有的函数在被调用时,都会创建一个执行上下文,这个执行上下文中存放着函数的调用栈,AO对象等,(不了解这些概念的可以去看看笔者之前的文章)。this也是这些记录中的一个(执行上下文中也存放了this)。
函数里this到底指哪?
首先我们要明确一点,函数在调用时,javascript会默认给this绑定一个指。this的绑定和定义的位置(编写的位置)没有关系,并且this是在运行时被绑定的。
其次,this有四种绑定规则,它们分别是:默认绑定、隐式绑定、显示绑定、new绑定。笔者会在下文举例说明。
默认绑定
独立函数调用即为默认绑定,此时this打印的值为window。大家一定要注意我说的,this是在函数调用时被确定值的,与它定义的位置没有关系!!! 下面直接上代码。
function foo(){ //代码1 这很好理解
console.log(this); //window
}
foo() //此处即为独立函数调用
function foo(){
console.log(this); //window,它们都是一样的
}
let fn = foo()
fn()
function test1(){ //代码2,这里打印的都是window
console.log(this);
test2()
}
function test2(){
console.log(this);
test3()
}
function test3(){
console.log(this);
}
test1()
function foo(func){
func()
}
let obj = {
name : 'why',
bar : function(){
console.log(this);
}
}
foo(obj.bar) //这里也是this
隐式绑定
隐式绑定绑定需要有一个前提条件,必须在调用的对象内部有一个对函数的引用(比如一个属性),如果没有这样的引用,函数就会报错。通过这个引用,间接将this绑定到这个对象上了。
听起来很抽象,实际上就是你调用对象中的函数,对象里要有它。
比如下面这个代码
//案例1
function foo(){
console.log(this);
}
var obj = {
name : 'why',
foo : foo
}
obj.foo() //obj对象
显示绑定
call, apply, bind函数可以制定this
所有的函数上都有call,apply与bind方法,它们可以用来调用函数,比如如下的代码,跟sum()一样。
但是它们可以指定this,具体如下面的代码,第一个参数就是设置this的指向。
call apply bind的区别
call与apply传参各有不同,apply需要传数组,它们都是没返回值的。
bind有返回值。
let obj = {
name : 'harry',
age:18
}
function sum(num1,num2){
console.log(num1+num2,this);
}
sum.call("aaa",20,30) //call与apply是没有返回值的
sum.apply(obj,[20,30])
let fn = sum.bind("sdds",20,30) //传参跟call一样
fn() //这里的this是sdds,显示绑定的优先级高于独立函数
new绑定
javascript中使用new关键字,函数可以当做一个类的构造函数来使用.
//使用new绑定
//这个this是在调用这个构造器时创建出来的对象
function Person(name,age){
this.name = name
this.age = age
}
var p1 = new Person("why",18)
console.log(p1.name,p1.age);
var p2 = new Person("kobe",30)
console.log(p2.name,p2.age);
特殊函数的this
setTimeout
seTimeout实现的逻辑如下
function hySetTimeout(fn,duration){
fn() //内部类似这样调用的
}
hySetTimeout(function(){
console.log(this); //这里就是window
},3000)
JS的dom监听
html代码就省略了
addEventListner也是一样的
const boxDiv = document.querySelector('.box')
boxDiv.onclick = function(){
console.log(this); //那个dom
//内部做了一个boxDiv.onclick()这个操作
//bixDiv.onClick
}
this绑定规则优先级
- 默认绑定优先级最低
- call/apply /bind这类显示绑定高于 隐式绑定
- new绑定值最高
new > 显示 > 隐式 > 默认
箭头函数的this
箭头函数不使用this的四种规则,在箭头函数中压根就没有this这个东西。如果要找就是去外层作用域里找。
在开发中常见的一种情况(这个非常实用)
var obj = {
data:[],
getData:function(){
// 发送网络请求
setTimeout(function(){
var result = ["1213","3224"];
this.data = result; //这里是不行的,这里this指向了window了
},2000)
}
}
obj.getData()
在箭头函数出现之前的解决方案(采用闭包解决):
var obj = {
data:[],
getData:function(){
// 发送网络请求
var _this = this
setTimeout(function(){
var result = ["1213","3224"];
_this.data = result; //箭头函数之前的解决方案
},2000)
}
}
obj.getData() //A处调用
箭头函数出现之后,就不用闭包这种解决方案了。因为箭头函数不绑定this,它会直接从上层作作用域里寻找,此时它找到了obj。(因为A处调用)
var obj = {
data:[],
getData:function(){
// 发送网络请求
setTimeout(()=>{
var result = ["1213","3224"];
this.data = result;
},2000)
}
}
obj.getData()
转自本人掘金 https://juejin.cn/post/7105363028522041380/