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

众所周知,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
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值