bind call apply 的区别和使用:https://www.jianshu.com/p/015f9f15d6b3javascript
在讲这个以前要理解一些概念,这些概念很重要,有人说过学会了javascript 的this 就基本会了一半的javascripthtml
在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。java
定义时上下文
运行时上下文
上下文是能够改变面试
若是要深刻理解这个知识要开个javascript 内存管理机制和运行原理了,这里就不作过多的介绍了。数组
function Fruits() {} Fruits.prototype = { color: "red", printf: function() { console.log("My color is " + this.color); } } var apple = new Fruits; apple.printf(); //My color is red // 改变this banana = { color: "yellow" } apple.printf.call(banana); //My color is yellow apple.printf.apply(banana); //My color is yellow // 经过call apply这两个来改变上下文的this指向
call ,apply 方法是同样的只是传递的参数不一样而已,call(obj,args1,args2)
apply(obj,[args1,args2]) ,这样很明显看出区别了吧!app
var array1 = [12 , "foo" , {name "Joe"} , -2458]; var array2 = ["Doe" , 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 值为 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */ // 这样子优雅的解决了push 方法子传递一个参数的问题了。固然数组合并有contact 方法来合并的 // 比较数组的大小,使用 apply 做为传递数组的必选方法。 var numbers = [5, 458 , 120 , -215 ]; var maxInNumbers = Math.max.apply(Math, numbers), //458 maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458 // 判断是不是数组 前提是toString 方法没有被重写。 functionisArray(obj){ return Object.prototype.toString.call(obj) === '[object Array]' ; } // 将伪数组转成数组 // ES6 有方法 Array.from(args) 转化 var dom = Array.prototype.slice.call(document.getElementsByTagName("div")); // 这样 domNodes 就可使用pop() ,push() 等方法了。
封装console.log 方法dom
function log(){ console.log.apply(console, arguments); }; log(1); //1 log(1,2); //1 2 // 这是一道面试题这样的方法能够说是最优雅的了 // 我也是今天才知道他们两能力这么大 function log(){ var args = Array.prototype.slice.call(arguments); var tim = new Date.getTime() args.unshift(tim); console.log.apply(console, args); }; // 这个就能够优雅的给log 方法带上一个时间搓的前缀啦,是否是很是的棒。函数的不定参 arguments 是伪数组来的 //写了这么多相信各位已经明白了,我如今才知道这两个方法的强大,之前一直认为只是改变this这么简单,其实也改变this啊!
再来讲说bind。bind() 方法与 apply 和 call 很类似,也是能够改变函数体内 this 的指向。函数
个人解释是:bind()方法会建立一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以建立它时传入 bind()方法的第一个参数做为 this,传入 bind() 方法的第二个以及之后的参数加上绑定函数运行时自己的参数按照顺序做为原函数的参数来调用原函数。ui
直接来看看具体如何使用,在常见的单体模式中,一般咱们会使用 _this , that , self 等保存 this ,这样咱们能够在改变了上下文以后继续引用到它。 像这样:this
var foo = { bar : 1, eventBind: function(){ var _this = this; $('.someClass').on('click',function(event) { /* Act on the event */ console.log(_this.bar); //1 }); } } // 使用 bind 方法 var foo = { bar : 1, eventBind: function(){ $('.someClass').on('click',function(event) { /* Act on the event */ console.log(this.bar); //1 }.bind(this)); } } // 多个bind var bar = function(){ console.log(this.x); } var foo = { x:3 } var sed = { x:4 } var func = bar.bind(foo).bind(sed); func(); //? var fiv = { x:5 } var func = bar.bind(foo).bind(sed).bind(fiv); func(); //3 第一个值,第二个失效了
Function.prototype.bind= function(obj){ if (Function.prototype.bind) return Function.prototype.bind; var _self = this, args = arguments; return function() { _self.apply(obj, Array.prototype.slice.call(args, 1)); } } // 可能你们会有疑惑,这里为何return 一个函数回去,由于bind()不是调用就执行的因此在这里返回一个函数。 // MDN的方法 if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { return fToBind.apply(this instanceof fNOP ? this : oThis, // 获取调用时(fBound)的传参.bind 返回的函数入参每每是这么传递的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 维护原型关系 if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }; } // 也就是加了比较严格的判断。
从bind 的源码中能够看出跟 call ,apply 的却别了吧!
bind调用完成后不执行,call,apply是立刻执行。相互之间是互通的
bind不兼容(IE5,6,7,8)
参考文献:
http://www.javashuo.com/article/p-bywxlvak-dk.html
https://blog.csdn.net/u012443286/article/details/78633540