《JavaScript: The Definitive Guide》web
call()和apply()的第一个实参是要调用函数的母对象,它是调用上下文,在函数体内经过this来得到对它的引用。简单来讲就是把一个方法绑定到一个对象上去调用:编程
栗如,要想以对象o的方法来调用函数f():数组
f.call(o); f.apply(o);
其实至关于:闭包
o.m = f; //将f存储为o的临时方法 o.m(); //调用它,不传入参数 delete o.m; //将临时方法删除
--> 对于call(),第一个实参以后的全部实参就是要传入待调用函数的值。栗如:app
//以对象o的方法的形式调用函数f(),并传入两个参数 f.call(o, 1, 2);
--> 对于apply(),它的实参都放入一个数组当中:ide
f.apply(o,[1, 2]);
给apply()传入的参数数组能够是任意长度的,栗如:函数式编程
//找出一个数组中最大的数值元素 var biggest = Math.max.apply(Math, array_of_numbers);
传入apply()的参数数组能够是类数组对象也能够是真实数组。实际上,能够将当前函数的arguments数组直接传入apply()来调用另外一个函数:函数
//将对象o中名为m的方法替换为另外一个方法 //能够在调用原始方法以前和以后记录日志消息 function trace(o, m) { var original = o[m];//在闭包中保存原始方法 o[m] = function() {//定义新的方法 console.log(new Date(), 'Entering', m); var result = original.apply(this, arguments);//调用原始函数 console.log(new Date(), 'Exiting', m); return result; }; } //这个新方法是包裹原始方法的另外一个泛函数 (monkey-patching)?
bind()是ES5中的方法。
当在函数f()上调用bind()方法并传入一个对象o做为参数,这个方法将返回一个新的函数,(以函数调用的方式)调用新的函数将会把原始的函数f()看成o的方法来调用。传入新的函数的任何实参都讲传入原始函数。栗如:ui
function f(y) { return this.x + y; } var o = { x: 1 }; var g = f.bind(o); g(2); //=> 3
能够用ES3简单模拟:this
function bind(f, o) { if(f.bind) return f.bind(o); else return function() { return f.apply(o, arguments); } }
然而,bind()方法不单单是将函数绑定至一个对象----除了第一个参数外,传入bind()的实参也会绑定至this,这个附带的应用是一种常见的函数式编程技术,也被称为“柯里化“。
function f(y, z) { return this.x + y + z } var g = f.bind({ x: 1 }, 2); g(3);//=> 6 this.x绑定到1, y绑定到2, z绑定到3
若是用ES3模拟:
if(!Function.prototype.bind){ Function.prototype.bind = function(o /*, args*/){ //将this和arguments的值保存至变量中 //以便在后面嵌套的函数中能够使用它们 var self = this, boundArgs = arguments; //bind方法的返回值是一个函数 return function(){ //建立一个实参列表,将传入bind()的第二个及后续的实参传入这个参数 var args = [], i; for(i=1; i<boundArgs.length; i++){ args.push(boundArgs[i]; } for(i=0;i<arguments.length;i++){ args.push(arguments[i]; } //如今将self做为o的方法来调用,传入这些实参 return self.apply(o, args); }; }; }
http://web.jobbole.com/83642/
深刻浅出妙用 Javascript 中 apply、call、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
三个输出的都是81,可是注意看使用 bind() 方法的,他后面多了对括号。
也就是说,区别是,当你但愿改变上下文环境以后并不是当即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会当即执行函数。
一个总结:
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者均可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是当即调用 。
一道题:
定义一个 log 方法,让它能够代理 console.log 方法
function log(){ console.log.apply(console, arguments); }
若要给每个 log 消息添加一个”(app)”的前辍?
//该怎么作比较优雅呢?这个时候须要想到arguments参数是个伪数组,经过 //Array.prototype.slice.call 转化为标准数组,再使用数组方法unshift function log(){ var args = Array.prototype.slice.call(arguments); args.unshift('(app)'); console.log.apply(console, args); }