资讯专栏INFORMATION COLUMN

this是什么以及如何判断它

Freelander / 1932人阅读

摘要:这也是为什么在后,诸如这类写越来越少的原因定时器对的影响调用的代码运行在与所在函数完全分离的执行环境上。

总结下对this的学习与理解

转眼前端的学习已有一年,日常写代码中经常碰到this这个东西。特别是在用vue的时候,this还是有点多的,哈哈。
在翻阅了一部分书籍和一堆大佬的博客后,决定总结一下这些东西,下面谈谈我对this的一些理解,如果有错误,欢迎大家批评指正。如果可以给你带来一些帮助,那是再好不过的了。

1.什么是this
this是在运行时基于函数的执行环境绑定的,它的上下文取决于函数调用时的各种条件。
当一个函数被调用时,会创建一个活动记录(有时候也称执行上下文)。这个记录会包含函数在哪里被调用,函数的调用方法、出今年入的参数等信息。this就是记录其中一个属性,会在函数执行的过程中用到 --你不知道的JavaScript(上)
this实际上是在函数被调用时发生的绑定 2 如何判断this绑定的对象是什么
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的绑定对象也就是全局对象

var name = "window"
function fn(){
 
  console.log(this.name)
}
fn()//"window"

下面这种情况为什么不是输出window呢?

var name = "window"
function fn(){
 this.name = "fn"
  console.log(this.name)
}
fn()// "fn"

也是因为在全局调用这个函数的时候,this.name === window.name就把之前的值给覆盖了,所以输出就是 "fn"。

3. 那么如何判断最终是谁调用了函数 函数调用的形式
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()
这里面call不传入参数,既为undefined。在非严格模式下传入undefined和null,都默认是window。
 
var name = "window"
function fn(){
  "use strict" //为函数开启严格模式
 this.name = "fn"
  console.log(this.name)
}
fn() //则会报错,这也同样说明了函数在js内部调用的形式

改改前面的代码

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了。

关于箭头函数和定时器 首先箭头函数是没有this的 ,它的作用域是和父级的上下文绑定在一起的
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这类写越来越少的原因

定时器对this的影响
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"

也就是说从优先级上说,有箭头函数和定时器就不判断是否由call/apply/bind调用 new对this的影响 new的优先级很高,在没有定时器影响的情况下是最高的
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"定时器

只要是由new调用的,就绑定到新创建的对象,其他情况似乎都无法再改变this绑定的对象。

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的绑定对象。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101847.html

相关文章

  • 前端基础进阶(十一):详细图解jQuery对象,以及如何扩展jQuery插件

    摘要:而在构造函数中,返回了的实例对象。在中直接返回过的实例,这里的是的真正构造函数最后对外暴露入口时,将字符与对等起来。因此当我们直接使用创建一个对象时,实际上是创建了一个的实例,这里的正真构造函数是原型中的方法。 showImg(https://segmentfault.com/img/remote/1460000008749398); 早几年学习前端,大家都非常热衷于研究jQuery源...

    RebeccaZhong 评论0 收藏0
  • 前端面试题收集,持续更新中

    摘要:对于所访问的每个元素,函数应该将该元素传递给所提供的回调函数。 HTML 在线阅读Github地址 题目列表 HTML HTML和XHTML的区别 Html的语义化 Doctype的文档类型 cookie、sessionSttorage、localStory区别 HTML全局属性(global attribute)有哪些? 常见的浏览器内核有哪些? 介绍一下你对浏览器内核的理解?...

    kgbook 评论0 收藏0
  • 前端面试题收集,持续更新中

    摘要:对于所访问的每个元素,函数应该将该元素传递给所提供的回调函数。 HTML 在线阅读Github地址 题目列表 HTML HTML和XHTML的区别 Html的语义化 Doctype的文档类型 cookie、sessionSttorage、localStory区别 HTML全局属性(global attribute)有哪些? 常见的浏览器内核有哪些? 介绍一下你对浏览器内核的理解?...

    2json 评论0 收藏0
  • 前端面试题收集,持续更新中

    摘要:对于所访问的每个元素,函数应该将该元素传递给所提供的回调函数。 HTML 在线阅读Github地址 题目列表 HTML HTML和XHTML的区别 Html的语义化 Doctype的文档类型 cookie、sessionSttorage、localStory区别 HTML全局属性(global attribute)有哪些? 常见的浏览器内核有哪些? 介绍一下你对浏览器内核的理解?...

    adam1q84 评论0 收藏0
  • 2019前端面试那些事儿

    摘要:虽然今年没有换工作的打算但为了跟上时代的脚步还是忍不住整理了一份最新前端知识点知识点汇总新特性,语义化浏览器的标准模式和怪异模式和的区别使用的好处标签废弃的标签,和一些定位写法放置位置和原因什么是渐进式渲染模板语言原理盒模型,新特性,伪 虽然今年没有换工作的打算 但为了跟上时代的脚步 还是忍不住整理了一份最新前端知识点 知识点汇总1.HTMLHTML5新特性,语义化浏览器的标准模式和怪...

    JeOam 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<