我们可以看到都执行func时,第一个func函数的this指向的是window全局对象,而第二个func函数的this指向的是newFun 。
Function.prototype.apply = function (context, arr) {context = context ? Object(context) : window;context.fn = this;let result;//判断有没有参数数组输入if (!arr) {result = context.fn();} else {result = context.fn(...arr);}//此处也可以使用eval进行处理// const result = eval("context.fn(...arr)");delete context.fnreturn result; } 3.2 bindbind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用 。
bind(thisArg,param1,param2,...); 其实,bind的实现思路基本和apply一致,但是在最后实现返回结果时,bind不需要直接执行,而是以返回函数的形式返回结果,之后再通过执行这个结果即可 。
先分析下bind的特性:首先是指定新对象this指向,再传入参数返回一个定义的函数,最后使用柯里化进行调用 。同样的,我们也可以根据这些特性进行手动封装一个bind函数:
Function.prototype.bind = function(context){//先要判断调用bind函数的是不是函数,需要抛出异常if(typeof this !== "function"){throw new Error("this bind function must be userd to function");}//存储this的指向const self = this;//context是新对象this指向的目标对象,而参数就是在第一个参数之后的参数const args = Array.prototype.slice.call(arguments,1);//创建一个空对象const fun = function(){}//返回一个函数const funBind = function(){//返回所有的参数给bind函数const bindArg = Array.prototype.slice.call(arguments);//将传入的参数合并成一个新的参数数组,作为self.apply()的第二个参数return self.apply(this instanceof fun ? this : context,args.concat(bindArgs));/**********************说明************************************/}//空对象的原型指向绑定函数的原型fun.prototype = this.prototype;//空对象的实例赋值给 funBind.prototypefunBind.prototype = new fun();return funBinf; } 补充说明:
- this instanceof fun返回为true时,表示的是fun是一个构造函数,其this指向实例,直接将context作为参数输入
- this instanceof fun返回为false时,表示的是fun是一个普通函数,其this指向顶级对象window,将绑定函数的this指向context对象
Function.prototype.bind = function(context,...args){//先要判断调用bind函数的是不是函数,需要抛出异常if(typeof this !== "function"){throw new Error("this bind function must be userd to function");}//存储this的指向const self = this;const fBind = function(){self.apply(this instanceof self ? this: context, args.concat(Array.prototype.slice.call(arguments)));}if(this.prototype){fBind.prototype = Object.create(this.prototype);}return fBind; } 注意:Object.create()是es2015语法引入的新特性,因此在IE<9的浏览器是不支持的 。3.3 call【Javascript的New、Apply、Bind、Call知多少】call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数 。使用调用者提供的 this 值和参数调用该函数的返回值 。若该方法没有返回值,则返回 undefined 。
function.call(thisArg, param1, param2, ...) 注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组 。call函数的实现:
Function.prototype.call = function(context,...args){//将函数设置为对象的属性context = context || window;context.fn = this;//执行函数const result = eval("context.fn(...args)");//删除对象的这个属性delete context.fn;return result; } 4 参考文章- 《解析 bind 原理,并手写 bind 实现》
- 《解析 call/apply 原理,并手写 call/apply 实现》
- 《JavaScript核心原理精讲》
- apply、call改变了this指向后,会立即进行调用函数,返回的是执行结果
- bind在改变this指向后,返回的是一个函数,需要另外再进行调用一次
- bind、call传递的第一个参数都是this将要指向的对象,后面都是一个一个参数的形式输入
- apply传递的第一个参数也是this将要指向的对象,后面传递的第二个参数是一个参数数组
推荐阅读
- 有哪些不同的CSS前端框架可供选择?
- 专门针对chrome谷歌浏览器而开发的一款访问插件
- 什么叫TLD、gTLD、nTLD、ccTLD、iTLD 以及几者之间的关系
- 6个实用的 Python 自动化脚本,你学会了吗?
- 康乃馨的搭配方法,康乃馨与玫瑰搭配的花束图片
- 小菊花的品种,大菊花和小菊花功效区别
- 老倪青钱柳茶的功效与作用,老倪青钱柳茶的功效
- 菊花茶是什么样子的图片,香椿是什么样子图片
- 好运的向日葵微信头像,微信头像推荐
- 香薷治口臭原理,治口臭清毒素
