登录

javascript关于this对象,在闭包函数中为什么会引用全局变量

# JavaScript
阿神阿神2172 天前842 次浏览

全部回复(14) 我要回复

  • 怪我咯

    怪我咯2017-04-11 13:30:38

    this是跟著函式呼叫而产生的,它的范围是以函式为界限,谁(某物件)呼叫了这个函式,谁(某物件)就是this,与函式是在全域定义或物件字面定义无关,与呼叫函式是谁才有关。总个来说明,作用域是静态的,但this的建立却是动态的。

    所以,像这个呼叫:

    object.getNameFunc()

    getNameFunc函式来说,this的确是object,也就是说当你的程式码改为下面的写法,就可以获得object.name,因为此时的this相当于object:

    var object = {
      name:'bb',
      getNameFunc2: function(){
        return this.name;
      }
    }
    
    console.log(object.getNameFunc2()); //bb

    当函式中没有明确的呼叫它的对象,在旧的情况下,this值默认为为window物件也就是全域物件,在新的标准中或是用严格模式(strict code)时,是undefined,刚上面说过this是以函式为界限。所以你在内部(巢状)函式里的下面这个函式呼叫,很明显的它的this值必然是默认情况:

    return function(){
           return this.name;
    }();

    你的结果会得到aa的值,是因为不在严格模式(strict code)下,如果在严格模式或较新式写法中,是会发生错误而无法得到值,因为呼叫者是undefined,也就是不存在。aa是属于全域变数,或是window物件中的变数值。

    而由于上面的这些知识,你可以利用内部(巢状)函式能够取得外部函式的变数作用域的特点,也就是闭包的特性,这种特性是因为作用域的连锁而来。进一步来修正内部函式的this值,所以可以用下面的解决方式,用一个中继的变数来转介外部函式的this值,下面的改写中的that并非一定要叫这个名称,有人喜好用self_that,实际上都行:

    var object = {
      name:'bb',
      getNameFunc: function(){
         var that = this
         return function(){
            return that.name;
         }();
      }
    }

    另一种改写方式是视情况使用函式的callbind,它们可以在第一个传参中使用一个物件,以此改变函式呼叫(或执行)的上下文,也就是this值。

    var object = {
      name:'bb',
      getNameFunc: function(){
         return function(){
            return this.name;
         }.call(this);
      }
    }

    由上面的实作可得知,内部函式的闭包结构,并不会传递外部函式的this值,因为this的设计是以函式为界限。提外话是,你可能也想知道函式的隐藏arguments物件会不会被传递,答案是当然也不会。

    最后,你可能不知道在物件里面可以呼叫物件本身,所以下面的写法也是可行的,但它与this无关,只是JavaScript里可以这样作而已:

    var object = {
      name:'bb',
      getNameFunc: function(){
         return function(){
            return object.name;
         }();
      }
    }

    你可以说他是个设计缺陷但它也存在几十年了,与其等待改变或直接放弃,不如先了解是什么。

    详细的内容可以参考小弟整理的ES6电子书,在gitbook上,繁体的供参考:

    闭包: https://eyesofkids.gitbooks.i...

    this: https://eyesofkids.gitbooks.i...

    回复
    0
  • 高洛峰

    高洛峰2017-04-11 13:30:38

    方法是谁调用的谁就是this。
    这个列子里面,object.getNameFunc()返回了一个自执行函数

    function(){
        return this.name;
    }()

    此时调用者为window,故this为window。

    回复
    0
  • 迷茫

    迷茫2017-04-11 13:30:38

    var object = {
      name:'bb',
      getNameFunc: function(){
         return: function(){
            return: this.name;
         }();
      }
    }

    分析一下作用域 全局中object -- > object里面的name/getNameFunc --> getNameFunc函数 -- > 返回函数的立即调用。

    object.getNameFunc()调用 ---- 返回一个函数的调用,独立函数调用会采用默认绑定规则绑定到全局作用域中

    推荐看《你不知道的js》里面有详细的介绍

    回复
    0
  • 巴扎黑

    巴扎黑2017-04-11 13:30:38

    这个问题,并不是说闭包函数的this一定指向全局,而是函数作用域的问题,一个匿名函数作为返回值,这个匿名函数在执行时已经脱离了原来的scope,作用域变为了全局,this自然指向全局。js中有很多这种情况,比如最常见的回调函数。

    回复
    0
  • 阿神

    阿神2017-04-11 13:30:38

    这与this是不是在闭包中没有直接关系的,this的指向取决于函数的执行环境,getNameFunc函数中的this指向是object,但是getNameFunc函数中的匿名函数是一个独立的执行环境,该匿名函数没有明确的调用者,所以默认执行环境是window

    关于闭包,闭包是可以访问外部作用域的变量,我认为题主所疑惑的是闭包里已经访问外部this,所以返回的应该是bb,但是this并不是一个变量,它会随着执行环境的变更而变更。

    回复
    0
  • 天蓬老师

    天蓬老师2017-04-11 13:30:38

    没明确定义在某个对象上的函数都是全局函数,隶属于全局对象。

    回复
    0
  • PHP中文网

    PHP中文网2017-04-11 13:30:38

    默认都是指向全局对象的,浏览器是window。
    你这个code应该

    var object = {
      name:'bb',
      getNameFunc: function(){
        var that=this;
        return function(){
          return that.name;
        }
      }
    }
    

    回复
    0
  • 迷茫

    迷茫2017-04-11 13:30:38

    var object = {
      name:'bb',
      getNameFunc: function(){
        return function(obj){
          return obj.name;
        }(this)
      }
    }

    回复
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-11 13:30:38

    因为闭包里的this指向window,你可以在闭包里console.log(this)一下,会发现输出window。至于为什么闭包里的this会指向window,我还分析不出。不过这个结果请牢记。

    回复
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-11 13:30:38

    因为你定义的name变量本身就是个全局变量,而你对象里面又没有定义有相同的变量名,JavaScript会依次从内部外部寻找name这个变量,你可以把变量写到对象里面去。

    回复
    0
  • 取消回复发送