JavaScript中的apply、call和bind方法

来源:互联网 发布:linux oracle 客户端 编辑:程序博客网 时间:2024/06/06 07:15

共同点

最近写了一段测试的码,加了严格模式后,发现挂了。检查后发现是使用 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, 输出 trueconsole.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);// 输出 trueconsole.log('name : '+ arg)}printName.apply(null, ["hust"]);


这里,我们传入了 null,结果 this 指向了 window 对象。
而在严格模式下:
'use strict'function printName(arg) {console.log(window === this);// 输出 false,注意,此时 this 为 nullconsole.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, 输出 trueconsole.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, 输出 trueconsole.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









原创粉丝点击