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
这三个货,都是用来绑定 this 的。区别如下:
this
call()
apply()
bind()
new
假设没有 Function.prototype.call() 方法,我们利用 this 默认绑定的特性处理即可。
Function.prototype.call()
Function.prototype.myCall() { // 获取执行函数 const fn = this // 获取绑定对象,及参数列表 const [context, ...args] = arguments // 避免与绑定对象属性冲突,采用 Symbol 值作为属性键,并将执行函数赋予该属性。 const key = Symbol() context[key] = fn // 执行函数并返回结果 const res = context[key](...args) // 移除临时属性 delete context[key] // 返回结果 return res }
还没完,请注意以下两种情况:
context
undefined
null
globalThis
window
Function.prototype.myCall = function () { const fn = this const [ctx, ...args] = arguments const context = ctx == undefined ? window : Object(ctx) const key = Symbol() context[key] = fn const res = context[key](...args) delete context[key] return res }
再简化一下:
Function.prototype.myCall = function (ctx, ...args) { const key = Symbol() const context = ctx == undefined ? window : Object(ctx) context[key] = this const res = context[key](...args) delete context[key] return res }
我们知道,Function.prototype.apply() 和 Function.prototype.call() 的区别仅在接收参数的形式不同,前者接收一个数组。
Function.prototype.apply()
基于上面的实现,简单修改下函数执行的参数即可。
Function.prototype.myApply = function (ctx, ...args) { const key = Symbol() const context = ctx == undefined ? window : Object(ctx) context[key] = this const res = context[key](args) // 与 call 方法的区别点 delete context[key] return res }
我们知道,Function.prototype.bind() 参数形式与 Function.prototype.call() 相同,区别在于 bind() 返回一个绑定了 this 的新函数。
Function.prototype.bind()
其实,我们可以很快就写出以下方法:
Function.prototype.myBind = function (ctx, ...args) { const fn = this return function (...newArgs) { return fn.apply(ctx, [...args, ...newArgs]) } }
但是,这是不完全正确的...
需要注意的是,bind() 方法返回的新函数,若通过 new 关键字进行调用,那么 this 绑定则不生效。
举个例子:
const person = { name: 'Frankie' } function Foo(name) { this.name = name } const Bar = Foo.bind(person) const bar = new Bar('Mandy') console.log(person.name) // "Frankie" console.log(bar.name) // "Mandy"
假设 Foo.bind(person) 生效的话,那么 new Bar('Mandy') 中 this.name 应该是 person.name = 'Mandy',修改的应该是 person 对象的 name 属性,但事实并非如此。
Foo.bind(person)
new Bar('Mandy')
this.name
person.name = 'Mandy'
person
name
顺道总结一下 this 绑定的优先级: 只要使用 new 关键字调用,无论是否含有 bind 绑定,this 总指向实例化对象。 通过 call、apply 或者 bind 显式绑定,this 指向该绑定对象。若第一个参数缺省时,则根据是否为严格模式,来确定 this 指向全局对象或者 undefined。 函数通过上下文对象调用,this 指向(最后)调用它的对象。 如以上均没有,则会默认绑定。严格模式下,this 指向 undefined,否则指向全局对象。
顺道总结一下 this 绑定的优先级:
bind
call
apply
因此,我们来完善一下 myBind() 方法:
myBind()
Function.prototype.myBind = function (ctx, ...args) { const fn = this return function newFn(...newArgs) { // 若通过 new 关键字调用,有几种方式可以判断: // 1. this instanceof newFn // 2. this.__proto__.constructor === newFn // 3. new.target 不为 undefined if (new.target) { return new newFn(...args, ...newArgs) } return fn.apply(ctx, [...args, ...newArgs]) } }
去掉注释,就长这样:
Function.prototype.myBind = function (ctx, ...args) { const fn = this return function newFn(...newArgs) { if (new.target) { return new newFn(...args, ...newArgs) } return fn.apply(ctx, [...args, ...newArgs]) } }
总的来说,其实并不能,真正了解 this 原理,要手写这几个常考的面试题,其实很简单哈。
插个话,我认为对于初学者来说,千万不要把作用域(链)和 this 混为一谈,其实它们完全就是两回事。作用域(链)与闭包相关,它在函数被定义时就已“确定”,不会再变了。而 this 则与函数调用相关。
这里将此前写过关于 this 的文章列举出来:
The text was updated successfully, but these errors were encountered:
No branches or pull requests
这三个货,都是用来绑定
this
的。区别如下:call()
、apply()
都返回函数执行结果,区别在于参数不一样,前者接收参数列表,后者接收一个数组参数(也可以是类数组)。bind()
返回一个新函数,但注意对使用new
关键字调用时,绑定无效。其使用方法与call()
一致,接受一个参数列表。一、call 实现
假设没有
Function.prototype.call()
方法,我们利用this
默认绑定的特性处理即可。还没完,请注意以下两种情况:
context
为undefined
或null
的情况。若处于非严格模式,context
应指向顶层对象globalThis
,在浏览器为window
对象。context
为其他原始值(不是undefined
、null
),应该要将其转换为对应的引用值。再简化一下:
二、apply 实现
我们知道,
Function.prototype.apply()
和Function.prototype.call()
的区别仅在接收参数的形式不同,前者接收一个数组。基于上面的实现,简单修改下函数执行的参数即可。
三、bind 实现
我们知道,
Function.prototype.bind()
参数形式与Function.prototype.call()
相同,区别在于bind()
返回一个绑定了this
的新函数。其实,我们可以很快就写出以下方法:
但是,这是不完全正确的...
举个例子:
假设
Foo.bind(person)
生效的话,那么new Bar('Mandy')
中this.name
应该是person.name = 'Mandy'
,修改的应该是person
对象的name
属性,但事实并非如此。因此,我们来完善一下
myBind()
方法:去掉注释,就长这样:
总的来说,其实并不能,真正了解 this 原理,要手写这几个常考的面试题,其实很简单哈。
References
这里将此前写过关于
this
的文章列举出来:The text was updated successfully, but these errors were encountered: