好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

JavaScript this

JavaScript this

当前执行 代码 的环境对象,在非严格模式下,总是指向 一个 对象,在严格模式下可以是任意值。(MDN)

this 指向的是当前的 代码 上下文环境,所以不同情况下的 this 指向也不同。

1. 全局下的 this

在全局环境下, this 指向全局对象。

全局对象和宿主环境相关,在浏览器下,全局对象就是 window 对象,在 node.js 中,全局对象是 global 对象。

 window  ===   this  ;   //  输出 :true 
 

新的标准提供了 globalThis 关键字来 获取 全局对象,这样就能抹平宿主的差异来操作处理全局对象了。

2. 函数 中的 this

函数 在不同情况下,其 this 的指向也不同。

2.1 对象下的 方法

方法 也是 一个 函数 ,如果通过对象 调用 一个 函数 , 函数 的 this 就会指向这个对象。

  var  person  =   { 
  age :   , 
  name :   '鸽子王'  , 
  skill :   '放鸽子'  , 
  say :   function  (  )   { 
    console .  log  (  '来一段自我介绍:'  )  ; 
    console .  log  (  '我是'   +   this  . name )  ; 
    console .  log  (  '我今年'   +   this  . age  +   '岁'  )  ; 
    console .  log  (  '我最擅长'   +   this  . skill )  ; 
   }  , 
 }  ; 

person .  say  (  )  ; 
 

say 函数 作为对象下的 方法 ,在被 调用 后,其 this 指向的是他所在的对象, 在这里 就是 person 对象。

2.2 原型链上 方法 的 this

原型链上的 方法 ,this 指向的也是 调用 该 方法 的对象。

  var  __proto__  =   { 
  sum :   function  (  )   { 
     return   this  . number1  +   this  . number2 ; 
   }  , 
 }  ; 

 var  object  =  Object .  create  ( __proto__ )  ; 

object . number1  =   ; 
object . number2  =   ; 

console .  log  ( 
  object .  sum  (  )  , 
 )  ;   //  输出 :3 
 

Object.create 做就就是将参数作为原型,创建 一个 对象。

所以 object 的第一原型就是 __proto__ 对象。

number1 和 number2 都是 object 变量的 属性 ,但却可以被 sum 方法 中的 this 访问到,所以在原型链的 方法 中,this 指向的就是 调用 该 方法 的对象。

2.3 getter / setter 下的 this

getter 和 setter 下的 this 也会指向 调用 该 getter 和 setter 的对象。

  var  object  =   { 
  _name :   '鸽子王'  , 

   get   name  (  )   { 
     return   this  . _name ; 
   }  , 

   set   name  ( val )   { 
    console .  log  ( val )  ; 
     this  . _name  =  val ; 
   } 
 }  ; 

console .  log  ( object . name )  ;   //  输出 :鸽子王 

object . name  =   '鸽子天王'  ;   //  输出 :鸽子天王 

console .  log  ( object . name )  ;   //  输出 :鸽子天王 
 

getter 和 setter 本质上也可以理解成两个 函数 ,作为对象下的 函数 ,在 调用 的时候 this 也会指向该对象。

2.4 作为 DOM 节点的事件处理器

作为 DOM 节点的事件处理器的时, 函数 的 this 会指向这个 DOM 对象。

    < div  >  
     < button  >  点击我   </ button  >  
   </ div  >  

   < script  >   
  document .  querySelector  (  'button'  )  .  addEventListener  (  'click'  ,   function  (  )   { 
     this  . innerHTML  =   '被点击了!'  ; 
   }  )  ; 
    </ script  >  
 

2.5 作为 一个 内联的事件处理器

内联的事件处理器,其 this 指向的是 DOM 节点自身。

  < div > 
   < button onclick =  "console.log(this); console.log(this === document.querySelector('button'))"  > 点击我 <  / button > 
 <  / div > 
 

这个规则有局限性,只有最外层的 this 符合这个规则。

  < div > 
   < button onclick =  "function  test()  { console.log(this) };  test() ;"  > 点击我 <  / button > 
 <  / div > 
 

test 函数 的 this 指向的是全局对象 window 。

2.6 其他大部分情况下

排开上述的几个情况,剩下的 函数 大部分情况下在 调用 时,this 指向的是全局对象,在浏览器中就是 window 对象。

  function   fn  (  )   { 
  console .  log  (  this  )  ; 

  console .  log  (  this   ===  window )  ; 
 } 

 fn  (  )  ; 
 

