bind函数:
const $ = document.querySelector;
const div = $('div');
//Uncaught TypeError: Illegal invocation
// at <anonymous>:1:1
// querySelector 这个方法是document对象下的方法,window对象下并没有这个方法
//解决办法:
const $ = document.querySelector.bind(document);
const div = $('div');
// 返回结果 <div>......</div>
- bind函数可以多次bind调用,其中的this总是指向第一个绑定的对象
const sayName = function () {
console.log(this.name);
}
const p1 = {
name:'vidy'
}
const p2= {
name: 'lily'
}
const say = sayName.bind(p1).bind(p2);
say(); // vidy
- ES6的箭头函数里的this是指向外层函数的this的,不可改变,所以bind对箭头函数是无效的
- polyfill实现
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() {
// this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fNOP
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
}
- 偏函数
bind() 的另一个最简单的用法是使一个函数拥有预设的初始参数。这些参数(如果有的话)作为bind()的第二个参数跟在this(或其他对象)后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。
简单的理解就是:偏函数会返回一个新函数,这个函数有预设的参数
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
柯里化:
又称为部分求值,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回一个新的函数的技术,新函数接受余下参数并返回运算结果。
柯里化可以用来解决我们平时开发过程中具有共同主题的,或者说处理某一类,具有共同特性的,能起到代码复用。
比如:表单验证,我们可能需要验证手机,邮箱等等;
一般做法是:
function checkPhone(phoneNumber) {
return /^1[34578]\d{9}$/.test(phoneNumber);
}
function checkEmail(email) {
return /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/.test(email);
}
封装一个通用函数:
// 将正则,要验证的字符串作为参数传入
function check(targetString, reg) {
return reg.test(targetString);
}
check(/^1[34578]\d{9}$/, '14900000088');
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@163.com');
柯里化封装:
var _check = createCurry(check);
var checkPhone = _check(/^1[34578]\d{9}$/);
var checkEmail = _check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);
//使用的时候就更简洁
checkPhone('1806467897');
checkEmail('xxx@qq.com');
- 柯里化通用式:
function curry(fn, ...rest) {
return function(...arg) {
var args = [...rest, ...arg]
if (args.length >= fn.length) {
return fn.apply(null, args)
} else {
return curry.call(null, fn, ...args)
}
}
}
偏函数与柯里化区别:
柯里化是将一个多参数函数转换成多个单参数函数,也就是将一个 n 元函数转换成 n 个一元函数。
偏函数则是固定一个函数的一个或者多个参数,也就是将一个 n 元函数转换成一个 n - x 元函数。
js偏函数与柯里化函数:https://blog.csdn.net/neweastsun/article/details/75947785
Javascript bind的应用场景及实现思路:https://bonevidy.github.io/posts/2018/09/13/javascript-bind/
MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind