作用: call,apply,bind 都是改变this指向的
语法:
func.call(thisagr,param1,param1,...)
func.apply(thisagr,[param1,param1,...])
func.bind(thisagr,param1,param1,...)
1.call:
1.1 call第一个参数,就是要变成的this的对象
var obj = { name: 'psg' };
function fn(num1, num2) {
console.log(num1 + num2);
console.log("this指向:" + this, "num1:" + num1, "num2:" + num2)
}
fn(100, 200);//this指向window, num1=100, num2=200
fn.call(100, 200);////this指向100, num1=200, num2=undefined
fn.call(obj, 100, 200);//this指向obj, num1=100, num2=200
1.2严格模式,非严格模式下的this指向
在非严格模式下:this为null,undefined时,this指向window 在严格模式下:传谁this就是谁,不传this就是undefined
// 严格模式
fn.call(); //this指向undefined
fn.call(null); //this指向null
fn.call(undefined); //this指向undefined
2.apply:
apply 于call 类似,只是不用于的语法
call传参数是逗号分割,一个一个传入:fn.call(obj,arg1,agr2)
apply传参数是用一个数组传:fn.apply(obj,[agr1,agr2])
var obj1 = { name: 'psg' };
function fn1(num1, num2) {
console.log(num1 + num2);
console.log("this指向:" + this, "num1:" + num1, "num2:" + num2)
}
fn1.call(obj1, 100, 200);
fn1.apply(obj1, [100, 200]);
3.bind:
bind 于call类似,语法一致,但是bind体现了js的预处理
bind 不会执行函数,会有一个返回值(返回值是函数的拷贝)
预处理:实现把fn的this改变成我们想要的结果,并且把对象的参数也准备了,要用的时候,直接执行就行了
var obj1 = { name: 'psg' };
function fn1(num1, num2) {
console.log(num1 + num2);
console.log("this指向:" + this, "num1:" + num1, "num2:" + num2)
}
fn1.call(obj1, 100, 200);
fn1.bind(obj1, 100, 200);
//bind只是改变了fn中的this为obj,并且给fn传递了两个参数值,但是此时并没有给fn这个函数执行。
// 但是,执行bind会有一个返回值,这个返回值myFn就是我们把fn的this改变后的那个结果!!!
var myFn = fn1.bind(obj1, 100, 200);
myFn(); //执行函数
3.1手动实现bind
4.小结区别:
call于apply区别:
语法不同,传给函数的参数写法不同
call于bind区别:
1.执行:
call,apply改变了this执行,立马执行函数
bind 返回了this指向后的函数,没有执行函数
5.手动模拟实现call:
主要思路如上,不一样的是要通过arguments取出除第一位之外的所有参数放到一个数组里,然后通过展开运算符给要执行的函数或方法传参
1.改变this指向,给传递过来的对象添加属性,把this指向这个属性,然后指向方法,删除属性
2.用arguments接受传递过来的参数
Function.prototype.myCall = function (con) {
con = new Object(con) || window || global;//1.没有参数时,指向window
con.fun = this; //2.给目标对象新建一个属性,绑定这个函数
let arr =[]; //3.新建一个空数组
for (let i = 1; i < arguments.length; i++) {
arr.push(arguments[i]);
}
con.fun(...arr); //4.运行一下
delete con.fun; //5.删除目标对象上的fun属性,不删除会越来越多
}
var obj = { name: 12 }
function fn(num1, num2) {
console.log("this:" + this);
console.log("num1:" + num1);
console.log("num2:" + num2);
}
fn.myCall(100, 200);
fn.myCall(obj, 100, 200);
方法二:eval 将原始函数转换为字符串,再将其中的this替换为目标对象
1.arguments代指函数接收的所有参数,它是一个类数组,不能用Array的方法
第一位是this指向,后面的才是参数
- eavl() 可以接受一个字符串str作为参数,并把这个参数作为脚本代码来执行
var name = 'cao1';
var obj = {name: 'cao2'};
Function.prototype.call1_ = function (obj) {
var arr = []
for (var i = 1, len = arguments.length; i < len; i++) {
arr.push("arguments[" + i + "]")
}
obj.fn = this;
eval("obj.fn(" + arr + ")");//2.执行方法 eval(string)会做运算 eval("var a=1");
delete obj.fn;
}
function fn2(a, b, c) {
console.log(a + b + c + this.name);
};
fn2.call1_(obj, 1, 2, 3);
fn2.call1_(obj, "我的", "名字", "是");
// 如果是args.push(arguments[i])报错,因为传递的是字符串这一步我们提前将字符串进行了解析 等于 eval("obj.fn(我的,名字,是)")
6.开发使用
6.1 改变this指向
6.2 数据类型检测
function type(obj) {
return Object.prototype.toString.call(obj)[1];
};
type([123]);//Array
type('123');//String
type(123);//Number
type(null);//Null
type(undefined);//Undefined
6.2数组取最大值,最小值
var arr = [11, 1, 0, 2, 3, 5];
var max1 = Math.max.call(null, ...arr);
var max2 = Math.max.apply(null, arr);
var min1 = Math.min.call(null, ...arr);
var min2 = Math.min.apply(null, arr);
6.3函数arguments类数组操作
var fn = function () {
var arr = Array.prototype.slice.call(arguments);
console.log(arr); //[1, 2, 3, 4]
};
fn(1, 2, 3, 4);