this指向思维导图
this指向问题重要!!!重要!!!重要!!!
1.this是个关键字,在作用域内使用的关键字
- 要么使用在全局作用域
- 要么使用在私有作用域
因为只有函数生成私有作用域,所以就是使用在函数内部
2.this在全局作用域使用的时候
-
表示的意义就是window, 也叫作全局
-
一般不会在全局作用域下直接使用this
//全局作用域使用this console. log( this) console. log(window) console. log(window === this)
控制台输出:
3.this在**私有作用域(函数)**使用的时候
-
不管函数怎么定义,不管函数在哪定义,只看函数怎么调用(箭头函数除外)
-
普通调用/直接调用
函数名()
这样调用函数的时候
this 就是window -
对象调用
对象名.函数名()
这样调用函数的时候
对象名['函数名']()
这样调用函数的时候
this就是前面的对象,点前面是谁就是谁fn函数调用 里面的this 就是obj obj.fn() obj['fn']()
-
定时器处理困数
setTimeout(函数, 时间)
setInterval(函数,时间)
this 就是window -
事件处理函数
事件源.on事件类型=事件处理函数
事件源. addEventListener(‘事件类型’, 事件处理函数)
this 就是事件源(绑定在谁身上的事件)//私有作用域使用this //这个丽数只要调用,就会在控制台打印this function fn() { console.log( this ) } //调用fn兩数 //直按调用 fn() //本次调用,因为是直接调用,两数内部的this 就是wi ndow //对象调用 var obj ={ name:'Jack', //把fn存储的丽数地址给了obj对象的f成员份 //从此以后,obj.f和全局变量fn指向同个丽数空间 //两个名字调用的是同个两数 f: fn } obj.f() //本次调用,因为是对象调用,函数内部的this 就是这个对象obj
控制台输出:
<!-- css样式 -->
div{
width:200px;
height:200px:
background:pink;
}
<!--html -->
<div> </div>
<!-- js -->
<script>
//事件处理函数
var div = document . querySelector( 'div')
//当你点击div的时候,执行fn函数
//此时是把fn函数当做事件处理函数使用
div.onclick = fn //本次调用,因为是事件处理函数调用,函数内部的this 指向事件源,也就是div
//点击div区域,控制台输出div
//定时器处理函数
//会在1000ms 以后调用fn函数
//此时是把fn函数当做定时器处理函数使用
setTimeout(fn, 1000) //本次调用,因为是定时器处理函数调用,丙数内部的this 指向window
</script>
【练习】
function fn()
function fun() {
//这个this是书写在fun私有作用域的this
//只看fun函数是怎么被调用的
//不需要管fn是怎么调用的,只看fun这个函数是怎么调用的就可以了
console.log( this )
//普通调用的方式调用了fun函数
// fun函数内部的this -> window
fun( )
}
varobj={
name : '我是obj对象',
f: fn
}
// 开始调用
obj.f( )
总结:
普通函数的this指向
声明式 赋值式 定时器 延时器 forEach
window
事件处理函数
事件源
数组/对象中的函数
存储函数的数组/对象
箭头函数的this指向
父级程序的this指向
没有父级程序 父级程序没有this
this是 window
改变this指向
箭头函数不能改变this指向 永远是父级程序的this指向
执行时改变
函数.call(新的this指向 , 原始函数的实参)
函数.apply(新的this指向 , [原始函数的实参])
生成有一个新的函数
const 变量 = 函数.bind( 新的this指向 , 原始函数的实参 )
强行改变this 指向
- 在私有作用域内,当函数调用的时候,有本身的this 指向
- 我们可以使用一些方法来修改函数内的this指向
- 在JS内修改this 指向有三个方法
- call( )
- apply( )
- bind( )
-
call()方法
-
使用方式:
函数名.call( )
对象名.函数名.call( ) -
注意:
不要再事件处理函数和定时器处理函数里面使用
会立即调用函数 -
参数:
第一个:表示函数内的this 指向
第二个开始:表示传递给函数的实参// 1. call() function fn(a, b) { console.group('函数fn内的打印' ) console.log('a ':, a) console.log('b ':, b) console.log( 'this:', this) console.groupEnd( ) } //普通调用方式 //本次调用是普通调用方式,this -> window // 10是传递给a形参的内容 // 20是传递给b形参的内容 fn(10, 20) //当你需要修改本次函数内的 this 指向的时候 var arr = ['hello', 'world'] //也是在立即调用fn函数 //本次调用的时候,使用了call 把 fn 函数内的 this 强行修改成了arr // 100是传递纷a形参的内容 // 200是传递给b形参的内容 fn.call( arr,100,200)
// var obj = { name: ‘Jack’, age: 18 }
// 本次调用的时候,使用call 把fn函数内的 this强行修改成 了obj
// 1000 是传递给a形参的内容
// 2000是传递给b形参的内容
// fn.call(obj, 1000, 2000)// 假设我想修改 this指向,我是用了call 方法 //调用fn函数,使用calZ方法, 把fn雨数内的this 修改为了arr // '你好’是传递给 a 形参的内容 // '世界'是传递给 b 形参的内容 //相当于你在书写的时候,就把函数调用了 ,等到1000ms 以后,没有内容来执行了 //就是fn和fn()的区别 setTimeout(fn.call(arr, ' 你好','世界'),1000) // 1000ms 以后执行fn函数 setTimeout(fn, 1000 ) // 1000ms 以后执行fn函数的返回值 // setTimeout(fn(), 1000) var res=fn() setTimeout(res,1000) ``` 控制台输出内容: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210709173918858.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2VzdHJ1c0tpbmc=,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210709175505140.png)
-
-
apply()方法
-
使用方式:
函数名.apply()
对象名.函数名.apply() -
注意:
不要在事件处理函数和定时器处理函数时候使用
会立即调用函数 -
参数:
第一个:表示函数内的this 指向
第二个:是一个数组或者伪数组都行,里面的每一项是给函数传递的参数 -
特殊的使用方式:
改变一个函数的传递参数的方式// 2. apply() function fn(a, b) { console.group('函数fn内的打印' ) console.log('a ':, a) console.log('b ':, b) console.log( 'this:', this) console.groupEnd( ) } var arr = ['hello', 'world'] var obj = { name: 'Jack', age: 18 } //普通调用 fn(10, 20) //使用apply修改this指向 //本次调用的时候,使用apply 方法来进行调用的 // arr就是本次调用的时候,函数内的this指向 // [100, 200]是给fn传递参数使用的 //数组[0]也就是100是给a形参的内容 //数组[1]也就是200是给b形参的内容 fn.apply(arr, [100, 200]) //本次调用的挥手,使用apply 方法来进行调用的 // obj就是本次调用的时候,函数内的this指向 // [1000, 2000] 是给fn传递参数使用的 //数组[0]也就是1000是给a形参的内容 //数组[1]也就是2000 是给b形参的内容 fn. apply(obj, [1000, 2000]) //在定时器处理函数里面 //因为apply会立即调用函数 //那么就是在你书写的时候, 就已经把函数调用了,1000ms 以后就没有函数执行才 setTimeout(fn. apply(obj, ['你好', '世界']), 1000)
控制台输出内容:
// apply方法的特殊使用方式 //改变一个函数的传递参数的方式 //例子: Math.max() 方法 /* 在JS内有一个叫做Math 的对象 => 里面有一个叫做max的成员,是一个函数 Math = { max: function () {} } 语法: => Math.max(数字1, 数字2, 数字3,...) */ //本身 //注意:需要一个一个的传递参数, 判断多个参数内的最大值 var res = Math.max(10, 20, 30, 40, 33,23) console.log(res) //需求:判断数组里面的最大值 //就可以使用apply 方法来进行参数传递方式的改变 var a = [10,20,33,23,14,51,32] //var r2 = Math. max(a) //console.log(r2) //控制台输出 null //因为这次调用不是为了让你修改this 指向 //而是为了使用apply的传递给函数参数的方式 //此时a就是传递给Math. max函数的参数 // a[0]就是第一个参数 // a[1]就是第二个参数 var r2 = Math. max. apply(null, a) console.log(r2)
控制台输出内容:
-
-
bind()方法
-
使用方式:
函数名.bind()
对象名.函数名.bind() -
注意:
可以使用在定时器处理函数或者事件处理函数里面
不会立即调用函数
而是给一个返回值,返回一个新的函数 -
参数:
第一个:表示函数内的this 指向
第二个开始:表示传递给函数的实参
另一种,在使用bind 的时候,只传递一个参数,就是修改this 指向
当你调用返回值新函数的时候,在传递需要的实参 -
返回值:
是一个新的函数,把原始函数复制了一份一模一样的,只不过把里面的this锁定好了
不会立即调用函数// 3.bind() function fn(a, b) { console.group('函数fn内的打印' ) console.log('a ':, a) console.log('b ':, b) console.log( 'this:', this) console.groupEnd( ) } var arr = ['hello', 'world'] var obj = { name: 'Jack', age: 18 } console.log('fn : ',fn) //普通调用 // fn(10, 20) //使用bind 修改this 指向 //注意:本次没有调用fn函数 // bind的作用只是复制了一份fn函数 //把复制的这份fn函数里面的this锁定为了obj // 100是传递给a形参的内容 // 200 是传递给b形参的内容 // 把复制好的新函数作为 I返回值 // res接受的就是一个锁定好了this指向的新函数 var res = fn.bind(obj, 100,200 ) console.log( 'res :' , res ) //当你调用res的时候,res 里面的this 就是obj 了 res( ) // t经被锁死的this指向,还能不能通过call 再次修改? res.call(arr)
// bind的作用只是复制了一份fn函数 //把复制的这份fn函数里面的this锁定为了arr // 1000 是传递给a形参的内容 // 2000 是传递给b形参的内容 //把复制好的新函数作为了返回值 // r2接受的就是一个锁定好了this指向的新函数 var r2 = fn.bind(arr, 1000, 2000 ) r2( )
控制台输出内容:
参数另一种// bind的作用只是复制了一份fn函数 //把复制的这份fn函数里面的this 锁定为了arr //使用bind的时候,只是锁定this, 不锁定形参 //把复制好的新函数作为了返回值 // r2接受的就是个锁定好 了this指向的新函 数 var r2 = fn. bind( arr) //将来调用的时候,this 是锁定好的,形参可以根据需求来实时填入 r2( '你好','世界') r2( ' hello', 'world')
控制台输出内容:
//问题:如果我使用bind的时候,和调用返回值函数的时候都传递了实参,哪一个是真实的? //因为bind就是在锁定一系列内容,this和形参 //如果你在使用bind的时候,就给该函数传递I内容,那么参数值就被锁定了 //本次的调用-共锁定了三个内容 // fn函数内的this 被锁定为了obj // fn函数的a形参的值被锁定为了”你好' // fn函数的b形参的值被锁定为了'世界’ var res = fn.bind(obj, '你好','世界') res( ) //锁定以后,形参就不能再被修改了 res( 'hello', 'world' ) //锁定以后,this 也不能再被修改了 res. call(arr)
-