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 函数。

相关推荐
向明天乄25 分钟前
在 Vue 3 项目中集成高德地图(附 Key 与安全密钥申请全流程)
前端·vue.js·安全
sunshine_程序媛26 分钟前
vue3中的watch和watchEffect区别以及demo示例
前端·javascript·vue.js·vue3
电商数据girl1 小时前
【经验分享】浅谈京东商品SKU接口的技术实现原理
java·开发语言·前端·数据库·经验分享·eclipse·json
Senar1 小时前
听《富婆KTV》让我学到个新的API
前端·javascript·浏览器
烛阴2 小时前
提升Web爬虫效率的秘密武器:Puppeteer选择器全攻略
前端·javascript·爬虫
hao_wujing2 小时前
Web 连接和跟踪
服务器·前端·javascript
前端小白从0开始2 小时前
前端基础知识CSS系列 - 04(隐藏页面元素的方式和区别)
前端·css
想不到耶2 小时前
Vue3轮播图组件,当前轮播区域有当前图和左右两边图,两边图各显示一半,支持点击跳转和手动滑动切换
开发语言·前端·javascript
萌萌哒草头将军3 小时前
🚀🚀🚀尤雨溪:Vite 和 JavaScript 工具的未来
前端·vue.js·vuex
Fly-ping3 小时前
【前端】cookie和web stroage(localStorage,sessionStorage)的使用方法及区别
前端