Function原型上有四个方法,其中一个是toString方法,其他三个分别是call、apply和bind
我们知道toString方法是对象的方法,但是每个类型的数据,都重写了该方法。函数类型也重写了该方法。Function.prototype.toString() 可以得到函数的字符串形式。
1、先从call聊起:Function.prototype.call 改变this指向
func.call(thisArg, arg1, arg2, ...)
call方法让this指向thisArg,func的arguments对应接收arg1、arg2...
thisArg
如果这个函数处于非严格模式下,不指定或指定为
null
或undefined
时会自动替换为指向全局对象。原始值会被包装。如果是严格模式,指定什么this就为什么,且原始值不被包装。如果没有指定,this为undefined。
实际使用:与数组方法的结合使用,比如slice方法;调用或是借用别的对象的方法;对象想执行一个功能,但又不想在自身添加这个方法,可以通过匿名函数修改this指向来实现;构造函数继承别的函数。
(1)单纯的改变this指向,借用别的对象的方法
var obj1 = {
age: 24,
sayAge: function(){
console.log(this.age);
}
}
var obj2 = {
age: 18
}
obj1.sayAge.call(obj2);
(2)构造函数继承别的函数
function Foo(name, age){
this.name = name;
this.age = age;
}
function Bar(name,age, job){
Foo.call(this,name,age);
this.job = job;
}
console.log(new Bar("zhu",24,"programmer"))
(3)匿名函数调用call。某个匿名函数实现了一个功能,可以指向某个对象或数组来调用它。而不会把这个方法添加到对象或数组上
(function(){
console.log(this.name, this.age);
}).call({name:"zhu",age: 24})
2、聊聊apply:Function.prototype.apply
call()方法的作用和 apply() 方法类似,区别就是
call()
方法接受的是参数列表,而apply()
方法接受的是一个参数数组。其次由于apply 内部通过call实现,是对call的二次封装,性能不如call。
func.apply(thisArg, [argsArray])
thisArg的特性与call一样。
func的arguments是argsArray的每一项
兼容性:与 call一样,兼容IE5.5。ES5开始,第二个参数可以是类数组,兼容IE9
var obj1 = {
age: 24,
sayAge: function(){
console.log(this.age);
console.log(arguments);
}
}
var obj2 = {
age: 18
}
obj1.sayAge.apply(obj2, {0:"a",1:"b",2:"c",length:3});
实例:合并数组并修改原数组
我们知道push方法会修改原数组,但接收的是多个单一元素,如果接收一个数组,会把该数组作为一个元素push到原数组中;
var array = ['a', 'b'];
array.push("c","d","e");
console.info(array);//["a", "b", "c", "d", "e"]
而concat方法,虽然可以接收数组或多个单一元素,进行合并,但不会修改元素组;
var array = ['a', 'b'];
var array1 = array.concat(["c","d"],"e");
console.info(array);//["a", "b"]
console.info(array1);//["a", "b", "c", "d", "e"]
push.apply,既可以修改原数组,也可以合并数组
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
实例:找出数组中最大数或最小数
Math.max() 和 Math.min() 接收多个单一元素,返回最大或最小的值
var arr = [1,3,2,4,8,6];
console.log(Math.max(...arr)); //8
console.log(Math.min(...arr)); //1
console.log(Math.max.apply(arr,arr)) //8
主要使用在接收一串参数的方法上,运行该方法接收一个数组;比如:push、Math.max和Math.min
通过Array.apply来转arguments类数组为数组
apply的展开功能
Array.apply(null, arguments)
3、聊聊bind Function.prototype.bind
bind()
方法创建一个新的函数,在bind()
被调用时,这个新函数的this
被指定为bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。func.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
调用绑定函数时作为
this
参数传递给目标函数的值。如果使用
new
运算符构造绑定函数,则忽略该值。——》new时忽略thisArg,因为new会重新创建隐式的this。
arg1, arg2, ...
当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
当绑定函数执行时,其arguments是预置入的参数+函数执行时的参数。
(1)new忽略thisArg
function Foo(name, age){
this.name = name;
this.age = age;
}
var obj = {
name: "zhu",
age: 24
}
var Bar = Foo.bind(obj);
console.log(new Bar("z",18)); //Foo {name: "z", age: 18}
4、通过call、apply实现bind函数
(1)不兼容new
if (!Function.prototype.bind) (function(){
var slice = Array.prototype.slice;
Function.prototype.bind = function() {
var thatFunc = this, thatArg = arguments[0];
var args = slice.call(arguments, 1);
if (typeof thatFunc !== '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');
}
return function(){
var funcArgs = args.concat(slice.call(arguments))
return thatFunc.apply(thatArg, funcArgs);
};
};
})();
(2)兼容new
if (!Function.prototype.mybind) (function(){
var ArrayPrototypeSlice = Array.prototype.slice;
Function.prototype.mybind = function(otherThis) {
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 baseArgs= ArrayPrototypeSlice.call(arguments, 1),
baseArgsLength = baseArgs.length,
fToBind = this,
fNOP = function() {},
fBound = function() {
//改变函数this后的函数
//如果是fBound函数执行,this是函数执行时的上下文,比如window
//如果是new fBound(),this是构造函数的实例对象
baseArgs.length = baseArgsLength; // reset to default base arguments
baseArgs.push.apply(baseArgs, arguments);
return fToBind.apply( //执行fBound时执行原函数
fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs //如果是实例对象,this
);
};
if (this.prototype) {//此处的this是mybind的this,是个函数
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound; //执行bind返回的函数
};
})();
call在构造函数中的使用:https://blog.csdn.net/zyz00000000/article/details/106904163