# apply | bind | call

# apply

# 介绍

👍➡️MDN官网apply介绍⬅️

Function.apply(obj, args) 方法能接收两个参数
obj: 这个对象将代替Function类里this对象
args: 这个是数组, 它将作为参数传给Function( args-- > arguments)
1
2
3

# 使用

  • 实现继承效果

function Person(name, age) {
    this.name = name;
    this.age = age;
}
/*定义一个学生类*/

function Student(name, age, grade) {
    Person.apply(this, arguments);
    this.grade = grade;
}
//创建一个学生类
let student = new Student("zhangsan", 21, "一年级");
//测试
alert(
    "name:" +
    student.name +
    "\n" +
    "age:" +
    student.age +
    "\n" +
    "grade:" +
    student.grade
);
/*
name:zhangsan
age:21
grade:一年级
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

解释

apply是应用的意思,即为把Person应用到Student的this上。或者理解为Student的this去调用Person方法, this.Person(arguments) ,因为是Student的this去调用的Person函数,故Person函数中this指向了Student中的this(此处重要:得出一个结论,函数的调用方式决定了 this 的值(运行时绑定)。详见箭头函数和普通函数的区别),会把Person当中的属性添加到Student的this上。

Student 实现了继承于 Person 构造函数

  • 用 apply 将数组各项添加到另一个数组

我们可以使用 push 将元素追加到数组中。由于 push 接受可变数量的参数,所以也可以一次追加多个元素。

但是,如果 push 的参数是数组,它会将该数组作为单个元素添加,而不是将这个数组内的每个元素添加进去,因此我们最终会得到一个数组内的数组。如果不想这样呢?concat 符合我们的需求,但它并不是将元素添加到现有数组,而是创建并返回一个新数组。 然而我们需要将元素追加到现有数组...... 那么怎么做好?难道要写一个循环吗?别当然不是!

apply 正派上用场!

/* push */
let array = ["a", "b"];
let elements = [0, 1, 2];
/* 方法一 */
array.push.apply(array, elements);
/* 方法二 */
Array.prototype.push.apply(array, elements)
console.info(array); // ["a", "b", 0, 1, 2]

/* Max|Min */
/* 找出数组中最大/小的数字 */
let numbers = [5, 6, 2, 3, 7];
/* 使用Math.min/Math.max以及apply 函数时的代码 */
let max = Math.max.apply(
    null,
    numbers
); /* 基本等同于 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..) */
let min = Math.min.apply(null, numbers);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

apply 的一个巧妙的用处, 可以将一个类数组数组默认的转换为一个参数列表 [param1,param2,param3] 转换为 param1,param2,param3 这个如果让我们用程序来实现将数组的每一个项, 来装换为参数的列表, 可能都得费一会功夫, 借助 apply 的这点特性, 所有就有了以上的特殊用法。

  • 一些其他的用法(将数组转换为下标对象)
const arr = ['niko', 'simple', 'device']
let a = {};
Array.prototype.push.apply(a, arr);
//@ts-ignore
console.log(a); // 输出: {0: 'niko', 1: 'simple', 2: 'device', length: 3}
1
2
3
4
5

# bind

# 介绍

MDN介绍:bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

实现Bind

Function.prototype.bind = function(context) {
    var self = this; // 保存原函数
    return function() { // 返回一个新的函数
        return self.apply(context, arguments);
        // 执行新的函数的时候,会把之前传入的 context // 当作新函数体内的 this
    }
};
var obj = {
    name: 'sven'
};
var func = function() {
    alert(this.name);
}.bind(obj);
func();
// 输出:sven
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

bind函数使用方法有三种

  • 创建绑定函数
  • 偏函数
  • 配合 setTimeout

# 创建绑定函数

使用最多的一种方法,在React类式编写的组件中,广泛的使用这种方法来解决this指向问题。

const module = {
    x: 42,
    getX: function() {
        return this.x;
    }
};

const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 偏函数 (一种很新奇的使用方式)

MDN介绍:bind() 的另一个最简单的用法是使一个函数拥有预设的初始参数。只要将这些参数(如果有的话)作为 bind() 的参数写在 this 后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。

具体示例请查看MDN-bind偏函数 (opens new window)

# 配合 setTimeout

MDN介绍:在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window(或 global)对象。当类的方法中需要 this 指向类的实例时,你可能需要显式地把 this 绑定到回调函数,就不会丢失该实例的引用。

具体示例请查看MDN-bind 配合 setTimeout (opens new window)

# call

# 介绍

MDN介绍: call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。理解为使用一个this去调用一个函数,并给这个函数传递一个或多个参数

function Product(name, price) {
    this.name = name;
    this.price = price;
}

function Food(name, price) {
    Product.call(this, name, price);
    this.category = 'food';
}

console.log(new Food('cheese', 5).name);
// Expected output: "cheese"
1
2
3
4
5
6
7
8
9
10
11
12

以上表示,使用 Food 中的 this 去调用 Product函数 ,用给Product传递了两个参数 name,price ,形式为 this.Product(name,price)

TIP

备注: 该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。

# 参考文献

Last Updated: 3/4/2024, 3:06:40 PM