Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 中 this 的用法 #9

Open
huangtengfei opened this issue Dec 16, 2015 · 0 comments
Open

JavaScript 中 this 的用法 #9

huangtengfei opened this issue Dec 16, 2015 · 0 comments

Comments

@huangtengfei
Copy link
Owner

在 JavaScript 中,this 是动态绑定,或称为运行期绑定的。一般而言,在Javascript中,this 指向函数执行时的当前对象。

由于其运行期绑定的特性,JavaScript 中的 this 可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 中函数的调用有以下几种方式:没有明确的调用对象,作为对象方法调用,使用 new 关键字作为构造函数调用,和使用 applycalleval 调用。

没有明确的当前对象时

当没有明确的执行时的当前对象时,this 指向全局对象 window

纯粹的函数调用

举个栗子

var x = 1;
function test(){
    var x = 2;
    alert(this.x);
}
test();     // 1

再看个复杂的栗子

var name = "window";

var Bob = {
    name: "Bob",
    showName: function(){
        alert(this.name);
    }
};

var Tom = {
    name: "Tom",
    showName: function(){
        var fun = Bob.showName;
        fun();
    }
};

Tom.showName();  //window

其实也不复杂,只要按照上面那句话来判断就行。

setTimeout、setInterval和匿名函数

在浏览器中 setTimeoutsetInterval 和匿名函数执行时的当前对象是全局对象 window,这条可以看成是上一条的一个特殊情况。

var name = "Bob";  
var nameObj = {  
    name : "Tom",  
    showName : function(){  
        alert(this.name);  
    },  
    waitShowName : function(){  
        setTimeout(this.showName, 1000);  
    }  
};  

nameObj.waitShowName();     // Bob

setTimeout 可以看做是一个延迟执行的匿名函数。

waitShowName : function(){  
    function(__callback){
       __callback();
    }(this.showName);  
} 

由于匿名函数的当前对象是 window,所以当在该匿名函数中运行回调函数时,回调函数的 this 指向了 window,所以 alert 出来 window.name

作为对象方法调用时

使用这种调用方式时,this 被自然绑定到该对象。

通常情况

var text = 'window'
var obj = {
    text: 'obj',
    foo: function(){
        console.log(this.text);
    }
}
obj.foo();      // obj

内部函数调用

但是,如果在 objfoo() 内部再声明一个函数,在内部函数中调用 this,像下面这样:

'use strict';
var obj = {
    text: 'hello world',
    foo: function(){
        return function(){
            console.log(this.text);
        }()
    }
}

obj.foo();      
// Uncaught TypeError: Cannot read property 'text' of undefined

这是因为 this 指针只在 foo 方法的函数内指向 obj ,在函数内部定义的函数, this 又指向 undefined 了!(在非 strict 模式下,它重新指向全局对象 window !)

修复的办法是用一个 that 变量首先捕获 this

'use strict';
var obj = {
    text: 'obj',
    foo: function(){
        var that = this;
        return function(){
            console.log(that.text);
        }()
    }
}
obj.foo();  // obj

三种特殊情况

new关键字 - 作为构造函数调用时

所谓构造函数,就是通过这个函数生成一个新对象。这时,this 就指这个新对象。

function Person(__name){
    this.name = __name;
    // this 指向使用该构造函数构造的新对象
}
Person.prototype.show = function(){
    alert(this.name);
}

var Bob = new Person("Bob");
Bob.show();        //Bob

apply 和 call

在 JavaScript 中函数也是对象,对象则有方法,apply()call() 就是函数对象的方法。它们能够强制改变函数执行时的当前对象,让 this 指向其他对象。

apply() 接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是 Array,表示函数本身的参数。call()apply() 的唯一区别就是把函数本身的参数一个个传入。

// 对普通函数调用,通常把 this 绑定为 null
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5

举个使用 apply() 改变当前对象的栗子:

var name = "window";

var someone = {
    name: "Bob",
    showName: function(){
        alert(this.name);
    }
};

var other = {
    name: "Tom"
};    

someone.showName.apply();    // window
someone.showName.apply(other);    // Tom

apply() 的参数为空时,默认调用全局对象。

eval

对于 eval 函数,其执行时候似乎没有指定当前对象,但实际上其 this 并非指向 window,因为该函数执行时的作用域是当前作用域,即等同于在该行将里面的代码填进去。

var name = "window";

var Bob = {
    name: "Bob",
    showName: function(){
        eval("alert(this.name)");
    }
};

Bob.showName();    //Bob

参考

  1. 对 js 中 this、apply、call 和闭包的理解
  2. Javascript中this关键字详解
  3. 深入浅出 JavaScript 中的 this
  4. Javascript的this用法
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant