You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
letprofile={name: "walter",info: function(age){console.log("I am ",this.name+" and "+age+" years old");}};letjudegment={name: "handsome Boy",};profile.info(25);// I am walter and 25 years old
然后使用apply以及call方法
// 数组形式profile.info.apply(judegment,[25]);// I am handsome Boy and 25 years old// 参数序列形式profile.info.call(judegment,25);// I am handsome Boy and 25 years old
Function.prototype.applyMe=function(context){// 获取被调用的函数,假想context对象预先不存在名为fn的属性// 根据传入的实参循序,context是对象judegmentcontext.fn=this;// 获取参数,使用ES6扩展运算和解构赋值,args = [25]let[args]=[...(Array.from(arguments).slice(1))]// 执行被调用的函数context.fn(...args);//删除临时属性fndeletecontext.fn;}letprofile={name: "walter",info: function(age){console.log("I am ",this.name+" and "+age+" years old");}};letjudegment={name: "handsome Boy",};profile.info.applyMe(judegment,[25]);// I am handsome Boy and 25 years old
// 数组形式 profile.info.bind(judegment)([25]);// I am handsome Boy and 25 years old// 参数序列形式profile.info.bind(judegment)(25);// I am handsome Boy and 25 years old
bind函数使用的场景的主要特点就是绑定this但不要像call、apply那样立即执行
varname='window'functionPerson(name){this.nickname=name;this.sayHi=function(){setTimeout(function(){console.log("Hello, my name is "+this.nickname);},500);}}varp=newPerson('walter');p.sayHi();//Hello, my name is window
functionPerson(name){this.nickname=name;this.sayHi=function(){setTimeout(function(){console.log("Hello, my name is "+this.nickname);}.bind(this),500);// 将this指向了Person构造函数,函数实例化后也就thsi指向了该实例}}varp=newPerson('walter');p.sayHi();// "Hello, my name is walter"
// 兼容处理:嗅探下原生有没有bind方法Function.prototype.bind=Function.prototype.bind||function(){// 调用bind方法的一定得是个函数if(typeofthis!=="function"){thrownewTypeError("Function.prototype.bind - what is trying to be bound is not callable");}varfunc=this;// 需要绑定的原函数varargs=[].slice.call(arguments);// 获取bind()中的参数varcontext=args.shift();// 拿到this,此时args数组中只有参数varF=function(){};varbound=function(){// 将bind()中的参数与 func中的参数合并// 这里的this是func所在的上下文环境,也就是window对象且并非函数的实例,该情况下this = context// args.concat([].slice.call(arguments)))来实现上面提到的bind的科里化returnfunc.apply(thisinstanceofF ? this : context,args.concat([].slice.call(arguments)));}// 寄生模式继承原函数的原型F.prototype=this.prototype;bound.prototype=newF();returnbound;};// 测试下functionfoo(){this.b=100;returnthis.a}varfunc=foo.bind({a:1})func();// this.a = 1
通过分析call()原理实现bind的polyfill来考验下基础吧
前言
最近在看文章的时候多次看到改变上下文环境中使用了bind方法,突然想写一下其polyfill方法,结果憋不出来,虽说没有什么实际意义,但后来学习后也算是对基础知识又一次的加固。
文字叙述不多,更多都在代码的注释中。
call、apply、bind的用法这里就不再赘述,其作用都是在指定的上下文环境中调用函数。
bind返回函数,而call、apply 返回函数并立即执行
bind涉及到函数科里化,实参可以少于形参; 而call、apply实参必须大于等于形参
apply接收两个参数,上下文环境和数组参数;而call第二个参数得是参数序列,就好像打电话一样,总得一个个数字拨打过去吧
还是简单的看个Demo吧:
然后使用apply以及call方法
call和apply的原理分析
不论是call还是apply其实本质上来讲做了两件事:
1、绑定上下文,也就是绑定了this的指向
2、profile.info()执行
通过下面这张图可以知道,
f.call(o)
函数的实现原理是先通过o.m=f将f作为对象o.m的属性值,执行后再删除该属性m。根据这个原理重新分析下刚刚
profile.info.call(judegment, 25)
的执行过程:基于以上原理来逐步实现apply方法
apply的实现步骤
第一步:实现功能
缺点:
1、边界问题:this可以传null或者不传,this就指向window
2、函数直接调用,要有返回值
第二步:修改边界问题和返回值
缺点:
1、属性名的唯一性:假想context对象预先不存在名为fn的属性,但若是context对象本来有fn这个属性则会重写,无法保证唯一性。
第三步:保证唯一性
ES6中提供了除
Undefined、Null、Boolean、String、Number
以外的第六种基本数据类型Symbol
,它用来避免属性名的冲突,确保了唯一性。Symbol函数可以接受一个字符串作为参数,表示Symbol实例。由于其唯一性,所以不能与其他类型的值进行计算通过Symbol()方法接收字符串,就能确保了属性名的唯一性了。
bind函数使用场景
bind函数的语法是这样样子的:fun.bind(thisArg[, arg1[, arg2[, ...]]])
虽然长得和call方法的语法差不多,但它们实质是不一样的。就像,老婆饼就一定是老婆做的么? 如果有,那也是别人的老婆~
传入bind方法的第一个参数作为this,传入第二个参数以及函数自带的参数按照顺序作为新的参数。可以看到bind函数并不是立即执行的,而是绑定上下文环境后再手动执行。
bind函数使用的场景的主要特点就是绑定this但不要像call、apply那样立即执行
这个时候输出的this.nickname是window,原因是this指向是在运行函数时确定的,而不是定义函数时候确定的,而setTimeout在全局环境下执行,所以this指向setTimeout的上下文:window。所以问题的关键之处就是要将setTimeout函数的上下文环境绑定在Person的实例上
新手经常犯的一个错误是将一个方法从对象中拿出来赋值给一个变量,然后再调用该变量,这样做一般会将this不能继续指向原来的对象:
bind函数Polyfill
上面讲完了bind方法的常见场景,现在来实现一下bind函数Polyfill
兼容构造函数
最终版本
参考文章
不用call和apply方法模拟实现ES5的bind方法
前端基础进阶(八):深入详解函数的柯里化
ECMAScript 6 入门
The text was updated successfully, but these errors were encountered: