this硬绑定

一、this显式绑定

this显式绑定,顾名思义,它有别于this的隐式绑定,而隐式绑定必须要求一个对象内部包含一个指向某个函数的属性(或者某个对象或者上下文包含一个函数调用位置),并通过这个属性间接调用这个函数,从而把this间接/隐式绑定到这个对象上。但是this的隐式绑定存在一个 绑定对象丢失问题,如下面代码所示:

function afun() {
    console.log(this.a);
}

var obj = {
    a: 1,
    afun: afun
};

var a = "hello";

setTimeout(obj.afun, 100);//"hello"

出人意料的是,控制台打印出来的结果是全局变量a的结果,而不是拥有指向函数属性的对象的a的值,这就是隐式绑定的对象丢失,回调函数丢失绑定对象是非常常见的。

但是,显式绑定仍然不能解决绑定对象丢失的问题,但是显式绑定的一个变种,即硬绑定可以解决绑定对象丢失。

在此之前,我们先来看看什么是显式绑定。

我们可以通过使用函数的call()和apply()方法实现this显式绑定,绝大多数内置函数和自定义函数都可以调用这两种方法。他们均接收两个参数

  • 参数:
  • thisArg: 要绑定到调用者this的对象。
    • arg1, arg2, ...(call):指定的参数列表,即要传给调用者的参数。比如a.call(obj, args)/a.apply(obj, args),args为参数传给调用者函数a作为该函数的实参。
    • argsArray(apply):一个数组或者类数组对象,如果该参数的值为nullundefined,则表示不需要传入任何参数。
  • 返回值:调用者函数若有返回值则返回该值,没有返回值则返回undefined。

来看下面的代码:

function bfun() {
    return this.a;
}

var obj1 = {
    a: "hello"
};

console.log(bfun.apply(obj1), bfun.call(obj1));//"hello" "hello"

若传入的第一个参数时一个原始值呢?来看下面的代码:

没错,原始值被转换成了它的对象形式,也就是new Number(),这被成为”装箱”。

但是,我们前面提到过,this显式绑定虽然强大,但是仍然不能解决this绑定丢失问题。下面我们来解释硬绑定,即显式绑定的一个变种,它能完美解决this绑定丢失问题。

二、硬绑定

先来看看下面的代码:

function cfun() {
    console.log(this.a)//"hello"
    return this.a;
}

var obj2 = {
    a: "hello"
};

var fn = function() {
    return cfun.apply(obj2);
};
console.log(fn());//"hello"

setTimeout(fn, 100);//"hello"

可以看到,硬绑定确实解决了this绑定丢失,但值得注意的是,通过apply()绑定的this对象,无法二次更改绑定对象:

function f() {
console.log( this.a );
}
var obj = {
a:2
};
var b = function() {
f.call( obj );
};
b(); // 2

b.call( window ); // 2

硬绑定的一个典型应用场景是创建一个 包裹函数,传入所有的参数给调用者函数并返回接收到的所有值。

function dfun(v) {
    return (v[0] + this.a);
}

var obj3 = {
    a: 10
};

var fn1 = function() {
    return dfun.call(obj3, arguments);
}

var result = fn1(6);
console.log(result);//16

对于arguments而言,call()和apply()的不同之处在于他们的参数类型不同:

function efun(v) {
    console.log(..v)//6 10 11
    return (v);
}

var obj4 = {
    a: 10
};

var fn1 = function() {
    return efun.apply(obj3, arguments);
}

var result = fn1([6, 10, 11]);
console.log(result);//[6, 10, 11]

也就是说call()的参数类型是Object,它传入的参数列表会被转换为键为’0’(随传入参数数量递增),值为传入参数的对象;而apply()的参数类型则是数组或者类数组。

function dfun(v) {
    return (v);
}

var obj3 = {
    a: 10
};

var fn1 = function() {
    return dfun.call(obj3, arguments);
}

var result = fn1(6, 19, 1, 1);
console.log(result);//[Arguments]{'0':6,'1':19,2':1,3':1}
console.log(typeof result);//'object'

最强大的一种方法是将包裹函数创建为可以重复使用的辅助函数,封装可重复使用的硬绑定。

function ffun(v) {
    return this.a * v;
}

var obj5 = {
    a: 5,
};

var fn2 = function(fn, obj) {
    return function() {
        return fn.apply(obj, arguments);
    }
}

var bind = fn2(ffun, obj5);
console.log(bind(10));//50

由于硬绑定十分常用,但通过包裹函数创建可重复使用的硬绑定比较麻烦,所以ES5提供了一个实现相同功能的方法bind()。用法如下:

function hfun(v) {
    return this.a * v;
}

var obj6 = {
    a: 6
};

var bind = hfun.bind(obj6);
console.log(bind(4));//24

可以看到,我们再无需构建一个包裹函数来手动调用call或apply方法,只需要提供调用者和绑定到调用者this的对象即可。

我们可能发现了一个奇怪的现象,通过apply()和call()方法绑定的对象在传参给调用者时,需要设置一个参数占位,但bind()方法则不用,这是因为他们的返回值不同,bind()方法会返回一个经过硬编码的新函数,它会把传入参数设置为this的上下文并调用原始函数。可以理解bind使用方法为 bind(obj)(args)。而对于call()和apply()方法而言,一旦调用此方法,就会立刻返回调用者函数的返回值,所以此时就需要同时传入参数给方法的参数占用符,然后被函数参数读取。值得注意的是,bind方法的参数和call方法类似。

