JavaScript是一门非常灵活的语言,它和其他编程语言相比有很多独特的地方。其中一个较为突出的表现就是,在JavaScript中允许我们手动更改上下文 。这会方便我们进行状态的共享,尤其是在事件回调中显得意义重大。但这也市场给一些初学者带来费解和疑惑。下面我们为大家讲述几种较为常用的手动更改上下文的方法:
function Student(name) {
this.name = name;
this.clicked =function () {
console.log(this.name);
}
this.introduce = function () {
document.onclick = this.clicked;
}
}
var s1 = new Student("jack");
s1.introduce();
上面的例子是一个简单的上下文发生更改的案例, 我们的预期效果是点击文档的时候,打印出jack 的名字 。但是由于绑定事件时,上下文发生了更改,所以当我们点击文档的时候打印出来的值是undefined ,所以我们需要手动变换一下上下文;
解决方案:
1. 变量赋值传递
var self = this;
this.clicked =function () {
console.log(self.name);
}
this.introduce = function () {
document.onclick =this.clicked;
}
这种方法是应用最为广泛的一种方法,在上下文发生更改之前使用变量将其缓存下来,在执行的时候利用缓存对象调用到属性值。
2. 使用bind方法
实际上JavaScript的运营商已经为我考虑到了上下文切换的问题 ,并在es5中新加了bind方法,专门用来更改函数的作用域 。
this.clicked =function () {
console.log(this.name);
}
this.introduce = function () {
document.onclick = this.clicked.bind(this);
}
上述代码中,我们利用bind方法 进行了作用域的更改,实际上是将内部代码的执行对象更改为了外部的this 对象 。
3. 使用代理函数 。
function Student(name) {
this.name = name;
this.proxy=function (func,thisObject) {
return (function () {
returnfunc.apply(thisObject,arguments);
});
}
this.clicked =function () {
console.log(this.name);
}
this.introduce = function () {
document.onclick = this.proxy(this.clicked,this);
}
}
var s1 = new Student("jack");
s1.introduce();
对比发现上边的代码格式发生了比较大的变化 ,这里比较关键的是我们定义了一个proxy的函数,这个函数实际上是模拟了jquery中的$.proxy 方法,原理是利用aplly方法进行作用域的更改,不过我们将这部分的逻辑封装成一个函数,这样看上去会更加清爽一些。当然我们也可以直接使用apply或call方法,实现执行对象的更改 。
4. apply 或call 方法
这里简单介绍一下apply方法和call方法 。这两个方法在功能上有些类似,最基本的用法是 b.apply(a,arguments) 或 b.call(a,arguments[0], arguments[1], arguments[2]…) . 上述功能是将b方法的功能复制给a对象 。它们的调用对象都是函数 ,不同点是后续传入的参数个数。apply 只需要传入arguments 数组,arguments代表函数所有参数,call 方法需要依次传入函数的参数 。
注意:直接使用call或apply方法并不能妥善的解决上下文切换的问题, 我们最好的做法是像type3所介绍的方法一样结合一个代理函数去使用它们 。下面并不是一个很好地示例,因为我们结合了type1 的方法,不过通过这个案例你依然能看出apply或call方法 在处理上下文切换方面的作用 。
this.introduce = function () {
var self = this;
document.οnclick=function () {
return (function () {
console.log(this.name);
}).apply(self,arguments);
}
}