# 实现apply、call、bind
# call函数的实现
//给所有函数添加一个oncall方法
Function.prototype.oncall = function (thisArg,...args) {
//在这里获取需要调用的函数 foo,因为是隐式绑定,this指向的就是函数本身。
//...arg是剩余参数
var fn = this
//将thisArg转成对象类型,进行判断,如果是null等就绑定为window
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
//通过thisArg进行调用,隐式绑定将this绑定为thisArg
thisArg.fn = fn
result = thisArg.fn(...args)//这里...是展开
//返回结果
return result
delete thisArg.fn
}
function foo() {
console.log("foo被调用了",this)
}
function sum(num1,num2) {
console.log( this,num1 + num2)
}
sum.oncall("aaa",1,2) //可以看作一个隐式绑定,这时的this就是函数本身
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
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函数的实现
//给所有函数添加一个onapply方法
Function.prototype.onapply = function (thisArg,argArray) {
//获取到要执行的函数
var fn = this
//对thisArg进行处理
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
//执行函数,绑定this
thisArg.fn = fn
//判断argArray有没有值
//argArray = argArray ? argArray : []
argArray = argArray || []
result = thisArg.fn(...argArray)//这里...是展开
delete thisArg.fn
//返回结果
return result
}
function foo() {
console.log("foo被调用了",this)
}
function sum(num1,num2) {
console.log( this,num1 + num2)
}
foo.onapply("aaa")
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
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
# bind函数的实现
Function.prototype.onbind = function(thisArg,...argArray){
//返回一个新函数
var fn = this
//对this进行判断,绑定this
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
function proxyFn(...args){
//通过thisArg进行调用,隐式绑定将this绑定为thisArg
thisArg.fn = fn
//解决参数问题 对两个参数进行合并
var finalArgs = [...argArray,...args]
var result = thisArg.fn(...finalArgs)
delete thisArg.fn
//返回结果
return result
}
return proxyFn
}
function sum(num1,num2,num3,num4){
console.log(num1,num2,num3,num4,this)
}
//bind的参数可以分别传递
var newSum = sum.onbind("abc",10,20)
newSum(30,40)
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
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
# arguments
argument 是一个对应于 传递给函数的参数 的 类数组(array-like)对象。
function foo(num1,num2,num3){
console.log(num1,num2,num3)
}
//参数会被放到一个类数组中
foo(10,20,30,40)
1
2
3
4
5
6
7
2
3
4
5
6
7
# aguments操作
# 获取参数长度:aguments.length
function foo(num1,num2,num3){
console.log(arguments.length)//3
}
foo(10,20,30)
1
2
3
4
5
6
2
3
4
5
6
# 获取某一个参数:arguments[i]
function foo(num1,num2,num3){
console.log(arguments[0])//10
console.log(arguments[1])//20
console.log(arguments[2])//30
}
foo(10,20,30)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 获取当前arguments所在的函数
function foo(num1,num2,num3){
console.log(arguments.callee)
//f foo(num,num2,num3){...}
}
foo(10,20,30)
1
2
3
4
5
6
7
2
3
4
5
6
7
# arguments 转 Array 类型
# 直接遍历
//遍历arguments
function foo(num1,num2,num3){
var newArr = []
for(var i = 0;i < arguments.length;i++){
newArr.push(arguments[i] * 10)
}
console.log(newArr)
}
foo(10,20,30)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 通过 slice()
- 方法一
function foo(num1,num2,num3){
console.log(Array.prototype.slice.call(arguments))
}
foo(10,20,30,40)
1
2
3
4
5
6
2
3
4
5
6
- 方法二
function foo(num1,num2,num3){
console.log([].slice.call(arguments))
}
foo(10,20,30,40)
1
2
3
4
5
6
2
3
4
5
6
# slice函数的实现
Array.prototype.onslice = function(start,end){
var arr = this
start = start || 0
end = end || arr.length
var newArr = []
for(var i = start;i<end;i++){
newArr.push(arr[i])
}
return newArr
}
function foo(num1,num2,num3){
console.log(
Array.prototype.onslice.call(arguments))
//因为是通过call调用,所以this指向的就是arguments本身
}
foo(10,20,30,40)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ES6语法:Array.from()
function foo(num1,num2,num3){
console.log(Array.from(arguments))
}
foo(10,20,30,40)
1
2
3
4
5
6
2
3
4
5
6
# 展开运算符
function foo(num1,num2,num3){
console.log([...arguments])
}
foo(10,20,30,40)
1
2
3
4
5
6
2
3
4
5
6
# ES6推荐使用args
var foo = (num1,num2,...args) =>{
console.log(args)//[30,40,50]
}
foo(10,20,30,40,50)
1
2
3
4
5
2
3
4
5
# 理解JavaScript纯函数
# 纯函数的定义
# 副作用的理解
# 纯函数的案例
# 数组的两个函数的对比
var names = ["aaa","bbb","ccc","ddd"]
var newNames1 = names.slice(0,3)
//slice()
console.log(newNames1) //[ 'aaa', 'bbb', 'ccc' ]
console.log(names) //[ 'aaa', 'bbb', 'ccc', 'ddd' ]
//splice()
var newNames2 = names.splice(2)
console.log(newNames2)[ 'ccc', 'ddd' ]
console.log(names) [ 'aaa', 'bbb' ]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- slice()函数不会修改原来的值,会返回一个新的函数,符合纯函数的要求。
- splice()函数会修改原来数组对象本身,所以splice()不是一个纯函数。
# 纯函数的优势
# JavaScript柯里化
# 柯里化的定义
- 只传递给函数一部分参数来调用他,让它返回一个函数去处理剩余的参数。
- 这个过程就称为柯里化。
function foo(m,n,x,y){
return m + n + x + y
}
var fo = foo(10,20,30,40)
console.log(fo)
//对上面的函数进行柯里化
function bar(m){
return function(n){
return function(x){
return function(y){
return m + n + x + y
}
}
}
}
var ba = bar(10)(20)(30)(40)
console.log(ba)
//箭头函数写法
var bar = m => n => x => y => m + n + x + y
console.log(bar(10)(20)(30)(40))
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
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
# 柯里化的作用
# 让函数的职责单一
- 在函数式编程中,我们其实希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理过程交给一个函数来处理;
- 那么我们是否就可以将每次传入的参数在单一的函数中进行处理,处理完之后在下一个函数中再使用处理后的结果。
# 逻辑复用
function makeAdder(count){
return function(num){
return count + num
}
}
var adder5 = makeAdder(5)
result1 = adder5(10)
result2 = adder5(15)
console.log(result1)
console.log(result2)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 柯里化函数的实现
function Currying(fn){
function curried(...args){
//判断当前已经接收的参数的个数,判断参数本省需要接收的参数是否已经一致了
//1.当已经传入的参数 大于等于 需要的参数时 就执行函数
if(args.length >= fn.length){
//fn(...args)
//fn.call(this,...args)
return fn.apply(this,args)
}else{
//没有达到个数时,需要返回一个新的函数,继续来接收参数
function curried2(...args2){
//接收到参数之后,需要递归调用curried来检查函数的个数是否达到
return curried.apply(this,[...args,...args2])
}
return curried2
}
}
return curried
}
function foo(m,n,x,y){
return m + n + x + y
}
var fooo = Currying(foo)(1)(2)(3)
console.log(fooo(4))function Currying(fn){
function curried(...args){
if(args.length >= fn.length){
return fn.apply(this,args)
}else{
function curried2(...args2){
return curried.apply(this,[...args,...args2])
}
return curried2
}
}
return curried
}
function foo(m,n,x,y){
return m + n + x + y
}
var fooo = Currying(foo)(1)(2)(3)
console.log(fooo(4))
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
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
# 组合函数
function double(num){
return num * 2
}
function square(num){
return num**2
}
var count = 10
var result = square(double(count))
console.log(result)
function composeFn(m,n){
return function(count){
return n(m(count))
}
}
var newFn = composeFn(double,square)
console.log(newFn(10))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20