JS进阶 - 函数
1. 定义
- 匿名函数
1 | function (){ |
- 具名函数
1 | function fn3 (){ |
- 箭头函数
1 | var fn5 = e => e+1; |
三个函数前两个区别在于名称,实际都有 .nam
第三个函数特殊之处在于 this
2. 词法作用域
词法作用域也作静态作用域
1 | var global = 1 |
浏览器看到这一段代码时,会先将它变成抽象语法树。
global 和 fn1 同级
fn1 创建了五个变量,local1 local2 param1 fn2 fn3
深入阅读
3. Call Stack
数据结构 栈 – Stack 先进后出 后进先出
1 | a() |
4. this & arguments
- this 是隐藏的第一个参数,且必须为对象
1 | function f(){ |
为什么我们使用 f.call() 而不是 f()?
因为 f() 就是 阉割版的 f.call()
this 为什么必须是对象
因为 this 就是函数与对象之间的羁绊
1 | var person = { |
因为函数的本质是存储在堆内存中的一串地址数据,它本身只是一个数值,所以受上下文环境影响(函数可以在不同的上下文环境中运行)。
this 就是 call 的第一个参数!call 的其他参数统称为 arguments
https://zhuanlan.zhihu.com/p/23804247
5. call/apply
比如我们想要求一个数组之中所有数的总和,但是我们不知道这个数组有多少项目,那我们可以使用 apply。
当我们不确定数据的长度的时候,我们可以使用 apply 来代替 call。
6. bind
call 和 apply 是直接调用函数,而 bind 是返回一个函数,他没有调用原来的函数,这个新的函数会 call 原来的函数,call 的参数你来指定。
7. return
每个函数都有 return,如果不写那就是 undefined
8. 柯里化/高阶函数
返回函数的函数
柯里化:将 f(x,y) 变成 f(x=1)(y) ,用来惰性求值,也就是将真实计算拖延到最后再做
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 柯里化之前
function sum(x, y){
return x + y;
}
// 柯里化之后
function addOne(y){
return sum(1, y);
}
// 柯里化之前
function Handlebar( template, data ) {
return template.replace('{{name}}', data.name)
}
// 柯里化之后
function Handlebar ( template, data ) {
return fucntion ( data ) {
return template.replace('{{name}}', data.name)
}
}相关文章:http://www.yinwang.org/blog-cn/2013/04/02/currying
https://zhuanlan.zhihu.com/p/31271179高阶函数
在数学和计算机科学中,高阶函数是至少满足下列一个条件额函数:
- 接受一个或多个函数作为输入:forEach map sort
- 输出一个函数:loadsh.curry
- 不过它通常同时满足两个条件:bind
9. 回调 Callback
- 名词形式:被当作参数的函数就是回调
- 动词形式:调用这个回调
回调和异步没有任何关系
10. 构造函数
返回对象的函数就是构造函数
一般首字母大写
1 | new Number(1) |
不过很少有函数返回对象,大多都是基础数据类型。
11. 箭头函数
ES 带来的特别好用的一个东西
很简单:
1 | // 正常的写一个函数 |
箭头函数不存在 this(官方明示 this 不好用)
我们以 setTimeout 为例子:
1 | setTimeout(function(){ |
以上是旧的方式,我们需要使用到 bind
下面我们来看一下箭头函数的方法:
1 | setTimeout(function(){ |
如果你希望某个函数里面的 this 和外面的 this 是一个 this 的时候,你就可以使用箭头函数。
每次进入一个函数的时候,首先它会进入栈,然后一定会确定一个 this,没法不传,它是一个 JS 设计的漏洞。我们使用箭头函数来规避掉麻烦的 this,但是它是有 arguments 的。
这才是真正的函数。
下面我们来看一下奇怪的东西:
1 | var fn = () => console.log(this) |
这样子 this 就从参数转变为变量。
这就回到了我们之前提到的词法作用域上面,当我们声明一个带参数的函数的时候,它会新建此参数。
习题
请写出一个柯里化其他函数的函数 curry,这个函数能够将-接受多个参数的函数-,转变为-多个接受一个参数的函数-,见示例:
1 | // loadsh.curry |
写一个函数的时候,我们只要关注输入和输出。
形式大于逻辑:
1 | function curry(func, fixedParams){ |