编程技术

javascript栏目详细介绍一句代码。

一行有趣的JS代码_编程技术_亿码酷站插图

我们经常在框架级的源码中看到类似如下的一句代码,比如:

var toStr1 = Function.prototype.call.bind(Object.prototype.toString);复制代码

在这一句代码中既使用call方法,同时也使用bind方法,乍看之下,有点晕!这到底是想干嘛?

无妨,我们调用看看,传入不同的类型试试,效果如下:

console.log(toStr1({}));      // "[object Object]"console.log(toStr1([]));      // "[object Array]"console.log(toStr1(123));     // "[object Number]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1(new Date));// "[object Date]"复制代码

从结果中可以看到该方法的主要功能是用于检测对象的类型。但通常类型检测,我们可能更多地看到如下代码实现:

var toStr2 = obj => Object.prototype.toString.call(obj);console.log(toStr2({}));      // "[object Object]"console.log(toStr2([]));      // "[object Array]"console.log(toStr2(123));     // "[object Number]"console.log(toStr2("abc"));   // "[object String]"console.log(toStr2("abc"));   // "[object String]"console.log(toStr2(new Date));// "[object Date]"复制代码

熟悉bind和call的同学应该知道,两种方法本质上是相同的,而第二种方法更简洁,仅仅使用一次call就能获得我们想要的功能,且代码逻辑清晰,理解起来更加容易,可在众多框架中为何更多使用第一种呢?

其实主要的原因是防止原型污染,比如我们在业务代码中覆写了Object.prototype.toString方法,第二种写法将得不到正确的结果,而第一种写法仍然可以。我们用代码来来试试:

var toStr1 = Function.prototype.call.bind(Object.prototype.toString);var toStr2 = obj => Object.prototype.toString.call(obj);Object.prototype.toString = function(){  return'toString方法被覆盖!';
}// 接着我们再调用上述方法// toStr1调用结果如下:console.log(toStr1({}));      // "[object Object]"console.log(toStr1([]));      // "[object Array]"console.log(toStr1(123));     // "[object Number]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1(new Date));// "[object Date]"// toStr2调用结果如下:console.log(toStr2({}));      // "toString方法被覆盖!"console.log(toStr2([]));      // "toString方法被覆盖!"console.log(toStr2(123));     // "toString方法被覆盖!"console.log(toStr2("abc"));   // "toString方法被覆盖!"console.log(toStr2("abc"));   // "toString方法被覆盖!"console.log(toStr2(new Date));// "toString方法被覆盖!"复制代码

image-20201028233049911

image-20201028233518306

结果很明显。第一种方法仍然能正确得到结果,而第二种则不行!那么为什么会这样呢?我们知道bind函数返回结果是一个函数,这个函数是函数内部的函数,会被延迟执行,那么很自然联想到这里可能存在闭包!因为闭包可以保持内部函数执行时的上下文状态。不过在现代版浏览器中call和bind都已经被js引擎内部实现了,我们没有办法调试!但是我们可以通过polly-fill提供的近似实现的源码来理解引擎内部的逻辑,下面是本文调试的demo,大家可以尝试下:

// 模拟实现call// ES6实现Function.prototype.mycall = function (context) {
  context = context ? Object(context) : window;  var fn = Symbol();
  context[fn] = this;  let args = [...arguments].slice(1);  let result = context[fn](...args);  delete context[fn]  return result;
}// 模拟实现bindFunction.prototype.mybind = function (context) {  if (typeof this !== "function") {    throw new Error("请使用函数对象调用我,谢谢!");
  }  var self = this;  var args = Array.prototype.slice.call(arguments, 1);  var fNOP = function () { };  var fBound = function () {    var bindArgs = Array.prototype.slice.call(arguments);    return self.myapply(this instanceof fNOP ? this : context, args.concat(bindArgs));
  }

  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();  return fBound;
}// 模拟实现apply// ES6实现Function.prototype.myapply = function (context, arr) {
    context = context ? Object(context) : window;    var fn = Symbol();
    context[fn] = this;    let result;    if (!arr) {
        result = context[fn]();
    } else {
        result = context[fn](...arr);
    }    delete context[fn]    return result;
}var toStr1 = Function.prototype.mycall.mybind(Object.prototype.toString);console.log(toStr1({}));      // "[object Object]"console.log(toStr1([]));      // "[object Array]"console.log(toStr1(123));     // "[object Number]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1(new Date));// "[object Date]"复制代码

image-20201028234453730

上述的实现略去一些健壮性的代码,仅保留核心逻辑,具体的实现细节这里不做解释,有兴趣的可以自己研究,从devtools我们看到mybind形成的闭包确实在函数对象toStr1的作用域上!

当然如果你对原型链有深刻理解的话,其实这句有趣的代码还可以写成如下方式:

var toStr3 = Function.call.bind(Object.prototype.toString);var toStr4 = Function.call.call.bind(Object.prototype.toString);var toStr5 = Function.call.call.call.bind(Object.prototype.toString);// 甚至可以这么写。。。var toStr6 = (()=>{}).call.bind(Object.prototype.toString);复制代码

-END-

一行有趣的JS代码
—–文章转载自PHP中文网如有侵权请联系admin#tyuanma.cn删除

yum方式如何安装php5.5

下载声明:
  • 本站资源如无特殊说明默认解压密码为www.ymkuzhan.com建议使用WinRAR解压;
  • 本站资源来源于用户分享、互换、购买以及网络收集等渠道,本站不提供任何技术服务及有偿服务,资源仅提供给大家学习研究请勿作它用。
  • 赞助本站仅为维持服务器日常运行并非购买程序及源码费用因此不提供任何技术支持,如果你喜欢该程序,请购买正版!
  • 版权声明:
  • 下载本站资源学习研究的默认同意本站【版权声明】若本站提供的资源侵犯到你的权益,请提交版权证明文件至邮箱ymkuzhan#126.com(将#替换为@)站长将会在三个工作日内为您删除。
  • 免责声明:
  • 您好,本站所有资源(包括但不限于:源码、素材、工具、字体、图像、模板等)均为用户分享、互换、购买以及网络收集而来,并未取得原始权利人授权,因此禁止一切商用行为,仅可用于个人研究学习使用。请务必于下载后24小时内彻底删除,一切因下载人使用所引起的法律相关责任,包括但不限于:侵权,索赔,法律责任,刑事责任等相关责任,全部由下载人/使用人,全部承担。以上说明,一经发布视为您已全部阅读,理解、同意以上内容,如对以上内容持有异议,请勿下载,谢谢配合!支持正版,人人有责,如不慎对您的合法权益构成侵犯,请联系我们对相应内容进行删除,谢谢!