Javascript中bind函数和new对于this的影响分析

1. 问题描述

js 复制代码
function fn(name) {
  this.name = name;
}
const obj = {}
const fn1 = fn.bind(obj);
const instance = new fn1("abc");
console.log(instance.name);
console.log(obj.name);

上面这段代码的输出结果是:

js 复制代码
abc
undefined

在这段代码中我们首先声明了一个函数 fn, 函数内部将参数 name 赋值给 thisname 属性;随后将变量 fn 通过 bind 函数绑定了一个空对象 obj;之后通过 new fn1("abc") 创建了实例 instance; 通过打印,可以发现 instancename 属性是实例化时传入的参数 "abc",而 objname 属性不存在。

根据这个现象我们可以推断,在 fn 中获取到的 thisinstance,而不是通过 bind 函数绑定的 obj。因此我们可以得到结论,new 绑定对于 this 指向的优先级要高于 bind 函数

2. 原因解释

想要知道其中的原因,必然要知道 bind 的实现原理。参考 core-jsbind 函数的 polyfillgithub.com/zloirock/co... ),我们可以对 bind 函数实现原理有一个大致认识,以下是部分简化后的代码:

js 复制代码
function bind(that /* , ...args */) {
  var F = aCallable(this);
  var Prototype = F.prototype;
  var partArgs = arraySlice(arguments, 1);
  var boundFunction = function bound(/* args... */) {
    var args = concat(partArgs, arraySlice(arguments));
    return this instanceof boundFunction ? construct(F, args.length, args) : F.apply(that, args);
  };
  if (isObject(Prototype)) boundFunction.prototype = Prototype;
  return boundFunction;
};

代码中 aCallable 就是判断传入参数是否可调用,如果是则返回参数本身。construct 函数是将传入的 F 实例化。其它如 arraySliceconcatisObject 函数的作用结合函数名都比较好理解。

这里就可以很清晰的看到,bind 函数最终返回了 boundFunction,而在这个函数内部对 this 进行了判断,这里的 this 的值根据我们调用方式的不同就会有差别:

  • 通过 fn.bind(obj)(xxx) 直接调用

此时 bind 函数获取到的 that 参数为 obj,而 bind 函数中的 this 对象则是 fnfn.bind(obj) 返回了 boundFunction 函数,相当于调用 boundFunction(xxx),这时 boundFunction 函数没有显示的调用对象,因此 this 指向全局对象。

  • 通过 new fn.bind(obj)(xxx) 形式调用

fn.bind(obj) 函数返回的是函数 boundFunction,这里通过 new 调用,所以相当于 new boundFunction(xxx),那么显然在 boundFunction 中获取到的 this 就是 boundFunction 实例化后的对象。

我们在前面的代码中执行了 new fn.bind(obj)("abc"),也就相当于执行 new boundFunction(obj)("abc")

我们继续看 boundFunctionreturn 的内容。这一部分代码首先对 this instanceof boundFunction 进行了判断,又可以分两种情况讨论:

  • 如果我们是直接调用的话 this 指向全局对象,那么显然判断条件不成立,因此会走入 F.apply(that, args),这里的 that 根据前文分析是传入 bind 的参数 obj 对象,这种形式就是我们将函数 Fthis 显式绑定了对象 obj

  • 如果我们通过 new 进行调用,this 指向 boundFunction 的实例对象,那么判断条件成立,执行 construct(F, args.length, args),相当于 new F(...args),这里的 F 就是 bind 函数获取到的 this,也就是 fn 函数。因此最终我们执行的实际上是 new fn(xxx),很明显此时我们在 fn 函数中获取到的 this 就是 fn 实例化后的对象,而非我们在 bind 中传递的参数 obj

3. 小结

我们在同时用 newbind 函数去改变 this 指向时,newthis 的影响优先级要高于 bind 函数。这是由于在 bind 函数中我们返回了一个新函数 boundFunction,并且在这个函数中对 this instanceof boundFunction 进行了判断。调用方式的不同会导致判断结果的不同,最终导致了 newthis 指向的影响优先级高于 bind 函数。

相关推荐
人工智能训练1 天前
【极速部署】Ubuntu24.04+CUDA13.0 玩转 VLLM 0.15.0:预编译 Wheel 包 GPU 版安装全攻略
运维·前端·人工智能·python·ai编程·cuda·vllm
会跑的葫芦怪1 天前
若依Vue 项目多子路径配置
前端·javascript·vue.js
xiaoqi9221 天前
React Native鸿蒙跨平台如何进行狗狗领养中心,实现基于唯一标识的事件透传方式是移动端列表开发的通用规范
javascript·react native·react.js·ecmascript·harmonyos
jin1233221 天前
React Native鸿蒙跨平台剧本杀组队消息与快捷入口组件,包含消息列表展示、快捷入口管理、快捷操作触发和消息详情预览四大核心功能
javascript·react native·react.js·ecmascript·harmonyos
烬头88211 天前
React Native鸿蒙跨平台实现二维码联系人APP(QRCodeContactApp)
javascript·react native·react.js·ecmascript·harmonyos
pas1361 天前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js
摇滚侠1 天前
2 小时快速入门 ES6 基础视频教程
前端·ecmascript·es6
2601_949833391 天前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter
珑墨1 天前
【Turbo】使用介绍
前端
军军君011 天前
Three.js基础功能学习十三:太阳系实例上
前端·javascript·vue.js·学习·3d·前端框架·three