资讯专栏INFORMATION COLUMN

JavaScript专题之模拟实现bind

刘明 / 1653人阅读

摘要:但是三作为构造函数时函数其实还有一个非常重要的特点返回的函数如果作为构造函数,搭配关键字出现的话,我们的绑定就需要被忽略。其次,当返回的函数作为构造函数时,之前绑定的会失效。

本文共 1100 字,读完只需 4 分钟
概述

前一篇文章我们尝试模拟实现了 call 和 apply 方法,其实 bind 函数也可以用来改变 this 的指向。bind 和 call和 apply 两者的区别在于,bind 会返回一个被改变了 this 指向的函数。

本文介绍如何模拟实现 bind 函数:

首先观察 bind 函数有什么特点:

var person = {
    name: "jayChou"
}

function say(age, sex) {
    console.log(this.name, age, sex);
}

var foo = say.bind(person, "男", 39);

foo();  // jayChou 男 39

返回一个函数

函数参数以逗号的形式传入

改变了 this 的指向

一、call 简单实现

既然 bind 内部也要用改变 this 指向,我们可以用现成的 call 函数来实现这一功能。

Function.prototype.newBind = function(context) {
    if(typeof this !== "function") {
        throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var self = this;
    return function () {
        return self.call(context)
      }
}

说明一下:
if 判断是为了校验,只能让函数来调用此方法,并抛出错误。
第二个 return 是为了让返回的函数有返回值的功能。

测试一下:

var person = {
    name: "jayChou"
};

var say = function() {
    console.log(this.name);
}

var foo = say.newBind(person);
foo();  // jayChou

成功啦。

二、传递参数

刚才的函数是没有传递参数,当然不行,所以我们想办法把函数的参数也传递进去。

bind 函数有个特点,就是在绑定的时候可以传参,返回的函数还可以继续传参。

var person = {
    name: "jayChou"
};

var say = function(p1, p2) {
    console.log(this.name, p1, p2);
}

var foo = say.bind(person, 18);
foo(20);  // jayChou 18 20

还可以写成:

say.bind(person, 18)(20); // jayChou 18 20

好,进入正题,考虑传参的事。在前面的文章,我们讲过 arguments 类数组对象的一些特性,不能直接调用数组的方法,但是可以用原型方法间接来调用,我们采用 apply 的方式来传递参数。

Function.prototype.newBind = function(context) {
    if(typeof this !== "function") {
        throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);  // 间接调用数组方法,获取第一次传的参数
    
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments);
        return self.apply(context, args.concat(innerArgs))
      }
}


var person = {
    name: "jayChou"
};

var say = function(p1, p2) {
    console.log(this.name, p1, p2);
}

var foo = say.newBind(person, 18);  // 第一次传参
foo(20);  // 第二次传参

最后输出:

jayChou 18 20

结果正确,以上就完成了 bind 函数基本功能的实现。

但是!

三、作为构造函数时?

bind 函数其实还有一个非常重要的特点:

bind返回的函数如果作为构造函数,搭配new关键字出现的话,我们的绑定this就需要“被忽略”。

意思就是指:当使用 nuw 关键字把 bind 返回的函数作为构造函数,之前改变了指向的 this 就失效了。返回的函数的 this 就关联到了构造函数的实例对象上。

针对这个特点,需要再做一些修改:

Function.prototype.newBind = function(context) {
    if(typeof this !== "function") {
        throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);  // 间接调用数组方法,获取第一次传的参数
    
    let tempFn = function {};  // 利用一个空函数作为中转
    
    tempFn.prototype = this.prototype;  // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
    
    var resultFn = function () {
        var innerArgs = Array.prototype.slice.call(arguments);
        if (this instanceof tempFn) {  // 如果 返回函数被当做构造函数后,生成的对象是 tempFn 的实例,此时应该将 this 的指向指向创建的实例。
            return self.apply(this, args.concat(innerArgs));
        } else {
            return self.apply(context, args.concat(innerArgs))
        }
      }
      
    resultFn = new tempFn();
    return resultFn;
}
总结

本文尝试模拟实现了 bind 函数,bind 函数与 call,apply 函数的区别在于,bind 函数返回一个指定了 this 的函数,函数并未执行。其次,当返回的函数作为构造函数时,之前绑定的 this 会失效。

欢迎关注我的个人公众号“谢南波”,专注分享原创文章。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98854.html

相关文章

  • JavaScript深入系列15篇正式完结!

    摘要:写在前面深入系列共计篇已经正式完结,这是一个旨在帮助大家,其实也是帮助自己捋顺底层知识的系列。深入系列自月日发布第一篇文章,到月日发布最后一篇,感谢各位朋友的收藏点赞,鼓励指正。 写在前面 JavaScript 深入系列共计 15 篇已经正式完结,这是一个旨在帮助大家,其实也是帮助自己捋顺 JavaScript 底层知识的系列。重点讲解了如原型、作用域、执行上下文、变量对象、this、...

    fxp 评论0 收藏0
  • JS专题数组去重

    摘要:将元素作为对象的键,默认键对应的值为如果对象中没有这个键,则将这个元素放入结果数组中去。 前言 数组去重在日常开发中的使用频率还是较高的,也是网上随便一抓一大把的话题,所以,我写这篇文章目的在于归纳和总结,既然很多人都在提的数组去重,自己到底了解多少呢。又或者是如果自己在开发中遇到了去重的需求,自己能想到更好的解决方案吗。 这次我们来理一理怎么做数组去重才能做得最合适,既要考虑兼容性,...

    only_do 评论0 收藏0
  • JavaScript专题偏函数

    摘要:专题系列第十四篇,讲解偏函数以及如何实现一个函数定义维基百科中对偏函数的定义为翻译成中文在计算机科学中,局部应用是指固定一个函数的一些参数,然后产生另一个更小元的函数。 JavaScript 专题系列第十四篇,讲解偏函数以及如何实现一个 partial 函数 定义 维基百科中对偏函数 (Partial application) 的定义为: In computer science, pa...

    beita 评论0 收藏0
  • 【进阶 6-2 期】深入高阶函数应用柯里化

    摘要:引言上一节介绍了高阶函数的定义,并结合实例说明了使用高阶函数和不使用高阶函数的情况。我们期望函数输出,但是实际上调用柯里化函数时,所以调用时就已经执行并输出了,而不是理想中的返回闭包函数,所以后续调用将会报错。引言 上一节介绍了高阶函数的定义,并结合实例说明了使用高阶函数和不使用高阶函数的情况。后面几部分将结合实际应用场景介绍高阶函数的应用,本节先来聊聊函数柯里化,通过介绍其定义、比较常见的...

    stackvoid 评论0 收藏0
  • JavaScript专题模拟实现new

    摘要:模拟实现操作符构造函数返回结果创建一个空对象取传入的第一个参数,即构造函数,并删除第一个参数。二处理返回值构造函数也是函数,有不同类型返回值。有时候构造函数会返回指定的对象内容,所以要对这部分进行处理。 本文共 1230 字,读完只需 5 分钟 写在前面 最近工作太忙,快接近两周没更新博客,总感觉有一些事情等着自己去做,虽然工作内容对自己提升挺大,但我总觉得,一直埋着头走路,偶尔也...

    pingink 评论0 收藏0

发表评论

0条评论

刘明

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<