第二部分 - 第1章:关于this
1.1 为什么要用this
-
this
是一个很特别的关键字,同时也是JavaScript中很复杂的机制,本章讲解this
。 - 我们先看看,不用
this
的代码是怎么样的:
var Me = {
name : 'William'
}
var You = {
name : 'Yoki'
}
//公共方法:返回指定对象的大写name
function identify(context){
return context.name.toUpperCase();
}
//公共方法:用指定对象大写的name,输出hello字符串
function speak(context){
var greeting = "Hello,I'm " + identify(context);
console.log(greeting);
}
console.log(identify(You));
console.log(identify(Me));
speak(Me);
speak(You);
-
speak()
和identify()
方法不使用this
,则需要显式的传入context
对象,而随着代码越来越复杂,显式传递对象的方式会使得代码愈加混乱。 - 接着我们改写这两个方法,会发现,其实
this
提供了一种更优雅的方式隐式传递对象的引用,这样API也可以设计得更加简洁且复用。
function identify(){
return this.name.toUpperCase();
}
function speak(){
var greeting = "Hello,I'm " + identify.call(this);
console.log(greeting);
}
console.log(identify.call(You));
console.log(identify.call(Me));
speak(Me);
speak(You);
1.2 this的误解
- 人们很容易把
this
理解成指向函数自身,这从英语的语法上理解是没毛病的,但事实并不是这样的。
function foo(num){
console.log("foo:" + num);
this.count++;
}
foo.count = 0;
for(var i=0;i<10;i++){
if(i > 5){
foo(i);
}
}
console.log(foo.count);
console.log(count);
控制台输出的是:
foo:6
foo:7
foo:8
foo:9
0
NaN
- 从上述打印情况来看,
console.log()
语句确实产生了4条输出,证明foo()
方法被调用了4次,但this.count
的指向并不是foo.count
,反而在window
下多出了一个count
,值为NaN
。 - 为了修复上述的结果,当然可以将
foo
方法中的this.count++
改成foo.count++
,但忽略了真正的问题——this
究竟指向谁? - 下面我们来真正修复这个问题,其实只需要修改
foo()
方法调用的方式即可:
for(var i=0;i<10;i++){
if(i > 5){
//call()方法就是指明哪个对象来调用方法
//之前没使用call()方法时,默认是以window来调用方法,以致于window下会多个count=NaN的变量
foo.call(foo,i);
}
}
console.log(foo.count);
- 这下输出就正常了,由此可以看出其实
this
真正的含义是:谁调用我,我指向谁。 - 另外需要注意的是,不能通过
this
进行作用域穿越。
function foo(){
var a = 2;
bar();
}
function bar(){
console.log('a:' + this.a);
}
foo();
- 代码试图通过
this
关联foo()
和bar()
作用域,从而让bar()
能访问foo()
作用域中的变量,这是不可能实现的。
1.3 this到底是什么
-
this
在运行时绑定,而不是编写时,它的指向取决于函数的调用方式。 - JavaScript当函数被调用时,会创建一个context(上下文/环境)记录,这个记录的内容包含函数在哪里被调用、函数的调用方式、 传入的参数等信息,而
this
就是函数context记录的其中一个属性。
网友评论