this
全局上下文
-
在函数体外部,this永远指向全局对象window;
-
<script> console.log('this',this) // Window </script>
函数上下文
谁调用指向谁–在函数中,谁调用函数,函数体内部的this指向谁;
[1]全局环境下的函数
全局变量(使用var定义的)都是相当于window对象的属性,全局函数都是相当于window的方法
;
<script>
function fn1 () {
console.log(this) // 谁调用指向谁---window
}
fn1() //相当于window.fn1(),省略了window;
</script>
function fn1 () {
'use strict'
console.log(this) // 谁调用指向谁---undefined
}
fn1() //在严格模式下,fn1相当于直接被调用的,而不是作为对象的属性被调用的,因此值为undefiend
[2]定时器中的函数
-
定时器是在倒计时结束后
直接调用
函数,因此 若是函数为普通函数,函数体中的this指向window, 若是函数为箭头函数,函数体中的this通过作用域寻找上一级的this指向<script> function fn1 () { console.log(this) // 谁调用指向谁---window } setTimeout(fn1, 1000) </script>
-
2.定时器中的函数若是箭头函数,this指向上一级的this;
[3]对象中的方法
let obj = {
name: 'chaochao',
sex: '女',
say: function () {
console.log(this)
}
}
obj.say() // obj
let say = obj.say
say() // window
- 函数中的this -> 谁调用指向谁
- obj.say() 是对象obj调用,因此函数体内部的this指向obj
- say() 是直接调用,因此函数体内部的this指向window
易错点
-
1.若是使用var声明的全局变量是赋值给window作为属性,但是若使用let声明的变量并没有添加为window的属性;
-
2.window有一个默认的name属性,属性值为undefiend;
-
题目一
<script> var name = '123' // 3.使用var定义变量添加为window属性了,覆盖了原有的window的name属性 var obj = { name: '456', say: function () { console.log(this.name) //2.相当于window.name----123 } } var fun = obj.say fun() //1.调用fun函数,window调用的this指向window </script>
-
题目二
<script> let name = '123' // 3.使用let定义变量并没有添加为window属性,window.name='' var obj = { name: '456', say: function () { console.log(this.name) //2.相当于window.name----'' } } var fun = obj.say fun() //1.调用fun函数,window调用的this指向window </script>
-
题目三
<script> var name = 'tom' var obj = { name: 'zhar', say: function () { return function () { console.log(this.name) //window.name='tom' } } } obj.say()() // 分为两步 // 1.obj.say()---结果为 function(){console.log(this.name)}函数 // 2.调用这个函数,相当于是window屌用的 </script>
[4]构造函数的this
-
使用new关键字调用的函数被称为构造函数,new关键字可以修改函数的this指向;
-
构造函数new关键字的作用
- 1.使用字面量创建对象
- 2.将this指向修改为当前创建的对象
- 3.使用this进行赋值
- 4.返回这个this
-
因此构造函数的this指向的是实例化对象;
-
举例说明
<script> function Person (name) { this.name = name } var p1 = new Person('zhangsan') console.log(p1.name) // 因为new关键字修改了this指向,所以p1.name相当于构造函数中的this.name----'zhangsan' </script>
[5]es6中箭头函数的this
-
个人见解:箭头函数没有this指向,其本质是通过作用域链获取上一级的this指向;
-
因此:
- 1.箭头函数的this指向无法修改(使用上下文模式也无法修改箭头函数的tihs指向)
- 2.箭头函数不能通过new关键字调用,因为new关键字可以修改this指向;
- 3.DOM操作不适合使用箭头函数,因为this不会随着点击元素而改变
-
第一题
<script> let obj = { name: '好开心', eat () { let fn1 = function () { console.log(this) // window } fn1() let fn2 = () => { console.log(this) // obj } fn2() }, play: () => { let fn1 = function () { console.log(this) // window } fn1() let fn2 = () => { console.log(this) // window } fn2() } } obj.eat() obj.play() </script>
-
第二道
<script> function Person1 () { this.age = 0 setTimeout(function () { console.log(this.age) }, 1000) } var p = Person1() let person2 = () => { this.age = 10 setTimeout(() => { console.log(this.age) }, 1000) } var p = Person2() </script>
[6]vue实例化的对象中方法的this指向
1.vue中事件处理函数的this指向
- 若函数是普通函数
- 事件处理函数中的this指向的是
vue实例化对象
; - 原因:在vue实例化对象中将methods中的方法平铺在了自己身上,所以methods中的方法实际是vue实例化对象的方法;
- 事件处理函数中的this指向的是
- 若为箭头函数
- 事件处理函数的this指向的是
Window(一般情况下)
; - 原因:他的上一级是0;
- 因此不建议在vue中使用箭头函数;
- 事件处理函数的this指向的是
[7]react实例化对象中的this指向
class Mycomponent extend React.Component{
render(){
// render函数是实例化对象调用 -> this指向实例化对象
}
fun(){
// 普通函数在事件被触发时是直接调用 -> this指向windwo
}
}
- 推荐在react中使用箭头函数
[8]Dom事件中的this指向
给谁设置的事件this就指向谁;点击谁e.target就指向谁
-
一般情况下,this与e.target是相等的
<button>按钮</button> <script> document.getElementsByTagName('button')[0].onclick = function () { console.log(this.innerHTML) // 按钮 // this指的是触发事件的DOM元素本身 } </script>
-
特例:给ul设置点击事件,点击li—> this指向的是ul, e.target指的是li元素!
- 案例:ul>n个li,点击li元素输出li元素的标签间的文本内容
-
方案:比较高效,只需要设置一个点击事件!
<script> let ul = document.getElementById('ul') ul.onclick = function (e) { // 点击li元素,利用元素冒泡,会触发父元素的点击事件 console.log(e.target.innerHTML) } </script>
修改this指向
[1]上下文模式修改this指向
作用:修改函数中this的指向;
注:修改后的this值只能是复杂数据类型—函数,对象,数组;
若修改为简单数据类型
- string number boolean基本包装类型
- undefined null–转换失败,保留原来的this指向
- Symbol ----修改成功
[1]call方法
- 语法:函数.call(函数修改后的this指向,参数1,参数2)
- 特点
- (1)修改了函数this的指向
- (2)修改的同时调用了此函数
- (3)返回值为调用函数的得到的值
[2]apply方法
- 语法:函数.apply(函数修改后的this指向,数组/伪数组)
- 特点
- (1)修改了函数this的指向
- (2)修改的同时调用了此函数
- (3)apply方法传值可以传入1个数组,并且可以自动遍历这个数组作为参数
- (4)返回值为调用函数的得到的值
[3]bind方法
- 语法:函数.bind(函数修改后的this指向,参数)
- 特点
- (1)修改了函数this的指向
- (2)没有调用此函数,并返回一个新的函数(该函数被修改了this指向的函数)
- (3)若是传递了参数,以后在调用该函数时传递的函数不起作用,只能是此传递的参数;若是bind没有传递参数,以后调用时可以传递参数
案例
封装函数 bindThis,使 f 的 this 指向指定的对象
-
bind并不会调用此函数,而是返回一个修改了this指向的函数
-
此时得到的是f函数将this修改为oTarget后的函数;
function bindThis(f, oTarget) { return f.bind(oTarget); } let editThis=bindThis(f, oTarget)
-
-
举例说明
<script> // 封装函数,修改f的tihs指向为obj function editThis (fn, obj) { return fn.bind(obj) } function fn () { console.log(this) } let obj = {} let newFn = editThis(fn, obj) newFn() </script>