Original: https://www.cnblogs.com/mogebw/p/16768934.html
Author: 墨戈
Title: this硬绑定

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/801218/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • pandas 涉及内容的用法

    1.1 DataFrame 的构建 DataFrame 是由索引和内容组成的,索引有: 行索引和列索引; 创建方式: pd.DataFrame(ndarray数据,index=[‘…

    Python 2023年8月18日
    050
  • 一篇带你了解如何使用纯前端类Excel表格构建现金流量表

    现金流量表(Cash Flow Statement),是指反映企业在一定会计期间现金和现金等价物流入和流出的报表。现金流量表是企业财务报表的三个基本报告之一(另外两个是资产负债表和…

    Python 2023年10月18日
    037
  • 电子商务企业如何利用数据标签

    准确的搜索结果和个性化推荐无疑是现代电子商务的基石。随着全球越来越多的企业迁移到网上,每家这样的公司的目标都很简单——帮助用户快速轻松地找到他们想要的东西,以便在电子平台上实现最大…

    Python 2023年10月28日
    030
  • Rust 语言入门

    Java语言毫无疑问地稳坐霸主位置了。如今很难找到哪台机器上没有安装JDK。有了虚拟机,确实很方便,不需要过多地考虑机器环境,一次编写到处运行基本实现了。但,隔着一层”…

    Python 2023年6月6日
    076
  • ElasticSearch这些坑记得避开

    一、管理方式 二、结构维护 三、数据调度 1、同步方案 2、中断和恢复 四、刷新策略 五、深度分页 六、参考源码 Index用不好,麻烦事不会少; 一、管理方式 ElasticSe…

    Python 2023年10月16日
    030
  • python-绘图与可视化

    python 有许多可视化工具,但本书只介绍Matplotlib。Matplotlib是一种2D的绘图库,它可以支持硬拷贝和跨系统的交互,它可以在python脚本,IPython的…

    Python 2023年10月19日
    036
  • python测试开发django-169.过滤器django-filter 入门使用

    前言 在管理后台查询的时候,经常有需要查询包含某个内容,按时间段查询,或者商品价格大于多少,小于多少各种查询条件。django-filter 过滤器专门解决这种查询的问题。 环境准…

    Python 2023年8月4日
    066
  • python全系列之爬虫scrapy_Python爬虫系列教程07之初识Scrapy爬虫框架

    配套视频教程 概览 在具体的学习scrapy之前,我们先对scrapy的架构做一个简单的了解,之后所有的内容都是基于此架构实现的,在初学阶段只需要简单的了解即可,之后的学习中,你会…

    Python 2023年10月6日
    026
  • dataframe.to_sql() 一次性插入过多报错

    利用to_sql()方法 将dataframe 中的数据插入数据库;之前用的都没问题,这次突然报错, system error: 10054 远程主机强迫关闭了一个现有的连接。 刚…

    Python 2023年5月24日
    054
  • python保存图片不完整_python使用matplotlib的savefig保存时图片保存不完整的问题

    python使用matplotlib的savefig保存时图片保存不完整的问题 使用如下形式的代码进行图片保存时,保存的图片出现不完整的情况,如图1所示。 plt.colorbar…

    Python 2023年9月4日
    043
  • Python爬虫深造篇(四)——Scrapy爬虫框架启动一个真正的项目

    一、前情提要 经过前面的学习,我们初识了 Scrapy 框架,通过 Scrapy 提供的互动工具,我们在命令行中体验了 Scrapy 中的 CSS 选择器 最重要的几个点是:. 代…

    Python 2023年10月1日
    045
  • Python一键读取文件中英文单词数量

    一、 序言 今天用Python来试试,对一个文件里面的英文单词数量进行快速统计,告别传统计数方式。 目标文件 我也不知道多少个,瞎复制的~ ; 二、涉及知识点 文件读写 基础语法 …

    Python 2023年11月2日
    043
  • pygame下载(非常详细)

    pygame安装 第一次安装pygame,从网上查了很多资料,各种方式都有,我发现了一种很简单的方法,不用去官网找,直接输入命令就能下载,希望能给大家提供一些参考! 打开终端 1、…

    Python 2023年9月17日
    062
  • Python Pandas PK esProc SPL,谁才是数据预处理王者?

    做数据分析和人工智能运算前常常需要大量的数据准备工作,也就是把各种数据源以及各种规格的数据整理成统一的格式。因为情况非常复杂多样,很难有某种可视化工具来完成此项工作,常常需要编程才…

    Python 2023年8月1日
    049
  • Unity Webgl内嵌网页页面

    Unity Webgl端有时候会有这样一个需求,在Unity界面上内嵌一个网页,并且可以在界面上把这个网页关掉(不是重新打开新的标签页) 效果如下:现在来实现这个功能:1.在Ass…

    Python 2023年9月29日
    039
  • pytest单元测试框架基础知识

    一、pytest单元测试框架 单元测试是指在软件开发中,针对软件的最小单位(函数、方法)进行正确性的检查测试 Java:Junit和testing Python:UNItest和p…

    Python 2023年9月13日
    041
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球