关于JavaScript的this

  this这个概念在很多流行语言里都有,大家的定义都很一致,也就是运行时的实例本身,但是在JavaScript这里就不一样了。this是函数里的当前引用(全部代码你可以看成是在宿主对象window下的一个大匿名函数里,就像require的实现那样),有一种说法是JavaScript里的this是调用者对象,但这个并不贴切。比如下面的代码:
     
var  o  =  { } ;
o . f  =  function ( )  {
     var  ff  =  function ( )  {
         console . log ( this ) ;
     } ;
     ff ( ) ;
     console . log ( this ) ;
} ;
o . f ( ) ;  // window   &  o 
         
变量ff不是全局变量,执行环境是在o.f里面,一定要理解成ff()调用者是window,下面一句又回到o调用,这个也太别扭了。那么我们应该如何理顺这种关系呢?
  首先, 在JavaScript的运行时里,一切存在单位皆是对象(实例)。这些对象不是孤立存在的,它们之间有两种类型的关系。一类是对象能力的回溯关系(原型链);一类是对象引用的组织关系(对象属性),也就是摆放在哪儿。而this指向的正是其摆放位置对象。比如上例中的f在对象o里,里面的this就是o。o和ff没有明确指定摆放位置,在标准模式下它们会被摆放在宿主对象window里,this自然就是window了。那如果我们执行如下代码会怎么样呢:
 
var  of  =  o . f ;
of ( ) ;  // window  &  window
 of和o.f是同一个函数的两个引用,这里可以看出this即是引用位置对象。 继续代码:  
 
o . oo  =  {
     g :  function ( )  {
         console . log ( this ) ;
     }
} ;
o . oo . g ( ) ;  // o.oo 
不用解释了吧。继续代码:
 
var  f1  =  function ( )  {
     console . log ( this ) ;
} ;
var  o1  =  new  f1 ( ) ;  // f1 
这个怎么理解呢?我们把引擎的动作用如下的伪代码描述:
//  
var  f1  =  function ( )  {
     console . log ( this ) ;
} ;
var  o1  =  { } ;
o1 . __proto__  =  {
     constructor :  f1
} ;
o1 . constructor ( ) ;
不用解释了吧。继续代码: 
       
o . f2  =  function ( )  {
     var  ff  =  ( )  =>  {
         console . log ( this ) ;
     } ;
     ff ( ) ;
     console . log ( this ) ;
} ;
o . f2 ( ) ;  //     o
 Why? 这个o.f2和之前的o.f的区别就是把函数的书写形式变了一下,箭头函数里输出的为什么不是window呢?“箭头函数”的学名叫lambda表达式(lambda expression),它像函数一样拥有一个独立的作用域,但是并不具备函数的各种特性。所以箭头函数里的this也就等同于此“函数”所在位置的this。OK,继续code:
   
o . oo . g1  =  function ( )  {
     setTimeout ( this . g ,  1000 ) ;  // call o.oo.g()
} ;
o . oo . g1 ( ) ;  // window
 这里不会像直接执行o.oo.g()那样打印o.oo对象了,因为setTimeout向宿主环境(window)注册了一个执行体函数,window会把这个执行体保存在自己的一个匿名属性里,将来由宿主对象执行时打印的就是window。但是下面这个定时器又不一样了:
 
o . oo . g2  =  function ( )  {
     console . log ( this ) ;
     setTimeout (( ) => {  console . log ( this ) ;  } ,  1000 ) ;
} ;
o . oo . g2 ( ) ;  //  o.oo 
 这个定时器执行的时候为什么 不是打印window呢?前书说过,lambda表达式不具备函数特性,也不存在自己的this,这里这个this其实是因为闭包特性顺带过来的。如有疑问可以换一个普通变量看看即知。

  诸如call、apply、bind这些都是人工指定this,当然您指啥就是啥。如果指定对象是undefine或者null之类,则仍然遵守前述规则指向宿主对象window(正常模式)。
 
总结:
一、以上论述纯属推断,并未参考源代码的实际实现。因此如有雷同,纯属巧合呲牙  。我们从正向和反向看待同一个事物的时候,有时能看到不同的东西。
二、以上推断出于技术研究的动机,若出于实用目的,我认为可以用更加常规的代码组织方式,并不必要把这些东西剥得这么清楚。就如同我们想写一封信,并不需要会写四种“回”字。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值