• avascript中的this与函数讲解


    javascript中的this与函数讲解

    前言

    javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域。并且,大家可以认为全局作用域其实就是Window函数的函数作用域,我们编写的js代码,都存放在Window函数内(这是个假设),也就是说javascript中只有函数作用域(前面假设做前提下)。

    作用域是什么

    作用域是一个盒子,盒子内部的变量只能在当前盒子中使用,作用域盒子是可以嵌套的,内部盒子的变量对父级盒子是不可见的,因为盒子封闭了他们并且盒子不透明,但是盒子可以看到父级盒子内部定义的变量,因为内部这个盒子与父级的变量同处一个空间,他们是互相看得到的。就像css中的盒模型一样。

    以上这个图分为3层作用域,全局作用域、foo函数作用域、bar函数作用域,我们可以清晰的看到三层作用域各自的范围。

    this是什么

    我们经常用到this,this是代表着什么?this是代表着当前方法执行的环境上下文,那么何为环境上下文,通俗的说,谁调用了函数,谁就是这个函数的环境上下文。例如:

    复制代码
    function run () {
      console.log(this)
    }
    
    var o = {
      run: run
    }
    
    run()  //  window对象
    o.run  //  o对象
    复制代码

    在上述代码中,run是一个函数,首先执行run()返回了window对象,为什么呢?我们已经讲过,var定义的变量会默认挂在到window对象中去,那么function定义的函数呢,也会默认挂在到window对象中去,其实我们在执行一个函数如:run() 跟window.run()是一样的,所以,window调用了run,因此函数的this是window。

    注意:this的绑定是产生在函数调用时,并非在函数定义时

    复制代码
    var o = {
      color: 'red',
      getColor: function () {
        console.log(this.color)
      }
    }
    
    var color =  'blue'
    
    var getColor = o.getColor
    
    o.getColor // red
    getColor  // blue
    复制代码

    上述代码,我们将o.getColor方法赋值给了一个变量getColor,然后我们分别执行了两个方法,缺得到了不同的结果,对于o.getColor并没有什么疑问,但是初学者可能认为getColor返回的也应该是red,但事实是blue,这就说明了,this是产生在函数调用时,因为在o.getColor赋值语句,就相当于一下语句

    var getColor = function () {
      console.log(this.color)
    }

    o.getColor返回的是这个函数,并没有绑定this,也就是说getColor其实是被赋值了一个函数,仅此而已,this是在调用时绑定的,所以得到了那样的结果。

    不要被模样给蒙蔽

    看下面代码:

    复制代码
    var o = {
      run : function () {
        setTimeout(function () {
          console.log(this)   
        }, 1000)
      }
    }
    o.run()  //  window对象
    复制代码

    以上运行了o.run方法,隔一秒输出this,输出了window对象,初学者可能会疑问,o.run调用时明明是在o对象下啊,this应该是o对象啊!不错,有这个疑问说明对this有一定了解了,但是上面案例是在setTimeout方法中的回调函数中输出的this,此回调函数执行时,是以fn()方式执行的(涉及到异步回调),前面说过直接执行函数相当于window.fn,因此输出了window对象。

    拓展回调:

    回调是进行异步操作常用的功能,上面示例中,我们可以假设为setTimeout是这样定义的

    复制代码
    function setTimeout (fun) {
      fun()
    }
    
    
    setTimeout (function () {
      console.log(this)
    })
    复制代码

    可以看出,fun是直接调用的,输出的this必定是window对象。

    暴力绑定this

    有时候,我们需要强制某个函数中的this为某一对象,我们这时候需要暴力的绑定this,这里,暴力的方法有3个: call、apply、bind。下面通过一个简单的demo来看一下他们的用法。

    复制代码
    var color = 'blue'
    
    var o = {
      color: 'red',
      say: function (animal, beautiful) {
        console.log(this.color + '颜色的' + animal + (beautiful ? '好看': '不好看'))
      }
    }
    
    var say= o.say
    
    say('猫', false)   // blue颜色的猫不好看
    say.call(o, '猫', true)  // red颜色的猫好看
    say.apply(o, ['猫', true])  // red颜色的猫好看
    say.bind(o)('猫', true)  // red颜色的猫好看
    o.say.call(null, '猫', false)  // blue颜色的猫不好看
    复制代码

    我们这次将o函数加一个say方法,say方法接收两个参数,第一个数动物,第二个是布尔值代表好不好看,我们还是将o.say赋值给变量say。

    say('猫', false) 如期返回了blue颜色

    say.call(o, '猫', true),say.apply(o, ['猫', true]),say.bind(o)('猫', true) 这三个都返回了red,可见我们都暴力的绑定了this为o对象。

    call和apply的第一个参数都是接收要绑定的对象,也就是告诉引擎:'我要让say方法在o对象的环境下运行,你给我帮顶一下',引擎回答:‘包在我身上’,然后我们就绑定成功了,接下来我们需要传递参数到方法中去,call方法是在第二个参数之后,按顺序的传递参数 到方法中去,apply方法不同,apply方法是在第二个参数以数组的方式将参数传递到方法中去。而bind方法是es5中的方法,用途就在于绑定this指向然后返回已绑定好了的函数,因此,以上三个都输出了red

    同样o.say绑定到null或者undefined,引擎会自动绑定到全局对象window下面。

    进阶:函数的执行过程

    本着菜鸟的思路,努力讲述一下简单的函数执行背后的历程,有错误请指正。

    复制代码
    function fn (a, b) {
      var c = 2;
      function f () {...}
    }
    
    var o = {}
    
    fn.call(o,1,'ok')
    复制代码

    函数fn执行,会首先产生一个函数活动对象,这个活动对象对外是不可见的,该示例中,fn函数活动对象先绑定了此次调用的this指向o,参数之间的赋值形成arguments对象,然后进行了函数内部的初始化变量,最后执行函数内部的赋值过程。过程如下:

    复制代码
    function fn (a = 1, b = 'ok') {  
      var c
      var f
      //活动对象初始化完毕,进行函数体内的其他操作,这根变量提升和函数声明提升有关
      c = 2
      f = function () {...}
    }
    复制代码

    总结

    总而言之,函数是javascript中最主要的结构,this是javascript甚至每一门高级语言中都需要的动态绑定的指针。能力一般,水平有限,如有错误,轻喷轻骂。

  • 相关阅读:
    Educational Codeforces Round 67 D. Subarray Sorting
    2019 Multi-University Training Contest 5
    Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code
    Educational Codeforces Round 69 D. Yet Another Subarray Problem
    2019牛客暑期多校训练第六场
    Educational Codeforces Round 68 E. Count The Rectangles
    2019牛客多校第五场题解
    2019 Multi-University Training Contest 3
    2019 Multi-University Training Contest 2
    [模板] 三维偏序
  • 原文地址:https://www.cnblogs.com/libin-1/p/6244498.html
Copyright © 2020-2023  润新知