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(); // 3
const obj = {}
var P2 = Point.bind(obj, 1);
const p3 = new P2(2);
console.log(p3.toString()); // undefined
console.log(p3 instanceof P2); // true
console.log(p3 instanceof Point); // true
new 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;
}
复制代码
结语
本人能力有限,难免出现错误内容,欢迎大佬们看到后,指出文章的错误以及给出更优质的答案
参考链接
MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call