1、什么是this
this表示对象
取决于函数调用
(this表示对象=>当前对象=>当前环境对象=>函数运行时环境对象)
this就是函数运行时所在的环境对象
(取决于函数调用=>不同场合,this有不同的值)
函数的不同使用场合,this有不同的值。
1、this永远指向对象
(JS中一切皆对象,window也是对象)
2、this指向取决于函数调用的位置
(this指向是不定的,无法在事先声明时就得知它的具体指向,因此只有在调用时才能得知它的指向)
3、this只能在函数体内部使用
(this是函数运行时,内部自动生成的一个对象(执行环境上下文,也称环境对象),this即函数内部环境对象本象,因此只能在函数内部使用)
4、箭头函数无视上述规则,且优先级最高
(箭头函数中this指向在声明处决定,指向作用域链的父级)
2、核心理解
场景优先级
箭头函数 > new > 显示绑定(call/apply/bind)> 隐式绑定(上下文对象obj) > 默认绑定(严格模式undefined,非严格为window)
注:
定时器setTimeout,setInterval中分两种情况,具体看下面例子
闭包或自执行函数被调用可以看做是接收了一个函数字符串,同样要看该字符串函数被调用的环境对象,具体看下面例子。
3、this指向详细例子
3.1 箭头函数中调用 箭头函数的this指向上一级环境对象
function fn() {setTimeout(() => {console.log(this.a);}, 1000);
}var obj = {a: 20,fn,
};fn.call(obj); // 20,这里可以理解为调用了obj.fn();
3.2 new实例调用 指向实例化出来的对象
function Person(name, age) {this.name = name;this.age = age;
}
const a = new Person('itachi', 18);
console.log( a.name ); // 这里new Person()构造函数内部的this指向了实例对象,
//即this=>a 所以this.name === a.name === 'itachi'
3.3 显示绑定(call/apply/bind) 绑定到指定的对象
可以参见箭头函数实例
var obj = {age: 20,fn:function (name) {console.log(this.name + '今年' + this.age + '岁')}
};
const a = { }
obj.fn.call( a , 'itachi'); // 执行了a.fn('itachi');'itachi'今年20岁
//这里可以理解为将obj中的this绑定到 a
//让a拥有了obj中的方法fn(),并调用了 a.fn ('itachi');
3.4 隐式绑定(上下文对象obj)
function fn() {console.log(this.name);
}
var obj = {name: 'itachi'
};
// 调用 fn(..) 时把 this 绑定到 obj
obj.fn(); //itachi
3.5 默认绑定(严格模式undefined,非严格为window)
function fn() {console.log(this.a);
}
a = 10;
fn(); // 相当于window.fn() 输出10
function fn() {'use strict';console.log(this.a);
}
a = 10;
fn(); //相当于undefined.fn()
//输出 TypeError: Cannot read property 'a' of undefined
3.6 定时器情况 定时器setInterval或setTimeout是window对象内置的一个方法
var obj = {fun:function(){return this ;}
}
//此时还没执行fn,后面没跟(),即只是作为一堆字符串将其传了过去,执行的时候已经是1000ms以后了,这时是window.setInterval在执行
setInterval(obj.fn,1000); // this指向window对象
//传入时就执行了,因此this指向的是obj对象
setInterval('obj.fn()',1000); // this指向obj对象
3.7 函数作为闭包或自执行函数被调用 意味着这个函数不符合以上任意一种调用方式 因为闭包并不属于这个对象的属性或方法。所以在闭包中的this是指向window的
var name = “window”;
var obj={name: “Object”;getName: function(){return function(){return this.name;}}
};
var myobj = obj.getName(); //myobj接收到匿名函数(可以看做以字符串形式接收)
//myObj === 'function(){return this.name;}'
console.log(myobj()); // Window 相当于 return window.name
console.log(obj.myobj()); // Object 相当于 return obj.name
3.8 在绑定事件中this指向—>当前事件对象
document.onclick = function () {console.log(this);
}
4、总结
this表示函数调用时的环境对象(执行上下文)
根据函数调用的不同场景,this指向也不同在箭头函数中:this指向作用域链的父级环境 在定时器中this指向--->Window
通过new实例化时:this指向新实例化出来的对象 在对象中this指向--->当前对象 在构造函数中this指向--->实例对象
通过call/apply/bind调用时:this将绑定到指定的对象 通过上下文(对象)调用时:this指向上下文(该对象)
通过一般函数内部调用时:严格模式this指向undefined,否则指向全局对象 普通函数this指向--->Window
5、修改this指向三张方法的格式以及注意事项:
call apply:改变this的指向 ,call直接调用,而apply需要重新调用这个函数
call传参数:call(this指向的,参数1,参数2...);
apply传参数:apply(this指向的,[参数1,参数2...]); --->apply传参数是一个数组
bind传参数:bind
5.1 强制修改this指向的调用格式:
fn1.call(obj);call() 方法的第一个参数必须是指定的对象,然后方法的原参数,挨个放在后面。
(1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么;
(2)第二个参数开始:将原函数的参数往后顺延一位
函数名.call()function fun() {console.log(this); // 原来的函数this指向的是 Window
}
fun();function fun(a, b) {console.log(this); // this指向了输入的 字符串callconsole.log(a + b);
}
//使用call() 方法改变this指向,此时第一个参数是 字符串call,那么就会指向字符串call
fun.call('call', 2, 3) // 后面的参数就是原来函数自带的实参
fn1.apply(obj);
apply() 方法的第一个参数是指定的对象,方法的原参数,统一放在第二个数组参数中。
(1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么;
(2)第二个参数开始:将原函数的参数放在一个数组中
用法: 函数名.apply()
function fun() {console.log(this); // 原来的函数this指向的是 Window
}
fun();function fun(a, b) {console.log(this); // this指向了输入的 字符串applyconsole.log(a + b);
}
//使用apply() 方法改变this指向,此时第一个参数是 字符串apply,那么就会指向字符串apply
fun.apply('apply', [2, 3]) // 原函数的参数要以数组的形式呈现```
fn1.bind(obj)();
bind() 方法的用法和call()一样,直接运行方法,需要注意的是:bind返回新的方法,需要重新
调用
是需要自己手动调用的
用法: 函数名.bind()
function fun() {console.log(this); // 原来的函数this指向的是 Window
}
fun();function fun(a, b) {console.log(this); // this指向了输入的 字符串bindconsole.log(a + b);
}
//使用bind() 方法改变this指向,此时第一个参数是 字符串bind,那么就会指向字符串bind
let c = fun.bind('bind', 2, 3);
c(); // 返回新的方法,需要重新调用
// 也可以使用下面两种方法进行调用
// fun.bind('bind', 2, 3)();
// fun.bind('bind')(2, 3);
5.2 强制修改this指向的传参语法:
fn1.call(obj, 1, 2);fn1.apply(obj, [3, 4]);fn1.bind(obj)(5, 6); // bind传参在react框架用的比较多些