一.this概述
Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象。
其中this就是实现面向对象的一个非常重要的特性,但是 this在Javascript中非常容易被理解错,尤其是对于接触静态语言比较久的同学来说。而且 this又是面试中和实际项目中的重中之重,所以今天写一篇文章,加强记忆,温故而知新。
二.this三种指向
this的指向是可以修改的,接下来一一介绍
**环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建的实例对象
* 小技巧: 没点没new是window, 有new是实例,有点是点左边的对象**
注意:this在箭头函数中失效了,因为箭头函数没有单独的 this值。箭头函数的 this与声明所在的上下文相同。也就是说调用箭头函数的时候,不会隐式的调用 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>Document</title>
</head>
<body>
<script>
/*
环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建的实例对象
* 小技巧: 没点没new是window, 有new是实例,有点是点左边的对象
*/
/* function fn(){
console.log( this )
}
//普通函数 : window
fn()
//构造函数 : new创建实例对象
new fn()
let obj = {
name:'张三',
eat:fn
}
//对象方法 : obj对象
obj.eat() */
/*
1.函数this指向:谁'调用'我,我就指向谁
1.1普通函数:函数名() this-->window
1.2构造函数: new 函数名() this-->new创建的实例
1.3对象方法: 对象名.方法名() this-->对象 */
/* let fn = function(){
console.log(this)
}
// 1.普通函数
fn()
// 2.构造函数
new fn()
// 3.对象方法
let obj = {
name:'张三',
eat:fn
}
obj.eat() */
let person = {
name:'李四',
eat:function(){
console.log(this)
},
learn:function(){
let eat = this.eat
eat()
}
}
person.eat()
person.learn()
</script>
</body>
</html>
三.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>Document</title>
</head>
<body>
<script>
/*
环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建的实例对象
* 小技巧: 没点没new是window, 有new是实例,有点是点左边的对象
*/
//作用域链
let obj = {
name: "张三",
eat: function() {
//1级链
console.log(this) //1.obj
function fn() {
//2级链
console.log(this) //2.window
}
fn()
}
}
let eat = obj.eat
obj.eat()
</script>
</body>
</html>
四.call方法修改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>Document</title>
</head>
<body>
<script>
/*
1.环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建的实例对象
*** 默认情况下,函数内部的this不能主动修改. 如果需要修改,则需要使用上下文方式
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply()
2.3 函数名.bind()
*/
/* function fn(a,b){
console.log( a + b )
console.log( this )
}
// 函数名.call(修改后的this)
fn.call({name:'张三'},10,20) */
1.函数this指向:谁'调用'我,我就指向谁
1.1 普通函数:函数名() this-->window
1.2 构造函数:new 函数名() this-->new创建的实例
1.3 对象方法:对象名.方法名() this-->对象
2.默认情况下,函数内部的this是固定的,无法动态修改,
如果想要动态修改函数this指向,需要使用函数上下文调用
函数上下文:函数作用域
3.函数上下文调用:动态修改this指向
函数名.call(修改的this,参数1,参数2,....)
函数名.apply()
函数名.bind()
function fn(a,b){
console.log(this)
console.log(a+b)
}
// 函数名.call(修改后的this)
fn.call({name:'张三'},20,40)
</script>
</body>
</html>
五.apply方法修改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>Document</title>
</head>
<body>
<script>
/*
1.环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建的实例对象
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply(修改后的this, 数组或伪数组 )
2.3 函数名.bind()
*/
/* function fn(a,b){
console.log( a + b )
console.log( this )
}
// 函数名.call(修改后的this,形参1,形参2…………)
fn.call({name:'张三'},10,20)
// 函数名.apply(修改后的this, 数组或伪数组 )
// apply会自动帮你遍历数组,然后按照顺序逐一传参
fn.apply({name:'李四'}, [30,40] ) */
函数名,apply(修改后的this,数组或伪数组)
apply会自动帮你遍历数组,然后按照顺序逐一传参 */
function fn(a, b,c) {
console.log(this)
console.log(a + b)
}
fn.apply({ name: '李到' }, [44, 555])
</script>
</body>
</html>
六.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>Document</title>
</head>
<body>
<script>
/*
1.环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建的实例对象
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply(修改后的this, 数组或伪数组 )
2.3 函数名.bind(修改后的this)
* 不会立即执行函数,而是得到一个修改this之后的新函数。
* bind一般用于修改: 定时器函数、事件处理函数
*/
function fn(a,b){
console.log( a + b )
console.log( this )
}
// 函数名.call(修改后的this,形参1,形参2…………)
fn.call({name:'张三'},10,20)
// 函数名.apply(修改后的this, 数组或伪数组 )
// apply会自动帮你遍历数组,然后按照顺序逐一传参
fn.apply({name:'李四'}, [30,40] )
//函数名.bind(修改后的this)
// bind不会立即执行函数,而是返回一个修改this之后的新函数
let newFn = fn.bind({name:'王五'})
newFn(100,200)
newFn(10,20)
</script>
</body>
</html>
七.经典面试题:call、apply、bind区别
面试必问: call 和 apply 和 bind 三者区别
相同点 : 作用一致,修改函数this指向
不同点 :
传参方式不同 : call是按照顺序传参, apply是数组/伪数组传参
执行机制不同 : call和apply会立即执行函数,
而bind不会立即执行而是得到修改this的新函数