美文网首页
this指向判定,call,apply的应用

this指向判定,call,apply的应用

作者: Iswine | 来源:发表于2016-10-09 18:22 被阅读0次

    this的本质是任何函数创建时都会附带的隐藏参数,但因为不清楚其指向的问题,初学者往往犯迷糊,那么this到底指向谁呢?我们先来看几种情况(不讨论严格模式):

    var obj = {
        "name": "obj1",
        "foo": function(){
            console.log(this);
            }
    }
    var fn = obj.foo;
    fn();          //window
    obj.foo();     //obj
    fn.call(obj)   //obj
    

    判断this的指向可以用call判断法:

    • 有没有调用call()apply(),若有,则为里面的第一个参数;若无,下一步;
    • 将函数fn转换为fn.call()的形式,如:
    fn() == window.fn() == fn.call(window)
    obj.foo() == foo.call(obj);
    

    call()和apply()均是用来指定this指向,传入参数的函数,常常用于高阶函数的计算之中,它们唯一的区别在于apply传入的是数组,而call传入的一个个参数。例:

    function sum(x,y){
        return x+y;
    }
    sum.call(null,1,2);    //3
    sum.apply(null,[1,2]);  //3
    

    来看几道面试题:
    1.以下代码输出什么?

    var john = { 
      firstName: "John" 
    }
    function func() { 
      alert(this.firstName + ": hi!")
    }
    john.sayHi = func;
    john.sayHi();   // John:hi!
    // 因为john.sayHi() == john.sayHi.call(john),故答案如上;
    

    2.下面代码输出什么,为什么?

    func() 
    
    function func() { 
      alert(this)
    }      //window
    //首先函数声明被提前,其次func() == func.call(window);
    

    3.下面代码输出什么?

    function fn0(){
        function fn(){
            console.log(this);
        }
        fn();
    }
    fn0();     //window,和上一题本质是一样的;
    
    document.addEventListener('click', function(e){
        console.log(this);
        setTimeout(function(){
            console.log(this);
        }, 200);
    }, false); 
    //点击后,先输出document,再输出window;(setTimeout/setInterval中的this均指向window)   
    

    4.下面代码输出什么,why?

    var john = { 
      firstName: "John" 
    }
    
    function func() { 
      alert( this.firstName )
    }
    func.call(john) 
    //John;  前面已解释;
    

    5.下面代码输出什么,why?

    var john = { 
      firstName: "John",
      surname: "Smith"
    }
    
    function func(a, b) { 
      alert( this[a] + ' ' + this[b] )
    }
    func.call(john, 'firstName', 'surname') 
    //  John Smith;  同上
    

    6.以下代码有什么问题,如何修改

    var module= {
      bind: function(){
        $btn.on('click', function(){
          this.showMsg();
        })
      },
      
      showMsg: function(){
        console.log('饥人谷');
      }
    }
    module.bind();
    

    由于事件触发中,this代表了$btn这个DOM节点,而不是程序员所期望的module对象,所以输出无效;
    正确的应提前绑定this,改正后:

    var module= {
      bind: function(){
        var that = this;
        $btn.on('click', function(){
        that.showMsg();
        })
      },
      
      showMsg: function(){
        console.log('饥人谷');
      }
    }
    module.bind();
    

    7.下面代码输出什么? why?

    obj = {
      go: function() { alert(this) }
    }
    
    obj.go();     // obj  执行环境为obj;
    
    (obj.go)();   //obj;  被立即执行函数包裹,等价于obj.go();,环境依然为obj;
    
    (a = obj.go)();   // window;  等价于(a = function(){alert(this)})()   此时环境为window;
    
    (0 || obj.go)();   //window;
    

    着重分析第四题,若题目为0 || (obj.go)()则输出obj
    实际上,立即执行函数括号中已经生成了一个新的函数,而这个函数的执行环境是window,即已经变成了第三种情况。

    相关文章

      网友评论

          本文标题:this指向判定,call,apply的应用

          本文链接:https://www.haomeiwen.com/subject/okwpyttx.html