转眼前端的学习已有一年,平常写代码中常常碰到this这个东西。特别是在用vue的时候,this仍是有点多的,哈哈。
在翻阅了一部分书籍和一堆大佬的博客后,决定总结一下这些东西,下面谈谈我对this的一些理解,若是有错误,欢迎你们批评指正。若是能够给你带来一些帮助,那是再好不过的了。前端
this是在运行时基于函数的执行环境绑定的,它的上下文取决于函数调用时的各类条件。
当一个函数被调用时,会建立一个活动记录(有时候也称执行上下文)。这个记录会包含函数在哪里被调用,函数的调用方法、出今年入的参数等信息。this就是记录其中一个属性,会在函数执行的过程当中用到 --你不知道的JavaScript(上)
var name = 'window' const obj1 = { name:'obj1', fn(){ console.log(this.name) } } obj1.fn()//'obj1'
var name = 'window' const obj1 = { name:'obj1', fn(){ // "use strict" console.log(this.name) } } const obj2 = { name:'obj2', fn2:obj1.fn } obj2.fn2()//'obj2' obj1.fn()//'obj1'
#this的绑定与函数声明的位置没有声明的位置没有任何关系,只取决于函数的调用方式
#通常来讲,谁最终调用了函数,那么它就是this的绑定对象。
那在全局下调用函数,this的绑定对象也就是全局对象vue
var name = 'window' function fn(){ console.log(this.name) } fn()//'window'
下面这种状况为何不是输出window呢?es6
var name = 'window' function fn(){ this.name = 'fn' console.log(this.name) } fn()// 'fn'
也是由于在全局调用这个函数的时候,this.name === window.name就把以前的值给覆盖了,因此输出就是 'fn'。app
var name = 'window' const obj1 = { name:'obj1', fn(){ // "use strict" console.log(this.name) } } const obj2 = { name:'obj2', fn2:obj1.fn } obj2.fn2()//'obj2' obj1.fn()//'obj1'
仍是按照上面的代码为例,这里函数
obj2.fn2()//彻底等价于下面的 obj2.fn2.call(obj2) obj1.fn() 等于 obj1.fn.call(obj1)
一样的学习
var name = 'window' function fn(){ this.name = 'fn' console.log(this.name) } fn() 等于 fn.call()
var name = 'window' function fn(){ 'use strict' //为函数开启严格模式 this.name = 'fn' console.log(this.name) } fn() //则会报错,这也一样说明了函数在js内部调用的形式
改改前面的代码this
var name = 'window' const obj1 = { name:'obj1', fn(){ this.name = 'fn' function inFn(){ console.log(this.name) } inFn() } } obj1.fn()//'window '
上面的inFn()也等同于inFn.call(),在全局调用它,天然也就是输出window了。code
var name = 'window' const obj1 = { name:'obj1', fn(){ this.name = 'fn' inFn= ()=>{ console.log(this.name) } inFn() } } obj1.fn()//'fn'
它的this就是上一层第一个包裹它的普通函数的this
因此用call/bind/apply调用箭头函数的时候,是没有效果的。对象
var name = 'window' const obj1 = { name:'obj1', fn(){ this.name = 'fn' inFn= ()=>{ console.log(this.name) } inFn() } } obj1.fn.call(window)//'fn'
这也是为何在es6后,诸如_this=this这类写愈来愈少的缘由ip
setTimeout()调用的代码运行在与所在函数彻底分离的执行环境上。这会致使,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined,这和所指望的this的值是不同的。--MDN
备注:在严格模式下,setTimeout( )的回调函数里面的this仍然默认指向window对象, 并非undefined
this.name = 'window' function Foo(){ this.name = 'Foo' this.fn = function(){ console.log(this.name) } this.timer = function(){ setTimeout(this.fn) } } var obj = new Foo() obj.timer()//'window'
可使用call/apply/bind调用改变this绑定对象。
this.name = 'window' function Foo(){ this.name = 'Foo' this.fn = function(){ console.log(this.name) } this.timer = function(){ setTimeout(this.fn.call(this)) } } var obj = new Foo() obj.timer()//'Foo'
还有箭头函数
this.name = 'window' const obj = { name:'obj', fn(){ console.log(1) setTimeout(()=>{ console.log(this.name) },1000) } } obj.fn()//'obj'
this.name = 'window' function Foo(){ this.name = 'Foo' this.fn = function(){ console.log(this.name) } this.timer = function(){ setTimeout(this.fn) } } var obj = new Foo() obj.timer() //'window'定时器
1.箭头函数
function Foo(){ this.name='Foo' this.fn = ()=>{ console.log(this.name) } } var foo = new Foo() this.name = 'window' //设置一下window.name的值 foo.fn() //'Foo' 输出的是实例变量 console.log(this.name)//'window' 并无改变window.name的值
2.call/bind/apply
this.name = 'window' function Foo(){ this.name='Foo' this.fn = ()=>{ console.log(this.name) } } var foo = new Foo() foo.fn.call(window)//'Foo' const tes = foo.fn.bind(window) tes() //'Foo'
##也就是说判断一个运行中的this绑定,就要找到这个函数的直接调用位置。 ##按照上面介绍的优先级顺序进行判断即可以找到this的绑定对象。