首先我要先搞懂这三个方法怎么用数组
1. call( )
语法app
fun.call(thisArg, arg1, arg2, ...)
第一个参数理解为要在哪里执行fun(运行时指定的this值,他不必定是该函数执行时真正的this值,若是这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象),后面的一串参数意思是执行fun时的传参函数
返回值是你调用的方法(fun)的返回值,若该方法没有返回值,则返回undefinedthis
实现call开始prototype
// 首先没有给一个传入参数形式context Function.prototype._call(context){ // 就要判断实际调用有没有这个参数 let context = context ? context : window // 此时这个context就替代了上面的target context.func = this let result = context.func(args) // 拿参数这步省略了,无错,按照我本身的写法这样也能够 /* let [target, ...args] = [...arguments] 判断了传入的目标对象是null等状况,再赋值window实际也能成功 if(target == null || undefined){ target = window; } */ return result // 别忘记删除方法,这句写在return前面 delete context.func } // 最终我本身不看答案写出的结果以下,实测能够 不知道有没有潜在问题 Function.prototype._call = function(){ // let cont = context ? context : window let [target, ...args] = [...arguments] if(target == null || undefined){ target = window; } target.fn = this let result = target.fn(...args) delete target.fn return result }
2.apply( )
语法指针
fun.apply(obj,args)
第一个参数仍然理解为要在哪里执行fun,第二个参数是一个数组。code
两种方法意思是同样的,只是传参方式不一样。call后面能够给不少,而apply就只能给一个数组,在实际状况中按需使用吧。(我今天看懂继承再看看能多说点什么,还有试一下apply的返回是否是同样)对象
实现apply开始继承
Function.prototype._apply = function(){ // 一切和call都差很少 let [target, ...args] = [...arguments] // 考虑不传参 做用域的状况 if(target == null || undefined){ target = window } target.fn = this let result // 考虑参数存在状况。 if(args){ // 这里踩坑了,实际调用过程仍是会把数组转化成非数组的 要加上... result = target.fn(...args) }else{ result = target.fn() } delete target.fn return result // 有了call作铺垫基本还行,主要是判断args是否存在,还有参数是 数组的问题 }
3.bind( ) ip
bind 是返回新的函数,以便稍后调用;apply 、call 则是当即调用原函数。也就是说 要定义一个新的变量 把bind返回的方法赋予给这个变量再去执行
语法
fun.bind(thisArg[, arg1[, arg2[, ...]]])
第一个参数我已经能够理解了,这里有一个新特性,就是若是bind返回的函数以new的形式去调用,第一个参数会被忽略,this仍然指向被调用的函数(fun)
arg1, arg2, … (可选)当绑定函数被调用时,要将这些参数(若是有的话)做为bind()的参数写在this后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。
也就是说bind能够实现预设一些函数参数的功能(有啥用)
如下有两个例子来表达上面两点,搜来的:
function original(x){ this.a=1; this.b =function(){return this.a + x} } var obj={ a:10 } var newObj = original.bind(obj,2) //传入了一个实参2 var newObjChild = new newObj() console.log(newObj.a) //输出 1, 说明返回的函数用做构造函数时obj(this的值)被忽略了 console.log(newObj.b()) //输出3 ,说明传入的实参2传入了原函数original
var sum = function(x,y) { return x + y }; var succ = sum.bind(null, 1); //让this指向null,其后的实参也会做为实参传入被绑定的函数sum succ(2) // => 3: 能够看到1绑定到了sum函数中的x
另外的,bind和函数柯里化好像有点关系,一下子回家讨论下
实现bind开始
bind好难我本身写不出来,只好一遍一遍看了
Function.prototype._bind = function(context){ if(typeof this !== 'function'){ throw new TypeError('被绑定的对象须要是函数') } var self = this // 保存起原指针(做用域) var args = [].slice.call(arguments, 1) console.log(arguments) // =====> bind被调用时的传入参数 fBound = function(){ // this instanceof fBound === true时,说明返回的fBound被当作new的构造函数调用 console.log(arguments) // =====> bind返回的函数fBound被调用时传入的参数 return self.apply(this instanceof fBound ? this : context, args.concat([].slice.call(arguments))) /* 若是被Fbound被用做了构造函数, 构造出的实例必定是Fbound类型, 若是没有,那么当前的this和Fbound没有任何关系。 参数为bind被调用时和Fbound被调用时的参数联合 */ } // ----------------------------------------------- var func = function(){} // 这个究竟是干吗的?? //维护原型关系 console.log(this.prototype) // 一个constructor指向原函数 console.log(func.prototype) // 什么都没有 if(this.prototype){ func.prototype = this.prototype } //使fBound.prototype是func的实例,返回的fBound若做为new的构造函数,新对象的__proto__就是func的实例 fBound.prototype = new func() // ------------------------------框住的我先不看了 不能理解 return fBound }
留一个最新的MDN的polyfill
Function.prototype.bind = function() { var thatFunc = this, thatArg = arguments[0]; var args = slice.call(arguments, 1); if (typeof thatFunc !== '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'); } return function(){ var funcArgs = args.concat(slice.call(arguments)) return thatFunc.apply(thatArg, funcArgs); }; };