ADS2.3 JavaScript中的对象——关于this

前端技术 everyinch 1717℃ 0评论

大多数程序员都认为this是在当前脚本或对象的作用域中引用一个普通元素的标识符。然后,this在JavaScript中是依赖于它的执行环境的一个关键字。请看下面的例子:

var sound = 'Roar!';
function myOrneryBeast() {
    this.style.color='green';
    alert(sound);
}

其中的this关键字包含在一个函数中,这个函数是某个对象的方法,在这里this引用的就是那个对象。我们知道在JavaScript中全部脚本都包含在window全局对象中。因此,在脚本的最顶层,this引用的就是window对象。但是,在myOrneryBeast()函数的环境中的this是如何解析为window对象的呢?因为myOrneryBeast()函数作为window对象的一个方法而存在的,这样函数中的this关键字将会解析为包含它的函数作为方法被调用时所属的对象。因为myOrneryBeast()函数是在window环境中被调用的,所以this.style.color将会引用window.style.color。相应的解析过程如下图所示:
blog_this1
不过,this的环境可以随着函数被赋值给不同的对象而改变。比如直接或者使用ADS.addEvent()方法将函数赋值给一个事件侦听器属性:

var sound = 'Roar!';
function myOrneryBeast() {
    this.style.color='green';
    alert(sound);
}
function initPage() {
    var example = ADS.$('example');
    // 使用事件属性方法
    example.onclick = myOrneryBeast;
    // 或者使用ADS.addEvent()方法
    ADS.addEvent(example,'click', myOrneryBeast);
}
ADS.addEvent(window,'load',initPage);

无论使用哪种事件注册模型,相应的元素在单击时会变成绿色,也会看到显示“Roar!”的警告框。如果对变量sound求值的结果仍然是“Roar!”,那么this不也仍然应该引用window对象吗?事实并不像期望的那样。因为JavaScript会事件侦听器被调用的环境中将this作为一个关键字来解析。在本例中,无论是onClick属性还是click事件,都是example对象的一个方法。因此,this会被解析为将函数作为其方法的对象,即将事件作为方法的HTML元素——this引用的是example这个HTML元素。
对于Sound变量而言,它在initPage()函数的作用域中没有改变,所以它在作用域链中始终会被解析为“Roar!”。解析过程如下图所示:
blog_this2

通过call()和apply()重新定义执行环境

关于this关键字的引用问题还有个问题需要解决,这个问题涉及环境的改变。如果改变环境并非是我们希望的那样,又该如何呢?下面看一个例子:

function doubleCheck() {
    this.message = 'Are you sure you want to leave?';
}
doubleCheck.prototype.sayGoodbye = function() {
    return confirm(this.message);
}
initPage() {
    var clickedLink = new doubleCheck();
    var links = document.getElementsByTagName('a');
    for (var i=0 ; i<links.length ; i++) {
        ADS.addEvent(links&#91;i&#93;, 'click', clickedLink.sayGoodbye);
    }
}
ADS.addEvent(window,'load',initPage);
&#91;/code&#93;
这个例子循环遍历页面中的所有链接,然后将clickedLink.sayGoodbye()方法指定为每个链接的click事件侦听器。根据上面的例子我们知道,当sayGoodbye()方法在&lt;a&gt;这个HTML元素的环境中执行时,this引用的就是这个HTML元素,而不是clickedLink。那如何解决这个问题呢?可以使用Function对象的call()或apply()方法。这两个方法可以指定函数的执行环境。例如想让方法在window对象的环境中执行,可以使用:
&#91;code lang="js"&#93;
clickedLink.sayGoodbye.call(window);
&#91;/code&#93;
或者:
&#91;code lang="js"&#93;
clickedLink.sayGoodbye.apply(window);
&#91;/code&#93;
在本例中clickedLink.sayGoodbye()方法没有参数,如果方法有参数,则对于call()方法而言,是将参数列在对象之后:
&#91;code lang="js"&#93;
functionReference.call(object, argument1, argument2, ...)
&#91;/code&#93;
对于apply(),则应该将参数作为一个数组:
&#91;code lang="js"&#93;
functionReference.apply(object, arguments)
&#91;/code&#93;
参数的不同传递方式是call()和apply()之间唯一的区别。
为了调整方法的执行环境apply()方法特别有用。下面的bindFunction()方法返回的函数,会取得通过func参数传递进来的函数,然后将其应用到由obj参数传递进来的对象上面:
&#91;code lang="js"&#93;
function bindFunction(obj, func) {
    return function() {
        func.apply(obj,arguments);
    };
}
&#91;/code&#93;
这个函数的主要目的是给原始的函数(func)创建一个新的执行环境。如下图所示:
<a href="http://www.everyinch.net/wp-content/uploads/2014/01/blog_this3.jpg"><img src="http://www.everyinch.net/wp-content/uploads/2014/01/blog_this3.jpg" alt="blog_this3" width="450" height="425" class="alignnone size-full wp-image-4533" /></a>
下面将bindFunction函数加入到ADS库中:

/**
 * 将func函数绑定到obj对象上
 */
function bindFunction(obj, func) {
    return function() {
        func.apply(obj,arguments);    
    };
};
window['ADS']['bindFunction'] = bindFunction;

使用这个方法可以修改任何方法的环境。具体到doubleCheck()的例子中,可以将原来的代码修改如下:

function doubleCheck() {
this.message = 'Are you sure you want to leave?';
}
doubleCheck.prototype.sayGoodbye = function() {
return confirm(this.message);
}
initPage() {
var clickedLink = new doubleCheck();
var links = document.getElementsByTagName('a');
for (var i=0 ; i

转载请注明:陈童的博客 » ADS2.3 JavaScript中的对象——关于this

喜欢 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

无觅相关文章插件,快速提升流量