We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
call:可以指定函数运行时的this。与apply之间的区别是传参方式不同,call的参数是若干参数列表,apply接受的是一个包含多个参数的数组。 首先,我们先实现第一个功能,指定函数运行时的this:
call
this
apply
Function.prototype.fakeCall = function(obj) { // 在传入的 obj 上创建一个属性,将该属性指向调用的函数 obj.fn = this // 然后执行 fn,则会将调用的函数的 this 指向 obj obj.fn() // 最后将创建的 fn 属性删除 delete obj.fn }
尝试下效果:
Function.prototype.fakeCall = function(obj) { obj.fn = this obj.fn() delete obj.fn } let foo = { value: 1 } function bar(name, age) { console.log(this) // {value: 1, fn: ƒ} console.log(this.value) // 1 } bar.fakeCall(foo)
跟预想的一样,已将bar的this强行改变成了foo。 原生的call方法还可以接受参数,现在实现这个功能。很简单,没错,就是用es6去实现es3,当然用eval也可以。
bar
foo
es6
es3
eval
Function.prototype.fakeCall = function(obj) { // 取出除 obj 参数外剩下的参数 let args = [].slice.call(arguments, 1) obj.fn = this // 传入参数 obj.fn(...args) delete obj.fn }
看下效果如何:
Function.prototype.fakeCall = function(obj) { let args = [].slice.call(arguments, 1) obj.fn = this obj.fn(...args) delete obj.fn } let foo = { value: 1 } function bar(name, age) { console.log(name) // xuedinge console.log(age) // 20 } bar.fakeCall(foo, "xuedinge", "20")
可以看出,基本上已经实现了原生的call了。现在考虑一些特殊情况。 1、当调用函数有返回值时,会怎么样。(会是undefined) 2、当调用函数传入的this参数是null或者是其他基本数据类型时,会发生什么。(会报错) 根据上面个特殊情况,我们对fakeCall稍作调整。
undefined
fakeCall
Function.prototype.fakeCall = function(obj) { // 处理传入的值是基本数据类型的情况,特别是 null obj = typeof obj !== "object" ? window : obj || window let args = [].slice.call(arguments, 1) obj.fn = this // 将调用函数的返回值保存下来,然后用 return 返回 let result = obj.fn(...args) delete obj.fn return result }
看下效果如何。
Function.prototype.fakeCall = function(obj) { obj = typeof obj !== "object" ? window : obj || window let args = [].slice.call(arguments, 1) obj.fn = this let result = obj.fn(...args) delete obj.fn return result } let foo = { value: 1 } function bar(name, age) { console.log(name) // xuedinge console.log(age) // 20 return { color: "yuanliangse" } } console.log(bar.fakeCall(undefined, "xuedinge", "20")) // {color: "yuanliangse"}
aplly:跟call的实现基本相同,区别是对除this外,剩余的参数处理方式不同。直接上代码。
aplly
Function.prototype.fakeApply = function(obj) { obj = typeof obj !== "object" ? window : obj || window let args = [].slice.call(arguments, 1) obj.fn = this // args的第一个值就是传入的数组 let result = obj.fn(...args[0]) delete obj.fn return result }
bind:bind方法返回一个新的函数,在调用时,设置this为提供的值。新函数在调用时,将给定的参数列表作为原函数的参数序列的前若干项。 也就是说,bind具有以下功能:
bind
根据这些特性,我们可以实现一个简单的bind方法先。
Function.prototype.fakeBind = function(context) { const self = this // bind 方法传的参数 const bindArgs = [].slice.call(arguments, 1) return function() { // bind 方法返回的函数传入的参数 const newArgs = [].slice.call(arguments) return self.apply(context, bindArgs.concat(newArgs)) } }
看下效果如何,从下面的结果看,还是可以的。
const foo = { value: 1 } function bar(name, age) { console.log(this.value) console.log(name) console.log(age) } const bindTar = bar.fakeBind(foo, "daisy") bindTar("19") // 1、daisy、19
但是,现在有个问题,就是bind方法返回的新函数当构造函数使用时,bind方法提供的this要失效的,this要指向new构造出来的实例。关于这一点,简单来说就是新的函数this指向的问题,那么我们在给新的函数绑定this时,判断下是不是当构造函数使用就可以了。
new
Function.prototype.fakeBind = function(context) { const self = this // bind 方法传的参数 const bindArgs = [].slice.call(arguments, 1) const fBound = function() { // bind 方法返回的函数传入的参数 const newArgs = [].slice.call(arguments) return self.apply( // 当作构造函数使用时,this 指向实例,this instanceof fBound 为 true this instanceof fBound ? this : context, bindArgs.concat(newArgs) ) } // 将实例的原型指向绑定函数的原型 fBound.prototype = this.prototype return fBound }
这里需要注意一点,我们修改fBound的原型时,也会修改绑定函数的原型,所以,我们使用一个空函数中转一下绑定函数的原型。最终版的代码如下:
fBound
Function.prototype.fakeBind = function(context) { const self = this // bind 方法传的参数 const bindArgs = [].slice.call(arguments, 1) const fn = function() {} const fBound = function() { // bind 方法返回的函数传入的参数 const newArgs = [].slice.call(arguments) return self.apply( this instanceof fn ? this : context, bindArgs.concat(newArgs) ) } fn.prototype = this.prototype fBound.prototype = new fn() return fBound }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
先实现个call
call
:可以指定函数运行时的this
。与apply
之间的区别是传参方式不同,call
的参数是若干参数列表,apply
接受的是一个包含多个参数的数组。首先,我们先实现第一个功能,指定函数运行时的
this
:尝试下效果:
跟预想的一样,已将
bar
的this
强行改变成了foo
。原生的
call
方法还可以接受参数,现在实现这个功能。很简单,没错,就是用es6
去实现es3
,当然用eval
也可以。看下效果如何:
可以看出,基本上已经实现了原生的
call
了。现在考虑一些特殊情况。1、当调用函数有返回值时,会怎么样。(会是
undefined
)2、当调用函数传入的this参数是null或者是其他基本数据类型时,会发生什么。(会报错)
根据上面个特殊情况,我们对
fakeCall
稍作调整。看下效果如何。
apply的实现
aplly
:跟call
的实现基本相同,区别是对除this
外,剩余的参数处理方式不同。直接上代码。bind的实现
bind:bind方法返回一个新的函数,在调用时,设置this为提供的值。新函数在调用时,将给定的参数列表作为原函数的参数序列的前若干项。
也就是说,bind具有以下功能:
this
的值bind
方法可以传参,返回的新函数也可以传参根据这些特性,我们可以实现一个简单的
bind
方法先。看下效果如何,从下面的结果看,还是可以的。
但是,现在有个问题,就是
bind
方法返回的新函数当构造函数使用时,bind
方法提供的this
要失效的,this
要指向new
构造出来的实例。关于这一点,简单来说就是新的函数this
指向的问题,那么我们在给新的函数绑定this
时,判断下是不是当构造函数使用就可以了。这里需要注意一点,我们修改
fBound
的原型时,也会修改绑定函数的原型,所以,我们使用一个空函数中转一下绑定函数的原型。最终版的代码如下:The text was updated successfully, but these errors were encountered: