共同点
最近写了一段测试的码,加了严格模式后,发现挂了。检查后发现是使用 apply 改变 this 后有些值没了。
这里整理下 apply(), call() 和 bind() 的使用。
共同点:
均改变函数的 this 对象指向。
参数类似,第一个是 this,之后是传给方法的参数。
apply
语法
fun.apply(thisArg, [argsArray])
指定一个 this,利用给定参数数组,调用函数。从ES5 开始可以使用类数组对象。即对象有 length 属性和[0...length) 范围的整数属性。
例如
var likeArrayObj = {
'length': 2,
'0': 'firstName',
'1': 'secondName'
}
先看一个例子, 函数 printName() 功能只是将当前上下文的 name 输出。
var name = "outside";
var obj = {
name : 'Object name'
}
function printName(arg) {
console.log(this === obj);// 调用时 this 指向 obj, 输出 true
console.log(this.name + " "+ arg)
}
printName.apply(obj, ["hust"]);
当指定基本类型
指定值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象
// 指定基本值
var that = 'zw';
function printName(arg) {
// this 执行
console.log(this);
console.log('name : '+ arg)
}
printName.apply(that, ["hust"]);
上面选中的就是 this的值,是JS 对我们传递的字符串进行了包装的对象。
需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象。
function printName(arg) {
console.log(window === this);// 输出 true
console.log('name : '+ arg)
}
printName.apply(null, ["hust"]);
这里,我们传入了 null,结果 this 指向了 window 对象。
而在严格模式下:
'use strict'
function printName(arg) {
console.log(window === this);// 输出 false,注意,此时 this 为 null
console.log(this === null) // 输出 true
}
printName.apply(null, ["hust"]);
发现 this 指向 null。
monkey-patching
所谓 monkey-patching 就是 “猴子补丁”,即
扩展
Object.prototype
或者其他内置类型的原型对象。下面代码来源于官网:
可以通过这种方式将第三方库引入我们的系统。不过
,个人觉得不得已的情况下才能这么做。下面是我从 JavaScript的后花园里截取的一段话。
有兴趣的话,可以自己研究下。
call
语法
fun.call(thisArg[, arg1[, arg2[, ...]]])
作用: 调用一个对象的一个方法,以另一个对象替换当前对象。
与apply的区别就是: apply 接受数组,call 接受参数序列。
继承例子
// 继承
function Person(name) {
this.name = name;// 将name、speak 属性赋值给 this, 下面call的使用,让 this 指向了 Teacher 的对象。
this.speak = function() {
console.log(this.name);
}
}
function Teacher(name) {
Person.call(this, name);
}
(new Teacher('Teacher')).speak();// 因此此时 Teacher的对象能获取到 speak 方法。
bind
fun.bind(thisArg[, arg1[, arg2[, ...]]])
创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列.
注意,这里是创建新的函数。而且函数的上下文和参数都已经绑定了。
'use strict'
var name = "outside";
var obj = {
name : 'Object name'
}
function printName(arg) {
console.log(this === obj);// 调用时 this 指向 obj, 输出 true
console.log(this.name + " "+ arg)
}
var copyFun = printName.bind(obj, "first bind");// 跟 call 一样使用参数序列
copyFun("This input no use");// 由于上面 bind 时已经绑定了上下文和参数,再传入参数不起作用。
同样的,再次调用 bind 也不能改变上下文和参数。
'use strict'
var name = "outside";
var obj = {
name : 'Object name'
}
function printName(arg) {
console.log(this === obj);// 调用时 this 指向 obj, 输出 true
console.log(this.name + " "+ arg)
}
var copyFun = printName.bind(obj, "first bind");// 跟 call 一样使用参数序列
// 这里返回一个函数引用,该函数引用已经被绑定了上下文
var obj2 = {
name : 'Second Object'
}
copyFunAgain = copyFun.bind(obj2, "second bind"); // 重新绑定上下文, 此处的绑定不起作用
copyFunAgain("zw");// 依旧输出 first bind