关于JS函数的bind
昨天被人问到js的bind的作用是什么?
这个倒还能回答出来,bind 之后返回一个新的函数,这个函数可以保持传递的this上下文。
接着又问了,那么bind两次不同的上下文会怎样?
这个一下子就蒙了,因为平时也没这么用过,于是开始查一下资料。
首先在浏览器中测试一下。
function test(){
console.log(this.a)
}
var bind1 = test.bind({a:1}) //第一次 bind
var bind2 = bind1.bind({a:2}) // 第二次 bind
bind1()
bind2()
结果如下
1
1
可以看到第二次bind并没有能再改变this的值。
查一下MDN,Function.prototype.bind() , 并没有解释bind两次会怎样。 但是他提供了一个Polyfill,可以了解下bind的实现。
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
}
可以看到MDN提供的polyfill的实现是oThis
做为参数传进来,返回一个新的函数,这个时候函数是个闭包,仍然可以访问oThis
变量,然后调用call/apply来实现指定的上下文。 这种情况下,如果bind两次,相当于闭包套闭包,不管套几层,值都是第一次保存的this
值。 即上面polyfill的 oThis
变量。
光看polyfill是不够了,因为并不知道polyfill实现是不是标准。所以还是要看下规范。这里我们参考下 ES2015文档
可以直接看到 19.2.3.2 节 NOTE 2,If Target is an arrow function or a bound function then the thisArg passed to this method will not be used by subsequent calls to F.
如果调用bind的是一个箭头函数或者是已经bind过的函数(bound function),那么再次bind是不会起作用的。 可以看到规范已经定义了这样的行为产生的结果,我们可以直接记住这个结论。
但是这里值得注意的是,我们看到规范定义的bind操作 和 MDN 上提供的polyfill并不一致。polyfill没有完全实现ES2015规定的bind。
比如ES2015 规定了 bound function 的length 和 name 行为。
Let targetHasLength be HasOwnProperty(Target, "length").
ReturnIfAbrupt(targetHasLength).
If targetHasLength is true, then
Let targetLen be Get(Target, "length").
ReturnIfAbrupt(targetLen).
If Type(targetLen) is not Number, let L be 0.
Else,
Let targetLen be ToInteger(targetLen).
Let L be the larger of 0 and the result of targetLen minus the number of elements of args.
Else let L be 0.
这里会规定bound function 的 length 属性,应该和bind之前的length一致。
再看name 的行为
Let targetName be Get(Target, "name").
ReturnIfAbrupt(targetName).
If Type(targetName) is not String, let targetName be the empty string.
Perform SetFunctionName(F, targetName, "bound").
这里规定bound function 的name 应该走 SetFunctionName 方法,而这里SetFunctionName之后的返回值应该是 bound字符串 + 空格 + 原先函数的name
......忽略了一些描述
prefix即bound 字符串
If prefix was passed, then
Let name be the concatenation of prefix, code unit 0x0020 (SPACE), and name.
即
function a(){}
var b = a.bind()
console.log(b.name)
结果应该是
bound a
而 MDN 的 polyfill
是没有实现这些细节的,所以用的时候如果依赖于这些,是要注意的。
关于JS函数的bind的更多相关文章
- JS 函数(arguments、箭头函数、bind)
参数 函数内部可用的 arguments 对象来访问函数的实参 注意 在函数递归调用的时候(在某一刻同一个函数运行了多次,也就是有多套实参),那么 arguments 属性的值是最近一次该函数调用时传 ...
- js 高程 22.1.4 函数绑定 bind() 封装分析
js 高程 书中原话(斜体表示): 22.1.4 函数绑定 另一个日益流行的高级技巧叫做函数绑定.函数绑定要创建一个函数,可以在特定的this 环境中 以指定参数调用另一个函数.该技巧常常和回调函数与 ...
- 如何用 js 实现一个 bind 函数
如何用 js 实现一个 bind 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...
- javascript中利用柯里化函数实现bind方法
柯理化函数思想:一个js预先处理的思想:利用函数执行可以形成一个不销毁的作用域的原理,把需要预先处理的内容都储存在这个不销毁的作用域中,并且返回一个小函数,以后我们执行的都是小函数,在小函数中把之前预 ...
- js函数绑定同时,如何保留代码执行环境?
经常写js的程序员一定不会对下面这段代码感到陌生. var EventUtil = { addHandler : function(element, type, handler){ if(elemen ...
- 在react jsx中,为什么使用箭头函数和bind容易出现问题
在之前的文章中,已经说明如何避免在react jsx中使用箭头函数和bind(https://medium.freecodecamp.o... 但是没有提供一个清晰的demo展示为什么要这样做. 现在 ...
- js函数的属性和方法
js函数的属性和方法 前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解j ...
- 如何编写高质量的 JS 函数(4) --函数式编程[实战篇]
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/ZoXYbjuezOWgNyJKmSQmTw作者:杨昆 [编写高质量函数系列],往期精彩内容: ...
- Underscore——JS函数库
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826065.html underscore是什么——它是一个js函数库 jQuery统一了不同浏览器之间的 ...
随机推荐
- 数据传输对象(DTO)介绍及各类型实体比较
数据传输对象(DTO)介绍及各类型实体比较 本文将介绍DDD分层架构中广泛使用的数据传输对象Dto,并且与领域实体Entity,查询实体QueryObject,视图实体ViewModel等几种实体进行 ...
- SEO 优化,网站推广优化教程100条(SEO,网站关键字优化,怎么优化网站,如何优化网站关键字)
这篇文章不错. http://www.cnblogs.com/zangdalei/archive/2010/08/31/1814047.html 看了一半之后的,觉得不太靠谱,很多都不懂. 于是 找 ...
- 拾人牙慧,浅记一些C++的类
这两天没事又翻了翻Primer,发现自己上岁数了,记单词能力开始下降,索引把一些简单的例子记下来,把一些肥肉剔除,剩一下骨头,方便今后Ctrl+F. 在此感谢: http://ticktick. ...
- POJ 3390 Print Words in Lines(DP)
Print Words in Lines Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 1624 Accepted: 864 D ...
- CF - 96D - Volleyball
题意:一个无向图,有n个点,m条边,每条边有距离w,每个点有两个属性(1.从这点出发能到的最远距离,2.从这点出发的费用(不论走多远都一样)),一个人要从点x到点y,问最小费用是多少. 题目链接:ht ...
- HDU 2064 汉诺塔III
汉诺塔III Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- leetcode第22题--Merge k Sorted Lists
problem:Merge k sorted linked lists and return it as one sorted list. Analyze and describe its compl ...
- FineUI开发实践
ASP.NET-FineUI开发实践-7 摘要: 下拉显示grid列表.其实很简单,但是试了很多方法,水平有限,主要是都不好使,还是简单的好使了,分享下.先是看了看网上的,是直接写个了extjs控件类 ...
- Ruby on Rails (ROR)类书籍
Ruby on Rails (ROR)类书籍下载地址及其他(整理) Ruby on Rails 如此之热,忍不住也去看了看热闹,现在把一些相关的电子图书下载地址整理下,方便有兴趣的朋友. 2006-0 ...
- Jqury笔记
1. --------------- -var aa = new Array(); aa.push(1); alert(aa[0]); var aa=[];也表示一个数组: ------------ ...