一、call、bind、apply的作用
改变函数执行时的上下文,即改变this指向
永远记住一句话:this永远指向最后调用它的对象
来!念三遍!this永远指向最后调用它的对象!this永远指向最后调用它的对象!this永远指向最后调用它的对象!
二、call、bind、apply三者区别
①call()方法接受参数表列,传递参数arg1,arg2,arg3;apply必须是数组
②call、apply会调用函数并且改变内部this指向;bind不会调用函数也可以改变内部this指向,需要手动调用。
三、call、bind、apply的应用场景
①call传递引用类型、传递值经常用于父类继承
②apply经常跟数组有关系,可以借助于数学对象实现数组的最大值和最小值。
③bind不调用函数,需要手动调用,可以改变this指向比如定时器内部this指向。
四、call()方法
//语法
fun.call(thisArg,arg1,arg2,arg3,...)
call主要用于继承
function Father(firstName, character) {
this.firstName = firstName;
this.character = character;
}
function Son(firstName, character) {
Father.call(this, firstName, character)
}
var son = new Son('wang', 'good');
console.log(son)
五、apply()方法
//语法
//第一个参数在fun函数运行时指定的this值 第二个参数只能传递数组 返回值是函数的返回值,因为它调用函数
fun.apply(thisArg, [argsArray])
求数组的最大值
const arr = [1, 22, 34, 23, 56, 66]
const max = Math.max.apply(Math, arr)
console.log(max)
六、bind()方法
bind()不会调用函数,但可以改变this内部指向
//语法
//fun.bind(thisArg, arg1, arg2, ...)
//返回由指定的this值和初始化参数改造的原函数拷贝
var myName = {
name: 'gaby'
}
function fn() {
console.log(this)
}
var f = fn.bind(myName);
f()
七、手写bind
(1)隐式原型Function.prototype.bind
Function.prototype.bind = function () {
//Todo Something
}
(2)bind的第一个形参是要绑定给函数的上下文
Function.prototype.bind = function (context) {
var fn = this;
return function () {
return fn.apply(context)
}
}
bind函数可以传递多个参数,第一个参数要绑定给调用它的函数上下文,其他的参数将会作为预设参数传递给这个函数
let foo = function () {
console.log(arguments);
}
foo.bind(null, "a", "b")("c", "d", "e");
(3)bind返回值绑定改进
Function.prototype.bind = function (context, ...args) {
var fn = this;
return function (...rest) {
return fn.apply(context, [...args, ...rest])
}
}
(4)ES5写法
Function.prototype.bind = function () {
var args = Array.prototype.slice.call(arguments)
var context = args.slice(0, 1)[0];
var fn = this;
return function () {
let rest = Array.prototype.slice.call(arguments);
return fn.apply(context, arg.concat(rest));
}
}
(5)保留函数原型
Function.prototype.bind = function () {
var args = Array.prototype.slice.call(arguments)
var context = args.slice(0, 1)[0];
var fn = this;
var res = function () {
let rest = Array.prototype.slice.call(arguments);
return fn.apply(context, args.concat(rest));
}
if (this.prototype) {
res.prototype = this.prototype;
}
return res;
}