这样 调用 函数 ,其 this 指向的就是 window 对象了。

有的时候可能会搞混以下情况:

  var  object  =   { 
  username :   '咸鱼'  , 
  fn :   function  (  )   { 
    console .  log  (  this  . username )  ; 

     function   thisTest  (  )   { 
      console .  log  (  this  . username )  ; 

      console .  log  (  this   ===  window )  ; 
     } 

     thisTest  (  )  ; 
   }  , 
 }  ; 

object .  fn  (  )  ; 
 

这里 thisTest 方法 输出 的 username 就会是个 undefined,因为他的 this 指向的是 window,因为他不属于 object 对象的 一个 方法 ,所以 this 就指向了 window。

在回调 函数 中经常会碰到这个问题:

  var  info  =   { 
  account :   '123'  , 
  password :   '456'  , 
  login :   function  ( cb )   { 
     setTimeout  (  function  (  )   { 
       cb  (  { 
        account :   this  . account , 
        password :   this  . password , 
       }  )  ; 
     }  ,   )  ; 
   } 
 }  ; 

info .  login  (  function  ( info )   { 
  console .  log  ( info )  ; 
 }  )  ; 
 

这里回调 函数 获取 的账号和密码是 undefined ,原因就是 this 的指向问题。

通常会使用保留上层 this 的方式 解决 这个问题。

  var  info  =   { 
  account :   '123'  , 
  password :   '456'  , 
  login :   function  ( cb )   { 
     var  _this  =   this  ; 

     setTimeout  (  function  (  )   { 
       cb  (  { 
        account :  _this . account , 
        password :  _this . password , 
       }  )  ; 
     }  ,   )  ; 
   } 
 }  ; 

info .  login  (  function  ( info )   { 
  console .  log  ( info )  ; 
 }  )  ; 
 

这样就能 解决 这个问题。

另外 一个 情况也很容易混淆 this :

  var  object  =   { 
  user :   'no.1'  , 
  say :   function  (  )   { 
    console .  log  (  this  . user )  ; 
   }  , 
 }  ; 

 var  say  =  object . say ; 

object .  say  (  )  ;   //  输出 :"no.1" 
 say  (  )  ;   //  输出 :undefined 
 

这是因为把 object 下的 say 方法 单独赋值给 say 变量的时候,其就作为了 window 下的 一个 方法 ,所以他的 this 指向的是 window。

在严格模式中,这种情况下的 this 会变成 undefined 。

2.7 构造 函数

在 JavaScript 构造 函数 也被成为 对象构造器 ,用于产生对象。

构造 函数 的声明和普通 函数 几乎没有区别:

  function   Point  ( x ,  y )   { 
   this  . x  =  x ; 
   this  . y  =  y ; 
 } 

 var  point  =   new   Point  (  ,   )  ; 

console .  log  ( point . x )  ;   //  输出 :1 
console .  log  ( point . y )  ;   //  输出 :2 
 

构造 函数 使用 new 关键字来构造对象。所以当 一个 函数 被使用 new 关键字 调用 时,这个 函数 就会作为 一个 构造 函数 。

在 一个 构造 函数 被 调用 后,其内部的 this 会指向 一个 对象,具体的 内容 可以参考 构造 函数 章节。

@H_803_1 404 @3. 修改 this

3.1 call 方法 和 apply 方法

函数 具有 call 方法 和 apply 方法 ,这两个 方法 可以在 调用 函数 的时候指定 函数 的 this。

  var  object  =   { 
  user :   'no.1'  , 
 }  ; 

 function   say  (  )   { 
  console .  log  (  this  . user )  ; 
 } 

 say  (  )  ;   //  输出 :undefined 
say .  call  ( object )  ;   //  输出 :"no.1" 
say .  apply  ( object )  ;   //  输出 :"no.1" 
 

通过 call 和 apply 方法 将 say 函数 执行时候的 this 设置为 object 对象。

call 方法 从第二个参数开始,表示是要传递给当前 函数 的参数。

  var  object  =   { 
  user :   'no.1'  , 
 }  ; 

 function   fn  ( arg1 ,  arg2 ,  arg3 )   { 
  console .  log  ( 
     this  , 
    arg1 , 
    arg2 , 
    arg3 , 
   )  ; 
 } 

