您的位置:首页 > Web前端 > JavaScript

javascript实现计数器理解this作用域

2016-10-21 21:25 591 查看
众所周知,javascript的一大弊端便是全局作用域的使用。在想要计数的时候,定义一个全局变量计数显然是不可取的。利用面向对象编程的思想,我们想要实现一个计数器可能需要定义一个计数器类。但是想要利用javascript实现一个计数器,我们可以利用哪些方法呢?

首先,新手最先想到的可能是这样的:

function counter(){
var cnt=0;
return ++cnt;
}


但是,执行后是

counter();//结果是1
counter();//结果是1


原因在于每次函数执行时候都把cnt重新定义并且初始化成0了。那么会想,怎么只让它初始化一次呢?自然我们想到的就是让cnt的定义和初始化只执行一次。于是有:

function counter(){
var cnt=0;
this.increase = function(){
cnt++;
return cnt;
}
return this;
}

var myCounter= counter();
myCounter.increase();//结果是1
myCounter.increase();//结果是2


到这里,计数器就可以使用了。但是为什么counter函数要返回this呢?

原因在于函数未显式指定返回值时候它默认会返回undefined。

更重要的问题是:此时this指向的是谁呢?是counter对象吗?我们接下去进行测试:

console.log(global.increase);//结果是[Function]


以上测试说明this指向的是global。为什么this不指向自身而指向counter呢?

这就涉及this作用域的问题,this的指向取决于函数调用的模式。接下来介绍常用的函数调用模式

(1)函数调用模式

当一个函数并非一个对象的属性的时候,他直接以functionName()的方式被调用时候,它的this指向的是global全局对象。上述counter函数的调用就是这种模式。

var counter = {
cnt:0,
increase:function(){
this.cnt ++;
return this.cnt;
},
increaseTo:function(i){
var helper = function(i){
this.cnt=i;
}
helper(i);//函数调用模式
return this.cnt;
}
}
counter.increase();//结果是1
counter.increase();//结果是2
counter.increaseTo(9);//结果是2
console.log(global.cnt);//结果是9


上述helper的调用就是函数调用模式,由于helper内this指向的是全局对象,所以导致global.cnt值为9。此bug的改进可以将increaseTo函数改为如下形式

var counter = {
cnt:0,
increase:function(){
this.cnt++;
return this.cnt;
},
increaseTo:function(i){
var that = this;
var helper = function(i){
that.cnt=i;
}
helper(i);//函数调用模式
return this.cnt;
}
}
counter.increase();//结果是1
counter.increase();//结果是2
counter.increaseTo(9);//结果是9
console.log(global.cnt);//结果是undefined


(2)方法调用模式

在面向对象编程中,我们知道对象具有各种属性。当一个函数被保存为对象的一个属性的时候,我们称它为一个方法。当一个方法被对象调用的时候,this指向了这个对象。

var counter = {
cnt:0,
increase:function(){
this.cnt++;
return this.cnt;
}
}
counter.increase();//结果为1(方法调用模式)
counter.increase();//结果为2(方法调用模式)


counter是一个计时器对象,increase是计时器的一个方法。increase方法可以通过this去访问对象,因为此时this指向的就是调用它的counter对象。

(3)构造器调用模式

如果在一个函数前面带上new来调用,那么将创建一个包含该函数上下文的新对象。并且this将指向这个对象。

function Counter(){
this.cnt=0;
this.increase = function(){
this.cnt++;
return this.cnt;
}
}

var myCounter= new Counter();//构造器调用模式
myCounter.increase();//结果是1
myCounter.increase();//结果是2
console.log(global.cnt);//结果是undefined


结合new前缀调用的函数被称为构造器函数。按照约定,他们以首字母大写命名。

(4)apply调用模式

格式Function.apply(obj,args);

通俗的讲,函数的功能就是把Function的代码放到obj内去执行,同时将args参数传递给Function。apply调用模式可以直接将Function函数的this指向obj。

function increase(cnt){
this.increase=function(){
cnt++;
return cnt;
}
}
function Counter(){
var cnt=0;
increase.apply(this,[cnt]);
}
var myCounter= new Counter();
myCounter.increase();//结果是1
myCounter.increase();//结果是2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息