在JavaScript中,call、apply和bind是Function对象自带的三个方法,都是为了改变函数体内部 this 的指向。
bind 是返回对应 函数,便于稍后调用;apply 、call则是立即调用
call 是把参数按顺序传递进去,而 apply 则是把参数放在数组 里。
类(伪)数组使用数组方法
Javascript中存在一种名为伪数组的对象结构。比较特别的是 arguments 对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法
vardivElements = document.getElementsByTagName('div');//虽然 divElements 有length属性,但是他是一个伪数组,不能使用数组里面的方法
Array.isArray(divElements);
vardomNodes = Array.prototype.slice.call(document.getElementsByTagName('div'));// 将数组对象Array里的this指向伪数组document.getElementsByTagName('div'),
//slice() 方法可从已有的数组中返回选定的元素,不传参数是,返回整个数组
Array.isArray(domNodes);// true
验证一个对象的类型可以用:
Object.prototype.toString.call(obj)
原因:
这是因为toString为Object的原型方法,而Array ,function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串.....),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。
在 Javascript 中,多次bind()是无效的。更深层次的原因,bind()的实现,相当于使用函数在内部包了一个call / apply,第二次bind()相当于再包住第一次bind(),故第二次以后的bind是无法生效的。
当传入参数的个数是不确定的时候,这个时候就可以考虑使用 apply 或者 call,注意这里传入多少个参数是不确定的,所以使用apply是最好的
functionlog(){
console.log.apply(console, arguments);
};
log(1); //1
log(1,2);
接下来的要求是给每一个 log 消息添加一个"(app)"的前辍,比如:
log("hello world"); //(app)hello world
该怎么做比较优雅呢?这个时候需要想到arguments参数是个伪数组,通过 Array.prototype.slice.call 转化为标准数组,再使用数组方法unshift,像这样:
functionlog(){
varargs = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
};
区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。
当函数通过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它
再总结一下:
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
网友评论