J47 call、apply、bind的应用

158 阅读3分钟

1. call 方法的使用:函数方法名.call(this指向谁,实参)

let func = function (x, y) {
	this.sum = x + y;
};
window.name = "HELLO~";
let obj = {
	name: '张三'
}; 
func.call(obj, 10, 20);
console.log(obj);//{name: "张三", sum: 30}

2. apply 方法的使用:函数方法名.apply(this指向谁就是谁,数组)

let func = function (x, y) {
    this.sum = x + y;
};
window.name = "HELLO~";
let obj = {
name: '张三'
};
func.apply(obj,[10,20]);
console.log(obj);//{name: "张三", sum: 30}

3. bind方法的使用:f2相当于创建了一个func这个函数,但是this指向了obj,但是f2没有立即执行,需要手动执行

let func = function (x, y) {
	this.sum = x + y;
};
window.name = "HELLO~";
let obj = {
	name: '张三'
};	
var f2=func.bind(obj,10,20);	
f2();
console.log(obj);//=>{name: "张三", sum: 30}

4.call 和apply的区别?

  • 1.CALL方法:让函数执行,改变函数中THIS指向的
  • 2.APPLY方法:和CALL方法的作用一样,唯一的区别就是传递给函数的参数方式不一样
  • 3.CALL方法是把实参信息一个个的传递进来 fn.call(context,params1,params2...)
  • 4.APPLY传参方式是传递一个数组进来,但是也相当于再给函数一项项的传参,语法上需要写成数组而已 fn.apply(context,[params1,params2...])
  • 5.CALL的性能要比APPLY好一些,尤其是需要传递给函数的实参超过三个的时候,所以真实项目中使用CALL偏多;但是某些需求基于APPLY可以实现更好的效果;

5.需求实现数组中的最大值和最小值

1.用数学函数和剩余运算符

let arr = [10, 20, 14, 8, 25, 13, 16, 10],
	max = 0,
	min = 0;
	max = Math.max(...arr);
	min = Math.min(...arr);
	console.log(max, min);//25 8

2.排序

let arr = [10, 20, 14, 8, 25, 13, 16, 10];
arr.sort((a, b) => a - b);
max = arr[arr.length - 1];
min = arr[0];
console.log(max, min);//=>25 8

3.:apply:利用APPLY写成一个数组。利用APPLY虽然在语法上是写成一个数组,但是和CALL一样,也是把数组中的每一项传递给函数(Math.max这些方法执行的时候和THIS没关系,所以THIS改成啥都行)

let arr = [10, 20, 14, 8, 25, 13, 16, 10];
max = Math.max.apply(null, arr);
min = Math.min.apply(null, arr);
console.log(max,min);//=>25 8

4.假设法,假设数组中的第一项就是最大值或者最小值,然后拿这个值分别后后面的每一项进行比较,一旦发现比他大的,说明假设失败,让当前最大值替换原有假设的值即可

let arr = [10, 20, 14, 8, 25, 13, 16, 10];
max = min = arr[0];
for (let i = 1; i < arr.length; i++) {
	let item = arr[i];
	item > max ? max = item : null;
	item < min ? min = item : null; 
}
console.log(max,min);//=>25 8

6.把类数组变为数组

题目:
// 1.函数实参集合ARGUMRNTS(类数组集合)
// 2.不是数组是一个对象  arguments.__proto__:Object.prototype
// 3.arguments.length传递实参个数
// 4.arguments[0]获取第一个传递的实参信息
 {
    0:10,
    1:20,
    2:30,
    length:3,
    __proto__:Object.prototype
 }

1.基于内置方法Array.from

 function func() {	
	console.log(Array.from(arguments));	
}
func(10, 20, 30);//=>[10, 20, 30]

2.方法2:直接...展开即可(把ARGUMRNTS中每一项都放置到一个新数组中)

function func() {	
let arr = [...arguments];
console.log(arr);
}
func(10, 20, 30);//=>[10, 20, 30]

3.基于Array执行直接创建数组(把ARGUMRNTS中的每一项分别传递会ARRAY)

function func() {
console.log(Array.apply(null, arguments));
}
func(10, 20, 30);//=>[10, 20, 30]

4.自己写一个循环

function func() {
let arr = [];
for (let i = 0; i < arguments.length; i++) {
	arr.push(arguments[i]);
}
console.log(arr);
}
func(10, 20, 30);//=>[10, 20, 30]

5.借用数组原型上的SLICE方法,让SLICE方法执行的时候,方法中的THIS变为要操作的类数组ARGUMENTS,这样就等价于ARGUMENTS利用数组中指定方法的代码完成一些自己要操作的需求(ARGUMENTS和数组解构很相似,所以能操作数组的代码,一般也能操作ARGUMENTS这种类数组的)

  • 1.找到原型上的SLICE:
  • 2.Array.prototype.slice
  • 3.[].slice => [].proto.slice
//1.this操作
 Array.prototype.slice = function slice() {
// this:操作数组实例(要克隆的数组)
// 模拟的内置SLICE代码
let arr = [];
for (let i = 0; i < this.length; i++) {
	arr.push(this[i]);
}
// 如果我们能够把Array.prototype.slice方法执行,并且让方法中的THIS
//变为要操作的类数组(例如:ARGUMENTS),就相当于在遍历类数组中的每一项,
//把每一项内容存放到新的数组中,实现了把类数组转换为数组
return arr;
};
 
let arr = [10, 20, 30];
// 数组克隆
let arr2 = arr.slice(); 
console.log(arr2);//=>[10, 20, 30]


//2.arguments操作
Array.prototype.slice = function slice() {
// 把arguments转换为数组的代码
let arr = [];
for (let i = 0; i < arguments.length; i++) {
	arr.push(arguments[i]);
} 		
return arr;
};

let arr = [10, 20, 30];
console.log(arr);//=>[10, 20, 30]

6.除了能借用SLICE,数组的大部分方法都可以借用过来使用的

function func() {
	[].forEach.call(arguments, item => {
		console.log(item);
	});
}
func(10, 20, 30);