JavaScript bind函数手写教程

 更新时间:2022年12月19日 11:04:17   作者:helloworld1024fd  
bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,当然这是绑定哦,不是像call、apply一样直接执行,apply要执行的话还得自己调用

经常会看到网上各种手写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.

其中需要注意的有一点是这条:

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过程中遇到的问题,记录探究的过程。通过一系列手写原生方法,锻炼了我们对于原理的进一步认识。但是也要注意验证,实际去操作几次,可能得出自己的经验。如果有更多的两者对比的发现,可以在评论里告诉我,欢迎各位大佬斧正。

到此这篇关于JavaScript bind函数手写教程的文章就介绍到这了,更多相关JS bind函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • javascript顺序加载图片的方法

    javascript顺序加载图片的方法

    这篇文章主要介绍了javascript顺序加载图片的方法,可实现javascript针对图片的逐次加载,从而减缓服务器压力,非常具有实用价值,需要的朋友可以参考下
    2015-07-07
  • layer弹出层取消遮罩的方法

    layer弹出层取消遮罩的方法

    今天小编就为大家分享一篇layer弹出层取消遮罩的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • JavaScript脚本延迟加载有哪些方式

    JavaScript脚本延迟加载有哪些方式

    本文主要介绍了JavaScript脚本延迟加载有哪些方式,主要介绍了五种方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-04-04
  • 详解原生JavaScript实现jQuery中AJAX处理的方法

    详解原生JavaScript实现jQuery中AJAX处理的方法

    这篇文章主要介绍了原生JavaScript实现jQuery中AJAX处理的方法,作者根据jQuery中一些对AJAX请求的处理方式来用原生API实现,需要的朋友可以参考下
    2016-05-05
  • 纯JavaScript 实现flappy bird小游戏实例代码

    纯JavaScript 实现flappy bird小游戏实例代码

    这篇文章主要介绍了纯JavaScript 实现flappy bird小游戏实例代码,b本文分七大步骤给大家介绍,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • createTextRange()的使用示例含文本框选中部分文字内容

    createTextRange()的使用示例含文本框选中部分文字内容

    这篇文章主要介绍了createTextRange()的使用示例,需要的朋友可以参考下
    2014-02-02
  • Javascript this 的一些学习总结

    Javascript this 的一些学习总结

    相信有C++、C#或Java等编程经验的各位,对于this关键字再熟悉不过了。由于Javascript是一种面向对象的编程语言,它和C++、C#或Java一样都包含this关键字,接下来我们将向大家介绍Javascript中的this关键字
    2012-08-08
  • 微信小程序表单验证错误提示效果

    微信小程序表单验证错误提示效果

    这篇文章主要为大家详细介绍了微信小程序表单验证错误提示效果,点击确认发布不能为空错误提示,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • javascript作用域容易记错的两个地方分析

    javascript作用域容易记错的两个地方分析

    javascript作用域容易记错的两个地方分析,学习js的朋友可以参考下
    2012-06-06
  • JS中appendChild追加子节点无效的解决方法

    JS中appendChild追加子节点无效的解决方法

    这篇文章主要给大家介绍了关于JS中appendChild追加子节点无效的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习
    2018-10-10

最新评论