# call vs apply
# call(this,parameter1,parameter2...)
call 方法的作用是:改变某一涵数中的this关键字,然后执行该方法。例如 fn.call(obj) 在执行call方法时,让 fn 中的 this 变为了第一个参数 obj,然后执行fn
- 首先fn通过__proto__找到 Function.prototype上的call方法
- 原型上的call方法执行,形成一个私有作用域(型参赋值->预解析->代码执行)
- 让fn中的this指向变为第一个参数obj
- 执行fn
# 模拟call方法
let obj = {name: 'newming'}
function fn() {
console.log(this);
}
Function.prototype.call = function (parameter1) {
// call内部的this是fn
// 首先将fn即this的内部this指向改为obj,然后执行fn,即this
this()
}
fn.call(obj) //call方法中的this为fn
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 面试题
function fn1() {
console.log(1);
}
function fn2() {
console.log(2);
}
fn1.call(fn2) // 1
fn1.call.call(fn2) // 2
Function.prototype.call.call(fn1) // 1
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# apply(this,[parameter1,parameter2...])
apply 方法和 call 方法非常相似,都是执行对应的方法,并且改变方法内部的this指向为第一个参数
# 区别
- call 在传递函数的参数值时是一个个的传递进来,而 apply 则是把需要传递的参数放到一个数组中一起传入进来,也是相当于给函数一个个传递参数
# call,apply应用
# 1.获取数组中的最大值最小值
var arr = [23,45,46,22,11,67,4,56]
// 方法一,先排序,在获取
arr.sort(function (a,b) {
return a - b
})
var min = arr[0]
var max = arr[arr.length-1]
// 2.假设法,假设第一个是最小值,和数组后面每一项进行比较,如果假设错误,让假设值变为当前最小值
var min = max = arr[0]
for (var i = 0; i < arr.length; i++) {
var cur = arr[i]
cur<min ? min=cur : null;
cur>max ? max=cur : null;
}
console.log(min, max);
// 3.Math.min,Math.max
var min = Math.min.apply(null,arr)
var max = Math.max.apply(null,arr)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2.获取平均数
// 去掉最高分,去掉最低分
// 1...
function avgFn() {
console.log(arguments);// 注意arguments是一个类数组,不是数组
// 1.把arguments转化为数组
let arr = [];
for (var i = 0; i < arguments.length; i++) {
arr[arr.length] = arguments[i]
}
// 2.数组进行排序,去掉首尾
arr.sort(function (a,b) {
return a - b
})
arr.shift()
arr.pop()
// 3.求和求平均
var total=0;
for (var i = 0; i < arr.length; i++) {
total+=arr[i]
}
return (total/arr.length).toFixed(2)
}
var res = avgFn(3,5,6,7,10,7);
console.log(res);
// 2...
function avgFn() {
// 借用数组方法将类数组转为数组
// 注意,借用数组方法slice将类数组(arguments,dom元素集合)转化为数组的时候,arguments在所以浏览器都兼容,dom元素集合在ie6~8不兼容,可以利用for循环实现兼容
var arr = Array.prototype.slice.call(arguments)
// 2.数组进行排序,去掉首尾
arr.sort(function (a,b) {
return a - b
})
arr.shift()
arr.pop()
// 3.求和求平均
return ( eval(arr.join('+')) / arr.length ).toFixed(2)
}
var res = avgFn(3,5,6,7,10,7);
console.log(res);
// 3...
function avgFn() {
// 借用数组方法
[].sort.call(arguments,function (a,b) {
return a - b
})
[].shift.call(arguments)
[].pop.call(arguments)
// 2.求和求平均
return ( eval([].join.call(arguments, '+')) / arguments.length ).toFixed(2)
}
var res = avgFn(3,5,6,7,10,7);
console.log(res);
// 4...
function avgFn(...arr) {
// 1.数组进行排序,去掉首尾
arr.sort(function (a,b) {
return a - b
})
arr.shift()
arr.pop()
// 2.求和求平均
return ( eval(arr.join('+')) / arr.length ).toFixed(2)
}
var res = avgFn(3,5,6,7,10,7);
console.log(res);
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 模拟call, apply
Function.prototype.call = function call(context, ...args) {
// this 是调用 change 的函数
context = context == undefined ? window : context
let type = typeof context
if (!/^(object|function)$/.test(type)) {
// 如果传入的参数不是一个 object
if (/^(symbol|bigint)$/.test(type)) {
// 如果是 symblo 或者 bigint
context = Object(context)
} else {
// 原始数据类型无法新增属性
context = new context.constructor(context)
}
}
let key = Symbol('key')
let result
context[key] = this
result = context[key](...args)
delete context[key]
return result
}
Function.prototype.apply = function call(context, args) {
// this 是调用 change 的函数
context = context == undefined ? window : context
let type = typeof context
if (!/^(object|function)$/.test(type)) {
// 如果传入的参数不是一个 object
if (/^(symbol|bigint)$/.test(type)) {
// 如果是 symblo 或者 bigint
context = Object(context)
} else {
context = new context.constructor(context)
}
}
let key = Symbol('key')
let result
context[key] = this
result = context[key](...args)
delete context[key]
return result
}
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
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