JavaScript中函数call-apply-bind底层模拟实现

apply代码模拟实现

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* cm_apply
* 通过js手动实现apply函数
* 1. 给所有函数添加cm_apply方法 ===> 在函数原型上添加临时方法
* 2. 先通过this获取需要执行的这个函数
* 2.1. 判断this是否是函数
* 2.2. 判断是否是undefined与null,直接返回window
* 2.3. 判断是否是数字,字符串等原始值,直接使用Object()函数转化为可挂载的对象
* 2.4. 对象即可直接使用
* 3. 使用Symbol()作为key来挂载这个函数
* 4. 处理第二个参数的正确性与规范性
* 4.1. 判断是否传数据
* 4.2. 判断是否为数组,否则报错
* 5. 传入参数并调用挂载的这个函数
* 6. 收集调用结果
* 7. delete 挂载在这个对象上的临时函数
* 8. return这个收集的结果
*/
Function.prototype.cm_apply = function (context, args) {
// 1. 获取需要执行的这个函数
const fn = this;

if (typeof fn !== "function") {
throw TypeError(fn + " is not a function");
}

// 2. 判断context的类型
if (context === undefined || context === null) {
context = window;
} else {
context = Object(context);
}

// 3. 使用Symbol()作为key来挂载这个函数
const key = Symbol();
context[key] = fn;

// 4. 处理第二个参数的正确性与规范性
if (args === undefined) {
args = [];
} else if (!Array.isArray(args)) {
throw new TypeError("CreateListFromArrayLike called on non-object");
}

// 5. 传入参数并调用挂载的这个函数
// 6. 收集调用结果
const result = context[key](...args);

// 7. delete 挂载在这个对象上的临时函数
delete context[key];

// 8. return这个收集的结果
return result;
};

call代码模拟实现

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* cm_call
* 通过js手动实现call函数
* 1. 给所有函数添加cm_call方法 ===> 在函数原型上添加临时方法
* 2. 先通过this获取需要执行的这个函数
* 2.1. 判断this是否是函数
* 2.2. 判断是否是undefined与null,直接返回window
* 2.3. 判断是否是数字,字符串等原始值,直接使用Object()函数转化为可挂载的对象
* 2.4. 对象即可直接使用
* 3. 使用Symbol()作为key来挂载这个函数
* 4. 处理后续参数的正确性与规范性
* 4.1. 判断是否传数据
* 5. 传入参数并调用挂载的这个函数
* 6. 收集调用结果
* 7. delete 挂载在这个对象上的临时函数
* 8. return这个收集的结果
*/
Function.prototype.cm_call = function (context, ...args) {
// 1. 获取需要执行的这个函数
const fn = this;

if (typeof fn !== "function") {
throw TypeError(fn + " is not a function");
}

// 2. 判断context的类型
if (context === undefined || context === null) {
context = window;
} else {
context = Object(context);
}

// 3. 使用Symbol()作为key来挂载这个函数
const key = Symbol();
context[key] = fn;

// 4. 处理后续参数的正确性与规范性
if (args.length === 0) {
args = [];
}

// 5. 传入参数并调用挂载的这个函数
// 6. 收集调用结果
const result = context[key](...args);

// 7. delete 挂载在这个对象上的临时函数
delete context[key];

// 8. return这个收集的结果
return result;
};

bind代码模拟实现

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* cm_bind
* 通过js手动实现bind函数
* 1. 给所有函数添加cm_bind方法 ===> 在函数原型上添加方法
* 2. 先通过this获取需要执行的这个函数
* 2.1. 判断this是否是函数
* 2.2. 判断是否是undefined与null,直接返回window
* 2.3. 判断是否是数字,字符串等原始值,直接使用Object()函数转化为可挂载的对象
* 2.4. 对象即可直接使用
* 3. 处理后续参数的正确性与规范性
* 4.1. 判断是否传数据
* 4.2. 处理分两次传入参数的情况
* 4. return这个返回的函数
*/
Function.prototype.cm_bind = function (context, ...args) {
// 1. 获取需要执行的这个函数
const fn = this;

if (typeof fn !== "function") {
throw TypeError(fn + " is not a function");
}

// 2. 判断context的类型
if (context === undefined || context === null) {
context = window;
} else {
context = Object(context);
}

// 3. 处理后续参数的正确性与规范性
if (args.length === 0) {
args = [];
}

// 4. return这个返回的函数
return function (...newArgs) {
const key = Symbol();
context[key] = fn;
const result = context[key](...args, ...newArgs);
delete context[key];
return result;
};
};