理解JavaScript普通函数以及箭头函数里使用的this

this

普通函数的this

普通函数的this是由动态作用域决定,它总指向于它的直接调用者。具体可以分为以下四项:

  1. this总是指向它的直接调用者, 例如 obj.func() ,那么func()里的this指的是obj。
  2. 在默认情况(非严格模式,未使用 'use strict'),如果函数没有直接调用者,this为window
  3. 在严格模式下,如果函数没有直接调者,this为undefined
  4. 使用call,apply,bind绑定的,this指的是绑定的对象

箭头函数的this

箭头函数是没有绑定自己的this,函数内使用的this是由静态作用域(也成为词法作用域,参考this)决定。静态作用域就是说箭头函数里this是由定义它的代码决定,而不是执行调用箭头函数的代码。

上面的说法有时很难理解,我自己总结的方法是:找出定义箭头函数的上下文(即包含箭头函数最近的函数或者对象),那么上下文所处的父上下文即为this。具体可以参考箭头函数的示例。

普通函数示例

示例1:对象函数的this

var obj = {
  myfunc : function() {
    console.log(this);  
  }
}
obj.myfunc();

输出的是obj对象,this指的是obj。

示例2:全局函数的this

function myfunc() {
    console.log(this);
}
myfunc();

输出的是Window对象,this指的是Window

示例3:严格模式下全局函数的this

'use strict';
function myfunc() {
    console.log(this);
}
myfunc();

this为undefined,因为严格模式下,myfunc没有直接的调用者。

示例1-变形1:在obj.myfunc()方法里添加普通函数,并执行

var obj = {
  myfunc : function() {
    function innerfunc() {
     console.log(this);
    }
    innerfunc();
  }
}
obj.myfunc();

this指的是Window。这是因为innerfunc()函数执行时没有直接调用者,所有this为Window。

示例1-变形2:把obj.myfunc赋值给一个变量后调用

var obj = {
  myfunc : function() {
    console.log(this);  
  }
}
var f = obj.myfunc;
f();

this指的是Window。这是因为f()是没有直接调用者,在非严格模式下,this指的是Window。

箭头函数示例

示例5:函数内使用箭头函数

var obj = {
  myfunc : function(){
    var f = ()=>{
      console.log(this);
    }
    f();
  }
}
obj.myfunc();

this指的是obj。因为定义箭头函数的上下文为myfunc函数,myfunc函数所在的父上下文为obj。

示例6:箭头函数作为方法

var obj = {
  myfunc : ()=>{
    console.log(this);  
  }
}
obj.myfunc();

这个地方很容易误以为this指的是obj。其实this实际指的是window,因为定义箭头函数最近的上下文为obj对象(myfunc和箭头函数作为key-value的形式是平级),而obj对象的父上下文为window。

MDN web docs里说的,建议箭头函数仅用在非方法的函数(non-method function)里。

示例7:

var outeobj = {
   outfunc:function() {
     var obj = {
       myfunc : ()=>{
         console.log(this);  
       }
     }
     obj.myfunc();
   }
}

outeobj.outfunc();

为了和示例6做对比,现在把obj对象添加到outerobj的outfunc里。

this指的是outobj。这是因为箭头函数最近的上下文为obj对象,而obj对象的父上下文为outobj。

这是我对this的一点理解以及对箭头函数里使用this的总结,如果有误,敬请指出。

参考:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
https://medium.com/@reasoncode/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4
http://whatis.techtarget.com/definition/lexical-scoping-static-scoping

版权声明:著作权归作者所有。

相关推荐

Kotlin传递函数作为参数的方式

Kotlin传递函数作为参数,可以有:命名参数,位置参数以及在参数列表外,以lamba的形式传递。示例data class Person(val name: String,                &nb

ES6 函数使用解构赋值(Destructuring )的几点好处

解构赋值(Destructuring )是ES6新增的特性。使用解构赋值有以下几点好处:命名参数设置默认参数多个返回值命名参数在传统的函数定义如下:function findUsersByRole (   role,    withContactInfo,    includeInactive )&

Kotlin集合扩展函数 - 转换

Kotlin 集合类型提供了很多用于转换的扩展函数。这里需要指出示例里的intList为val intList: List<I­nt> = listOf(1, 2, 3) associate关联函数:使用转换函数把Array或Iterable转换为Map:数组fun <T, K, V> any_array

JavaScript Array map()函数的用法及误用

Array的map()函数作用是一个数组映射为另一个数组,映射方式是以原数组的元素作为输入,使用提供的回调函数对输入元素处理,处理后返回的结果作为新数组的元素。基本语法var new_array = arr.map(function callback(currentValue, index, array) {  &nb