对比
1. call/apply
- 第一个参数就是改变的THIS指向,写谁就是谁(特殊:非严格模式下,传递
null/undefined
指向的也是window)
- 唯一区别:执行函数,传递的参数方式有区别,
call
是一个个的传递,apply
是把需要传递的参数放到数组中整体传递
func.call([context],10,20)
func.apply([context],[10,20])
2. bind
call/apply
都是改变this的同时直接把函数执行了,而bind不是立即执行函数,属于预先改变this和传递一些内容 =>"柯理化"
- 并且,绑定的时候可以额外传参数,执行的时候也可以额外传参数。
call
- 第一个参数为null或者undefined时,this指向全局对象window,值为原始值的指向该原始值的自动包装对象,如 String、Number、Boolean
- 为了避免函数名与上下文(context)的属性发生冲突,使用Symbol类型作为唯一值
- 将函数作为传入的上下文(context)属性执行
- 函数执行完成后删除该属性
- 返回执行结果
function add(c, d) {
return this.a + this.b + c + d;
}
const obj = { a: 1, b: 2 };
function es6call(context, ...args) {
context = context || window
context === null ? context = window : null;
let type = typeof context;
if (type !== "object" && type !== "function" && type !== "symbol") {
switch (type) {
case 'number':
context = new Number(context);
break;
case 'string':
context = new String(context);
break;
case 'boolean':
context = new Boolean(context);
break;
}
}
let $fn = Symbol()
context.$fn = this;
args = args ? args : []
let result = args.length > 0 ? context.$fn(...args) : context.$fn();
delete context.$fn;
return result; 、、5.
}
console.log(add.es6call(obj, 3, 4));
Function.prototype.myCall = function((context, ...args){}
apply
- 前部分与call一样
- 第二个参数可以不传,但类型必须为数组或者类数组
function apply(context = window, args) {
context.$fn = this;
let result = context.$fn(...args);
delete context.$fn;
return result;
}
bind
- 需要考虑:
- bind() 除了 this 外,还可传入多个参数;
- bind 创建的新函数可能传入多个参数;
- 新函数可能被当做构造函数调用;
- 函数可能有返回值;
- 实现方法:
- bind 方法不会立即执行,需要返回一个待执行的函数;(闭包)
- 实现作用域绑定(apply)
- 参数传递(apply 的数组传参)
- 当作为构造函数的时候,进行原型继承
~ function anonymous(proto) {
function bind(context){
if (context == undefined) {
context = window;
}
var args = [].slice.call(arguments,1)
var _this = this
function anonymous(){
var innerArg = [].slice.call(arguments,0)
args = args.concat(innerArg)
var new_this = this instanceof _this ? this : context
_this.apply(new_this, args)
}
var fnNoop = function(){}
if(this.prototype){
fnNoop.prototype = this.prototype
}
anonymous.prototype = new fnNoop()
return anonymous
}
proto.bind = bind
}(Function.prototype)