NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

JavaScript渐入佳境 - This指针

| Comments

在JavaScript中,随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用该函数的那个对象。this关键字在Javascript中和执行环境,而非声明环境有关。

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
var someone = {
    name: "Bob",
    showName: function(){
        alert(this.name);
    }
};

var other = {
    name: "Tom",
    showName: someone.showName
}

other.showName();  //Tom

这里其实应该好理解,other的showName属性指向了someone的showName所声明的函数,他等价于:

1
2
3
4
5
6
7
8
var other = {
    name: "Tom",
    showName: function(){
        alert(this.name);
    }
}

other.showName();  //Tom

所以this指针理所当然的指向other自己。

1
2
3
4
5
6
7
8
9
10
11
var name = "Tom";

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

var show = Bob.show;
show();  //Tom

上面这个show为什么显示Tom,它的执行对象是什么?Window对象。

Window对象是所有客户端JavaScript特性和API的主要接入点。它表示Web浏览器的一个窗口,并且可以用标示符window(小写)来引用。

1
2
3
4
window
$ Window {external: Object, chrome: Object, document: document, \_ASYNC_START: 1451649155228, \_chrome_37_fix: undefined}
Window
$ function Window() { [native code] }

Window对象定义了一些属性,比如,指代Location对象(location)的location属性。

1
2
window.location === location
$ true

Window对象还定义了一些方法,比如alert()和setTimeout(),使用时,我们都没有显示的使用window属性。Window对象是全局对象,处于作用域链的顶部,它的属性和方法实际上全是全局变量和全局函数。 通过window变量可以引用到Window对象本身,但是如果要使用全局窗口对象的属性,并不需要使用window。

我们常说,JavaScript很容易就创建一个全局变量或者全局函数。比如,直接var a_global_variable = ‘a global variable’。它不仅使全局变量,它还是window的一个属性。如下:

1
2
3
4
5
6
7
var a_global_variable = 'a global variable'
a_global_variable
$ "a global variable"
window.goodtest
$ "a global variable"
window.a_global_variable === a_global_variable
$ true

为什么在Window下?head/全局对象/顶层对象

JavaScript代码本身必须包含在对象内部。在Web浏览器环境中编写JavaScript代码时,JavaScript被包含在Window对象内,并在其内部执行。这个Window对象被认为是“head对象”。JavaScript的所有实现都需要使用一种head对象。

head对象是由JavaScript在幕后创建,用于封装用户用自定义代码,并容纳JavaScript预定义的原生代码。JavaScript将用户自定义代码放入head对象中来执行。在编写JavaScript代码时,它将被编写在head对象的上下文中。

换一种解释:

JavaScript的所有对象都存在于一个运行环境之中,这个运行环境本身也是对象,称为“顶层对象”。这就是说,JavaScript的所有对象,都是“顶层对象”的下属。不同的运行环境有不同的“顶层对象”,在浏览器环境中,这个顶层对象就是Window对象。

所有浏览器环境的全局变量,都是Window对象的属性。可以把Window理解成JavaScript Context 上下文环境。

理解了setTimeout是Window的属性之后,理解下面这段代码应该比较容易了:

1
2
3
4
5
6
7
8
9
10
11
var name = "Bob";
var nameObj ={
    name : "Tom",
    showName : function(){
        alert(this.name);//此时this指向的是window  
    },
    waitShowName : function(){
        setTimeout(this.showName, 1000);//这里的this指向的是nameObj.showName
    }
};
nameObj.waitShowName();// Bob

和下面这段代码相似

1
2
3
4
var name = "Bob";
setTimeout(function(){
    alert(this.name);
}, 1000);

new关键字

new关键字指向创建的对象,在上一篇文章中已经介绍的很清楚了。 http://benweizhu.github.io/blog/2015/12/31/javascript-contructor-new-prototype/

1
2
3
4
5
6
7
8
function Person(name){
    this.name = name; //这个this指向用该构造函数构造的新对象,这个例子是Bob对象
}
Person.prototype.show = function(){
    alert(this.name);
}
var Bob = new Person("Bob");
Bob.show();        //Bob

apply和call改变this指向的对象

apply和call能够强制改变函数执行时的当前对象,让this指向其他对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var name = "window";

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

var other = {
    name: "Tom"
};

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

参考资料:
1.http://www.cnblogs.com/justany/archive/2012/11/01/the_keyword_this_in_javascript.html
2.JavaScript启示录
3.http://blog.csdn.net/zoutongyuan/article/details/29355021

Comments