JavaScript this的用法

在 JavaScript 中,this 表示当前调用对象,用在函数体内。

1、this 用法

this 是函数体内自带的一个对象指针,它始终指向调用对象。当函数被调用时,使用 this 可以访问调用对象。this 关键字的使用范围局限于函数体内或者调用范围内。具体用法如下:

this[.属性]

如果 this 未包含属性,则传递的是当前对象。

this 用法比较灵活,它可以存在于任何位置,它并不仅仅局限于对象的方法内,还可以被应用在全局域内、函数内,以及其他特殊上下文环境中。

1.1、函数的引用和调用

函数的引用调用分别表示不同的概念。虽然它们都无法改变函数的定义作用域。但是引用函数,却能够改变函数的执行作用域,而调用函数是不会改变函数的执行作用域的。

var obj = {
    name:"对象obj",
    fun:function(){
        return this;
    }
}
obj.o1 = {
    name:"对象o1",
    me:obj.fun    //引用对象obj的方法fun
}

在上面示例中,函数中的 this 所代表的是当前执行域对象 o1:

var who = obj.o1.me();
alert(who.name);    //返回字符串"对象o1",说明当前this代表对象o1

如果把对象 o1 的 me 属性值改为函数调用:

obj.o1 = {
    name:"对象o1",
    me:obj.fun()    //调用对象obj的方法fun
}

则函数中的 this 所代表的是定义函数时所在的作用域对象 obj:

var who = obj.o1.me;
    alert(who.name);    //返回字符串"对象obj",说明当前this代表对象。
}

1.2 使用 call() 和 apply() 。

call() 和 apply() 方法可以直接改变被执行函数的作用域,使其作用域指向所传递的参数对象。因此,函数中包含 this 关键字也指向参数对象。

function fun(){
    if(this.constructor = arquments.callee)    //如果当前执行域对象的构造函数等于当前函数,则表示this为实例对象
        alert("this = 实例对象");
    else if(this = window)    //如果当前执行域对象等于window,则表示this为Window对象
        alert("thia-window对象");
    else     //如果当前执行域对象为其他对象,则表示this为其他对象
        alert("this ==其他对象 \n this.constructor = " + "this.constructor";
}

fun();        //this 指向window对象
new fun();    //this 指向实例对象
fun.call(1);  //this 指向数值实例对象

在上面示例中,直接调用函数 fun() 时,函数的执行作用域为全局域,所以 this 代表 window。当使用 new 运算符调用函数时,将创建一个新的实例对象,函数的执行作用域为实例对象所在的上下文,所以 this 就指向这个新创建的实例对象。而使用call() 方法执行函数 fun() 时,call() 会把函数 fun() 的作用域强制修改为参数对象所在的上下文。由于 call() 方法的参数值为数字 1,则 JavaScript 解释器会把数字 1 强制封装为数值对象,此时 this 就会指向这个数值对象。

在以下示例中,call() 方法把函数 fun() 强制转换为对象 obj 的一个方法并执行;这样函数 fun() 中的 this 就指代对象obj,所以 this.x 的值就等于 1,而 this.y 的值就等于 2,结果就返回 3:

funetion fun(){    //函数fun()
    alert(this.x + this.y);
}
var obj = {    //对象直接量
    x:1,
    y:2
}
fun.call(obj);    //执行函数fun(),返回值为3

1.3、原型继承

JavaScript 通过原型模式实现类的延续和继承,如果在父类的成员中包含了 this 关键字,当子类继了父类的这些成员时,this 的指向就变得很迷惑人。在一般情况下,子类继承父类的方法后,this 会指向子类的实例对象,但是也可能指向子类的原型对象,而不是子类的实例对象。

function Base(){    //基类
    this.m = function();    //基类的方法m()
        return "Base";
    }
    this.a = this.m();    //基类的属性a,调用当前作用域中m()方法
    this.b = this.m;      //基类的方法b(),引用当前作用域中m()方法
    this.c = function(){
        return this.m();    //基类的方法c(),以闭包结构调用当前作用域中m()方法
    }
}
function Fun(){    //子类
    this.m = function(){    //子类的方法m()
        return "Fun"
    }
}
Fun.prototype = new Base();    //继承基类
var fun = new Fun();    //实例化子类
alert(fun.a);      //返回字符串"Base",说明this.m()中this指向FUN的原型对象
alert(fun.b());    //返回字符串"Base",说明this.m()中this指向Fun的原型对象
alert(fun.c());    //返回字符串"Fun",说明this.m()中this指向Fun的实例对象

在上面示例中,基类 Base 包含 4 个成员,其中成员 b 和 c 以不同方式引用当前作用域内方法m() ,而成员 a 存储着当前作用域内方法 m() 的调用值。当这些成员继承给子类 Fun 后,其中 m、b 和 c 成为原型对象的方法,而 a 成为原型对象的属性。但是,c 的值为一个闭包体,当在子类的实例中调用时,实际上它的返回值已经成为实例对象的成员,也就是说,闭包体在哪儿被调用,则其中包含的 this 就会指向哪儿。所以,你会看到 fun.c() 中的 this 指向实例对象,而不是 Fun 类的原型对象。

为了避免因继承关系而影响父类中this所表的对象,除了通过上面介绍的方法,把方法的引用传递给父类的成员外,我们还可以为父类定义私有函数然后再把它的引用传递给其他父类成员,这样就避免了因为函数闭包的原因,而改变 this 的值

function Base(){
    var _m = function(){    //定义基类的私有函数_m()
        return "Base";
    }
    this.a = _m;
    this.b = _m();
}

这样基类的私有函数 _m() 就具有完全隐私性,外界其他任何对象都无法直接访问基类的私有函数 _m() 。所以,在一般情况下,定义方法的时候,对于相互依赖的方法,可以把它定义私有函数,并以引用方法的方式对外公开,这样就避免了外界对于依赖方法的影响。

1.4 异步调用之事件处理函数

异步调用就是通过事件机制或者计时器来延迟函数的调用时间和时机。通过调用函数的执行作用域不再是原来的定义作用域,所以函数中的 this 总是指向引发该事件的对象。

<input type="button" value="Button"/>
<script language="javascript" type="text/javascript">
    var button = document.getElementsByTagName("input")[0];
    var obj = {};
    obj.fun = function(){
        if(this == obj)    alert("this = obj");
        if(this == window)    alert("this = window");
        if(this == button)    alert("this = button");
    }
    button.onclick = obj.fun;
</script>

这里的方法 fun() 所包含的 this 不再指向对象 obj,而是指向按钮 button,因为它是被传递给按钮的事件处理函数之后,再被调用执行的。函数的执行作用域发生了变化,所以不再指向定义方法时所指定的对象。

1.5 异步调用之定时器

异步调用的另一种形式,就是使用定时器来调用函数,定时器就是指调用 window 对象的 setTimeout() 或 setlnterval() 方法来延期调用函数。例如,下面示例设计延期调用方法 obj.fun() 。

var obj = {};
obj.fun = function(){
    if(this == obj)    alert("this = obj");
    if(this == window)    alert("this = window");
    if(this == button)    alert("this = button");
}
setTimeout(obj.fun,100);

此时,经测试程序,会发现在 IE 中 this 指向 window 和 button 对象,但是,在符合 DOM标准的浏览器中 this 指向 window对象,而不是 button 对象,因为方法 setTimeout() 是在全局作用城中被执行的,所以 js 自然指向 window 对象。要解决这个问题,仍然可以使用 call() 或 apply() 方法来实现:

setTimeout(function(){
    obj.fun.call(obj);
},100);

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值