call
先来一个例子
const obj = { name: 'xiaoming', log: function(a) { console.log(this.name, a); }}obj.log(); // xiaoming undefined复制代码
call方法调用一个函数, 其具有一个指定的this
值和分别地提供的参数
const callObj = { name: 'call',}obj.log.call(callObj, 'callObj'); // call callObj复制代码
在非严格模式下,如果则指定为
null
和undefined
的this
值会自动指向全局对象(浏览器中就是window
对象),同时值为原始值(数字,字符串,布尔值)的this
会指向该原始值的自动包装对象
window.name = 'window';obj.log.call(null, 'windowObj'); // window windowObj// call方法的实现Function.prototype.call = function(context) { if (typeof this !== 'function') { throw new TypeError('error'); } context = context || window; context.fn = this; const result = context.fn(...[...arguments].slice(1)); delete context.fn; return result;}复制代码
apply
apply
方法的作用和call
方法类似,区别就是call
方法接受的是参数列表,而apply
方法接受的是一个参数数组。
const applyObj = { name: 'apply',}obj.log.apply(applyObj, ['applyObj']); // apply applyObj/*在非严格模式下,如果则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象)同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象*/window.name = 'window';obj.log.apply(null, ['applyObj']); // window windowObj// apply的实现Function.prototype.apply = function(context) { if (typeof this !== 'function') { throw new TypeError('error'); } context = context || window; context.fn = this; const result = arguments[1] ? context.fn(...arguments[1]) : context.fn(); delete context.fn; return result;};复制代码
bind
const bindObj = { name: 'bind'}obj.log.bind(bindObj);/* 这里并不会打印bind,而是返回一个函数ƒ () { console.log(this.name);}由此可见,bind()方法创建一个新的函数 */// 接着执行obj.log.bind(bindObj)(); // 打印 bind// 因此,当这个新函数被调用时其this置为提供的值复制代码
bind
的另一个最简单的用法是使一个函数拥有预设的初始参数。这些参数(如果有的话)作为bind
的第二个参数跟在this
(或其他对象)后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。
function list() { return Array.prototype.slice.call(arguments);}console.log(list(1,2,3)); // [1, 2, 3]const presetList = list.bind(null, 0);console.log(presetList()); // [0]console.log(presetList(1, 2, 3)); // [0, 1, 2, 3, 4]复制代码
绑定函数适用于用new操作符去构造一个由目标函数创建的新的实例。当一个绑定函数是用来构建一个值的,原来提供的 this 就会被忽略。然而, 原先提供的那些参数仍然会被前置到构造函数调用的前面。
function Point(a, b) { this.a = a; this.b = b;}Point.prototype.toString = function() { console.log(this.a + this.b);}const p1 = new Point(1,2);p1.toString(); // 3const obj = {}var P2 = Point.bind(obj, 1);const p3 = new P2(2);console.log(p3.toString()); // undefinedconsole.log(p3 instanceof P2); // trueconsole.log(p3 instanceof Point); // truenew Point(1, 2) instanceof P2; // true复制代码
bind的实现
Function.prototype.bind = function(context) { if (typeof this !== 'function') { throw new Error('Function.prototype.bind - what is trying to be bound is not callable'); } const slice = Array.prototype.slice; const args = slice.call(arguments, 1); const self = this; const F = function(){}; const fbound = function() { return self.apply(this instanceof F ? this: context, args.concat(slice.call(arguments))); } if (this.prototype) { F.prototype = this.prototype; } fbound.prototype = new F(); return fbound;}复制代码
结语
本人能力有限,难免出现错误内容,欢迎大佬们看到后,指出文章的错误以及给出更优质的答案