fn .  call  ( object ,   ,   ,   )  ; 
 

apply 的第二个参数是个数组,数组里面的项会按数组的顺序作为参数传递给 函数 。

  var  object  =   { 
  user :   'no.1'  , 
 }  ; 

 function   fn  (  )   { 
  console .  log  ( 
     this  , 
    arguments , 
   )  ; 
 } 

fn .  apply  ( object ,   [  ,   ,   ]  )  ; 
 

通过 arguments 关键字就可以看到当前 函数 的参数,通常在需要 修改 this ,又不确定参数的情况下,会使用 apply 来 修改 this。

3.2 bind

bind 方法 用于给 一个 函数 永久绑定 一个 指定的 this,bind 不会 修改 原 函数 ,会返回 一个 新的 函数 。

  var  obj1  =   {  value :   '今天打砖'   }  ; 
 var  obj2  =   {  value :   '明天打转'   }  ; 

 var   fn   =   function  (  )   { 
  console .  log  (  this  )  ; 
 }  ; 

 var  bindFn1  =  fn .  bind  ( obj1 ) 
 var  bindFn2  =  bindFn1 .  bind  ( obj2 )  ; 

 bindFn1  (  )  ; 
 bindFn2  (  )  ; 
 

可以看到 bindFn1 被绑定了 obj1 作为 this,之后不论怎么操作,他的 this 都会是 obj1 。

bind 还有更多灵活的 用法 ,参数也可以绑定,有关 bind、call、apply 这三个 方法 的更详细的信息可以查阅对应的文档。

4. 小结

理解好 this 的处理机制可以设计出更加完善的 JavaScript 应用程序。

this 在 ES6 的箭头 函数 中的表现也有所不同,可以查阅 ES6 中有关箭头 函数 的 内容 。

严格模式 ? ?JavaScript instanceof

查看更多关于JavaScript this的详细内容...

  阅读:31次

上一篇

下一篇

第1节:什么是 JavaScript    第2节:学习环境准备    第3节:调试方案    第4节:JavaScript 变量    第5节:JavaScript 数据类型    第6节:JavaScript if 语句    第7节:for 语句    第8节:JavaScript 算数运算符    第9节:JavaScript 比较运算符    第10节:JavaScript 逻辑运算符    第11节:JavaScript 函数    第12节:JavaScript 表达式    第13节:JavaScript 对象    第14节:JavaScript 字符串    第15节:JavaScript 数字    第16节:JavaScript 数组    第17节:JavaScript switch 语句    第18节:JavaScript while 语句    第19节:JavaScript 的 break 与 continue    第20节:JavaScript with    第21节:document.cookie    第22节:JavaScript Function    第23节:JavaScript Math    第24节:JavaScript Date    第25节:JavaScript RegExp    第26节:JavaScript JSON    第27节:什么是 DOM    第28节:DOM 和 JavaScript 的关系    第29节:获取和操作 DOM 节点    第30节:DOM 与事件    第31节:DOM 事件绑定    第32节:DOM 事件对象    第33节:DOM 事件流    第34节:事件相关的优化    第35节:自定义事件    第36节:表单校验    第37节:什么是 BOM    第38节:常用的 BOM 相关对象    第39节:BOM 常用属性和方法    第40节:AJAX    第41节:异常处理    第42节:三元运算符    第43节:逗号操作符    第44节:void    第45节:typeof    第46节:delete 操作符    第47节:debugger    第48节:getter & setter    第49节:new 运算符与构造函数    第50节:JavaScript 原型    第51节:JavaScript instanceof    第52节:JavaScript this    第53节:严格模式    第54节:作用域    第55节:闭包    第56节:变量提升    第57节:对象包装器    第58节:Lodash    第59节:moment    第60节:swiper    第61节:ECMAScript 6    第62节:Node.js    第63节:Babel    第64节:CSS 预处理器    第65节:代码规范    第66节:TypeScript    第67节:WebComponents    第68节:Vue、React、Angular    第69节:小程序    第70节:JavaScript 关键字    第71节:分号导致的问题    第72节:对象属性访问问题    第73节:this 使用问题    第74节:浮点数精度问题    第75节:独一无二的 NaN    第76节:避免全局污染    第77节:控制台观察对象问题    第78节:根据环境选择语言特性    第79节:相关资源