关于javascript:面试官能用JavaScript手写一个bind函数吗

常常会看到网上各种手写bind的教程,上面是我在本人实现手写bind的过程中遇到的问题与思考。如果对于如何实现一个手写bind还有纳闷的话,那么能够先看看下面两篇文章。

手写bind vs 原生bind

咱们先应用一个典型的手写bind的例子,代码如下:

Function.prototype.bind2 = function (context) {
    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fNOP = function () {};

    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;
}

咱们首先用原生bind运行一下代码

function Foo(a) {this.a = a}
Foo.prototype.sayHi = function( ) {}
let _Foo = Foo.bind(undefined, 'a')
new _Foo() 

更多面试题解答参见 前端手写面试题具体解答

而后应用手写版代码,运行同样的代码

function Foo(a) {this.a = a}
Foo.prototype.sayHi = function( ) {}
let _Foo = Foo.bind2(undefined, 'a')
new _Foo() 

咱们能够看到相比原生bind办法,手写版的bind办法返回的构造函数,结构进去的新对象会比原生的多一层__proto__。而这个__proto__产生的起因就是在很多教程中提到的避免原型链篡改

这也就是为什么很多的文章会通知你,为什么要增加上面的代码。

var fNOP = function () {};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();

这段代码中,应用了一个空函数作为直达,相当于Object.create(fBound.prototype)。具体能够查看文章结尾给出的文章,外面的具体的阐明。

标准中的bind

既然说道,加上面的代码是为了避免原型链篡改。我就想看看原生的bind如何解决这个问题的呢?

function Foo(a) {this.a = a}
Foo.prototype.sayHi = function( ) {}
let _Foo = Foo.bind(undefined, 'a')
_Foo.prototype.sayHi = function( ) {console.log('篡改的_Foo的sayHi办法')}
(new _Foo().sayHi())

我发现在运行下面的代码,程序执行到批改_Foo的原型办法的语句时,就曾经报错了。提醒表明_Foo没有prototype属性!既然没有prototype属性,那么是不是也就不必解决原型链篡改的问题了呢?

之后,我查了一下标准, 在NOTE中,有上面一段话。明确指出了bind返回的函数是没有prototype属性,这也多少印证了下面的猜测。

Function objects created using Function.prototype.bind do not have a prototype property or the [[Code]], [[FormalParameters]], and [[Scope]] internal properties.

其中须要留神的有一点是这条:

  1. Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in 15.3.3.1.

我本人了解的意思是是bind进去的函数对象的prototype属性是内建的Function.prototype属性, 这里应该是阐明了为什么原生的bind不会多一层__proto__属性

小结

写这篇的目标是总结下本人在实现bind过程中遇到的问题,记录探索的过程。通过一系列手写原生办法,锤炼了咱们对于原理的进一步意识。然而也要留神验证,理论去操作几次,可能得出本人的教训。如果有更多的两者比照的发现,能够在评论里通知我,欢送各位大佬斧正。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理