前两天在作小程序的需求的时候用到bind的时候才想起本身对这三的东西的了解比较浅薄,这个时候用的时候就有点怕。时候仍是要好好学习下,理解下怎么玩。面试
先说call
和 apply
吧:
ECMAScript3给Function的原型定义了两个方法,他们是Function.prototype.call
和 Function.prototype.apply
. 在实际开发中,特别是在一些函数式风格的代码编写中,call和apply方法尤其有用。小程序
一、call和apply区别数组
其实他们的做用是同样的,只是传递的参数不同而已。
apply: 接受2个参数,第一个参数指定了函数体内this对象的指向,第二个参数为数组或者一个类数组。apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则做为call的参数传入(从第二个参数开始)。
举个栗子:app
let obj1 = { name: "copyes", getName: function(){ return this.name; } } let obj2 = { name: 'Fanchao' } console.log(obj1.getName()); // "copyes" console.log(obj1.getName.call(obj2)); // "Fanchao" console.log(obj1.getName.apply(obj2)); // "Fanchao"
function showArgs(a, b, c){ console.log(a,b,c); } showArgs.call(this, 3,4,5); showArgs.apply(this, [5,6,7]);
二、常见的call 和 apply 用法dom
数组之间追加函数
let arr1 = [12, 'foo', {name: 'fanchao'}, -1024]; let arr2 = ['copyes', '22', 1024]; Array.prototype.push.apply(arr1, arr2); console.log(arr1); // [ 12, 'foo', { name: 'fanchao' }, -1024, 'copyes', '22', 1024 ]
获取数组中的最大值和最小值学习
let numbers = [5,665,32,773,77,3,996]; let maxNum = Math.max.apply(Math, numbers); let maxNum2 = Math.min.call(Math, 5,665,32,773,77,3,996); console.log(maxNum); console.log(maxNum2);
验证是不是数组(前提是toString()方法没有被重写过)this
function isArray(obj){ return Object.prototype.toString.call(obj) === '[object Array]'; } console.log(isArray(1)); console.log(isArray([1,2]));
类(伪)数组使用数组方法prototype
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
三、经过一个面试题去深刻理解下apply 和 call代理
定义一个 log 方法,让它能够代理 console.log 方法:
// 常规作法 function log(msg){ console.log(msg); } log(12); log(1,2)
上面可以基本解决打印输出问题,可是下面多参数的时候就gg了。换个更好的方式吧。
function log(){ console.log.apply(console, arguments); } log(12); log(1,2)
接下来是要在每一条打印信息前面都要加上一个特定字符串'fanchao`s'又怎么说呢?
function log(){ let args = Array.prototype.slice.call(arguments); args.unshift('(fanchao`s)'); console.log.apply(console, args); } log(12); log(1,2)
四、说完了call和apply,接下来讲说bind
bind() 方法与 apply 和 call 很类似,也是能够改变函数体内 this 的指向。
MDN的解释是:bind()方法会建立一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以建立它时传入 bind()方法的第一个参数做为 this,传入 bind() 方法的第二个以及之后的参数加上绑定函数运行时自己的参数按照顺序做为原函数的参数来调用原函数。
看个栗子:
var func = function(){ console.log(this.x); console.log(arguments); } func(); // undefined, {} var obj = { x: 2 } var bar = func.bind(obj,1); bar(); // 2 , {'0':1}
一个有意思的事:
var bar = function() { console.log(this.x); } var foo = { x: 3 } var sed = { x: 4 } var func = bar.bind(foo).bind(sed); func(); //3 var fiv = { x: 5 } var func = bar.bind(foo).bind(sed).bind(fiv); func(); //3
在Javascript中,屡次 bind() 是无效的。更深层次的缘由, bind() 的实现,至关于使用函数在内部包了一个 call / apply ,第二次 bind() 至关于再包住第一次 bind() ,故第二次之后的 bind 是没法生效的。
五、这三个方法的异同点是什么呢?
仍是先看个栗子:
var obj = { x: 81, }; var foo = { getX: function() { return this.x; } } console.log(foo.getX.bind(obj)()); //81 console.log(foo.getX.call(obj)); //81 console.log(foo.getX.apply(obj)); //81
看到bind后面对了一对括号。区别是,当你但愿改变上下文环境以后并不是当即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会当即执行函数。
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;apply 、 call 、bind 三者均可以利用后续参数传参;bind是返回对应函数,便于稍后调用;apply、call则是当即调用 。