一、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"

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

function bfun() {
return this;
} console.log(bfun.apply(3));//[Number: 2]

没错,原始值被转换成了它的对象形式,也就是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方法类似。

this硬绑定的更多相关文章

  1. 深入理解this机制系列第一篇——this的4种绑定规则

    × 目录 [1]默认绑定 [2]隐式绑定 [3]隐式丢失[4]显式绑定[5]new绑定[6]严格模式 前面的话 如果要问javascript中哪两个知识点容易混淆,作用域查询和this机制绝对名列前茅 ...

  2. js中this的绑定

    人们对于this的绑定常常有两个误解,一:指向函数本身,二:指向函数作用域.这两种想法都是错的,this并不指向函数本身,也不指向函数作用域. function foo(){ this.count++ ...

  3. 理解javascript this 的绑定过程

    在理解this 的绑定过程之前,首先要理解调用位置:调用位置就是函数在代码中被调用的位置(而不是声明的位置).只有仔细分析调用位置才能回答这个问题:这个this 到底引用的是什么?通常来说,寻找调用位 ...

  4. JS绑定种类汇总

    这里是<你不知道的JS>中常见的this绑定种类分享: 1)默认绑定: function foo(){ console.log(this.a); } var a = 2; foo(); 解 ...

  5. 【javascript】函数中的this的四种绑定形式

    目录 this的默认绑定 this的隐式绑定 隐式绑定下,作为对象属性的函数,对于对象来说是独立的 在一串对象属性链中,this绑定的是最内层的对象 this的显式绑定:(call和bind方法) n ...

  6. this的四种绑定形式

    一 , this的默认绑定 当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象. 一个例子 function fire ...

  7. 2.2 .this的绑定规则

    2.this的绑定规则 1.默认绑定 function foo( ) { console.log(this.a); } var a=1; foo(); 在代码中,foo()函数不带任何修饰的引用进行调 ...

  8. 【javascript】函数中的this的四种绑定形式 — 大家准备好瓜子,我要讲故事啦~~

       javascript中的this和函数息息相关,所以今天,我就给大家详细地讲述一番:javascript函数中的this   一谈到this,很多让人晕晕乎乎的抽象概念就跑出来了,这里我就只说最 ...

  9. js中this的绑定规则及优先级

    一.   this绑定规则 函数调用位置决定了this的绑定对象,必须找到正确的调用位置判断需要应用下面四条规则中的哪一条. 1.1 默认绑定 看下面代码: function foo() { cons ...

随机推荐

  1. TFrecord写入与读取

    Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializi ...

  2. 「游戏引擎 浅入浅出」4.1 Unity Shader和OpenGL Shader

    「游戏引擎 浅入浅出」从零编写游戏引擎教程,是一本开源电子书,PDF/随书代码/资源下载: https://github.com/ThisisGame/cpp-game-engine-book 4.1 ...

  3. Eplan创建符号详细解说

    如何创建新的符号库以及在项目里面导入这个新的符号库 这个就不详细的赘述了 网上很多教程 和我一样的萌新可以参考 https://wenku.baidu.com/view/18c16641e45c3b3 ...

  4. CF717 Festival Organization

    \(CF717\ Festival\ Organization\) Description 一个合法的串定义为:长度在 \([l,r]\) 之间,且只含 \(0,1\),并且不存在连续 \(2\) 个 ...

  5. Java面试题(五)--Rabbits

    1.什么是MyBatis? 1.Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动.创建连接.创建statement等 ...

  6. Java注解最全详解(超级详细)

    Java注解是一个很重要的知识点,掌握好Java注解有利于学习Java开发框架底层实现.@mikechen Java注解定义 Java注解又称Java标注,是在 JDK5 时引入的新特性,注解(也被称 ...

  7. 如何快速上手AIRIOT?

    AIRIOT物联网低代码平台,快速构建稳定可靠的物联网系统,丰富的功能库及组件库,具备低成本.高效率.易操作,可扩展等特点,节省物联网项目实施时间及人力成本,支持二次开发.   [六步快速上手,玩儿转 ...

  8. 浅拷贝工具类,快速将实体类属性值复制给VO

    /** * 浅拷贝的工具类 */ public class PropertiesUtil { /** * 两个类,属性名一样的元素,复制成员. */ public static void copy(O ...

  9. 【java】非常多!学习路径24-总结目前所有知识(上)

    感谢sikiedu.com的siki老师.几年前就开始看siki的课程,最近突然想写这个笔记系列,顺便回顾一下这些基础的知识,同时也希望能帮助到一些人,有问题一起交流哈. 全文共十章,大约1.5万字, ...

  10. 踩坑之旅:配置 ROS 环境

    以下内容为本人的著作,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16660252.html 最近在学习机器人相关的导航算法, ...