js回调this问题

两个调用 第二次进行回调的时候 this 标记1和 this 标记2值不一样
这是为何?

 function a (val, callback) {
      callback.call(a,val,callback)
    }
    a(1,function b (val ,callback) {
        console.log(this, '标记1')
        console.log(val)
        console.log(callback)
        callback(2,function c(val, callback){
        console.log(this)
        console.log(val)
        console.log(callback)
        console.log('over')
      })
    })
    console.log('-----分割线-------')
    a(1,function b () {
        console.log(this, '标记2')
        console.log(arguments[0])
        console.log(arguments[1])
        arguments[1](2,function c(){
        console.log(this)
        console.log(arguments[0])
        console.log(arguments[1])
        console.log('over')
      })
    })

clipboard.png

阅读 1.2k
评论
    3 个回答
    • 6.9k

    第一步,先看函数a定义

    clipboard.png

    观察callback,上图中一共有三个callback,分别是

    1. 函数a的参数中的callback
    2. 绑定在a上执行的callback, 它执行时对应的this是函数a
    3. 2号callback执行时的参数中的callback,3号callback执行时并没有明确指定this绑定谁,在执行时确定

    第二步,简化你的试验代码,突出this

    function a(val, callback) {
        callback.call(a,val,callback);
    }
    
    
    a(1, function b(val ,callback) {
        console.log(this, '标记10的this');
        callback(2, function c(val, callback){
            console.log(this, '标记11的this');
        });
    });
    
    console.log('-----分割线-------');
    
    a(1, function b() {
        console.log(this, '标记20的this')
        arguments[1](2, function c(){
            console.log(this, '标记21的this');
        });
    });

    第三步, 分析分割线上半部分执行结果

    a(1, function b(val ,callback) {
        console.log(this, '标记10的this');
        callback(2, function c(val, callback){
            console.log(this, '标记11的this');
        });
    });
    //输出: a 标记10的this
    //输出: window 标记10的this
    //输出: window 标记11的this

    进一步简化,上面代码实际是 a(1, b), 结合第一步的图,

    1. b第一次执行时,对应第一步图中2号callback,

      1. 第一行开始执行:输出是 "a 标记10的this“
      2. 第二行开始执行:callback对应第一步图中3号callback,在此代指函数b,故等价于 b(2,c), b被第二次执行。
    2. b第二次执行时b(2,c),并未绑定任何对象,默认在window上执行,故this是window

      1. 第一行开始执行:输出 "window 标记10的this"
      2. 第二行开始执行:等价于 c(2,c)
      3. 第三行开始执行:c并未绑定任何对象,默认绑定在window上。 输出 ”window 标记11的this“

    第四步, 分析分割线下半部分执行结果

    a(1, function b() {
        console.log(this, '标记20的this')
        arguments[1](2, function c(){
            console.log(this, '标记21的this');
        });
    });
    //输出: a 标记20的this
    //输出: arguments 标记20的this
    //输出: arguments 标记21的this

    进一步简化,上面代码实际是 a(1, b), 结合第一步的图,

    1. b第一次执行时,对应第一步图中2号callback,

      1. 第一行开始执行:输出是 "a 标记20的this“
      2. 第二行开始执行:arguments[1]对应第一步图中3号callback,在此代指函数b,特别注意等价于绑定在arguments上执行b(2,c), b被第二次执行,为了好理解,你就理解为 arguments.b(2,c);
      3. 插播一段,数组内函数执行后,这个函数中的this默认指向数组:
      var arr = [function(){console.log(this)}];
      arr[0]();  // 输出的this的是 arr
    2. b第二次执行时arguments.b(2,c) (注意,只是为了好理解,实际是arguments[1]代b执行。),绑定在arguments对象上执行b,故this是arguments

      1. 第一行开始执行:输出 "arguments 标记20的this"
      2. 第二行开始执行:等价于 arguments.c(2,c) (注意,只是为了好理解,实际是arguments[1]代c执行。)
      3. 第三行开始执行:c也绑定在arguments上。 输出 ”arguments 标记21的this“

      翻译一下你的代码,说实话,你这命名不改一下真是谁都看不懂。

       function a(val, aCallback) {
           aCallback.call(a, val, aCallback)
       }
      
       a(1, function b(val, bCallback) { //b.call(a,1,callback) ->  b(1,a.callback) -> bCallback = function b(val,bCallback) -> this指向a
           console.log( this, '标记1')
      
           bCallback(2, function c(val, cCallback) { // b() -> bCallback = function c -> bCallback是个function 采用默认绑定 this指向window
               console.log('over 1')
           })
       })
      
       a(1, function b() { //b.call(a,1,callback) ->  b(1,a.callback) -> bCallback = function b(val,bCallback) -> this指向a
           console.log( this, '标记2')
      
           arguments[1](2, function c() { // b() -> bCallback = function c ->  由于arguments是个对象 采用隐式绑定 this指向arguments
               console.log('over 2')
           })
       })

        抱歉看不下去, 只看了前面两位的答案,大概就是这样了。

        该答案已被忽略,原因:无意义的内容 - 赞、顶、同问等毫无意义的内容

          撰写回答

          登录后参与交流、获取后续更新提醒