# 函数
函数是 javascript 世界中的一等公民,技能是定义作用域。 一般存在四种基本形式:函数声明、函数表达式、函数嵌套、闭包。 只有声明的函数才具有提升的特性。
函数声明(函数提升)
function func(){
console.log("函数的声明形态")
}
1
2
3
2
3
函数表达式
// 函数的表达式形态 之一
let func0 = function(){
console.log("函数的表达式形态");
}
// 函数的表达式形态 之二
(function func1() {})
1
2
3
4
5
6
7
2
3
4
5
6
7
函数嵌套
let func2 = function(){
console.log("函数的嵌套形态");
let func3 = function(){
console.log("func2嵌套在func1里")
}
func3();
}
1
2
3
4
5
6
7
2
3
4
5
6
7
闭包
let func4 = function(){
var a = "func4";
return function(){
console.log("我是以闭包形态存在的函数:"+a);
}
}
1
2
3
4
5
6
2
3
4
5
6
# 立即执行函数
立即执行函数IIFE
(Immediately-Invoked Function Expression)
(function(){
console.log("我是立即运行的匿名函数");
})();
(function(){
console.log("我也是立即运行的匿名函数");
}());
1
2
3
4
5
6
7
2
3
4
5
6
7
# 箭头函数
箭头函数(又叫做lambda表达式
)不暴露 arguments 对象。箭头函数可以保持this的指向,总是指向定义它时所在的上下文环境。
箭头函数不能作为构造函数,因此无法被new操作。
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
1
2
2
# 高阶函数
如果某个函数接收另一个函数作为参数或者返回值为一个函数,该函数就称之为高阶函数(HOF)。
回调函数是最常见的高阶函数
function fn1(cb){
cb && cb();
}
1
2
3
2
3
数组中的高阶函数:
Array.prototype.map
Array.prototype.reduce
Array.prototype.filter
Array.prototype.sort
# 函数重载
重载是面向对象编程语言(比如Java、C#)里的特性,JavaScript语言并不支持该特性。所谓重载(overload), 就是函数名称一样,但是随着传入的参数个数不一样,调用的逻辑或返回的结果会不一样。jQuery之父John Resig 曾经提供了一个非常巧妙的思路实现重载,代码如下:
(() => {
// IIFE+箭头函数,把要写的代码包起来,避免影响外界,这是个好习惯
// 当函数成为对象的一个属性的时候,可以称之为该对象的方法。
/**
* @param {object} 一个对象,以便接下来给这个对象添加重载的函数(方法)
* @param {name} object被重载的函数(方法)名
* @param {fn} 被添加进object参与重载的函数逻辑
*/
function overload(object, name, fn) {
// 存放旧函数,本办法灵魂所在,将多个fn串联起来
var oldMethod = object[name];
object[name] = function() {
// fn.length为fn定义时的参数个数,arguments.length为重载方法被调用时的参数个数
if (fn.length === arguments.length) {
// 若参数个数匹配上 就调用指定的函数fn
return fn.apply(this, arguments);
} else if (typeof oldMethod === "function") {
// 若参数个数不匹配 就调旧函数
return oldMethod.apply(this, arguments);
// 注意:当多次调用overload()时,旧函数中又有旧函数,层层嵌套,递归地执行if..else
// 判断,直到找到参数个数匹配的fn
}
};
}
// 不传参数时
function fn0() {
return "no param";
}
// 传1个参数
function fn1(param1) {
return "1 param:" + param1;
}
// 传两个参数时,返回param1和param2都匹配的name
function fn2(param1, param2) {
return "2 param:" + [param1, param2];
}
let obj = {}; // 定义一个对象,以便接下来给它的方法进行重载
overload(obj, "fn", fn0);//给obj添加第1个重载的函数
overload(obj, "fn", fn1);//给obj添加第2个重载的函数
overload(obj, "fn", fn2);//给obj添加第3个重载的函数
console.log(obj.fn());//>> no param
console.log(obj.fn(1));//>> 1 param:1
console.log(obj.fn(1, 2));//>> 2 param:1,2
})();
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
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
# arguments
# 函数的arguments为什么不是数组?如何转化成数组?
因为argument
是一个对象【类数组】,它的属性从0开始,依次为0,1,2...最后还有callee和length属性。
常见的类数组:
getElementByTagName()
、getElementsByClassName()
、getElementsByName()
获得的HTMLCollection.querySelector()
获得的nodeList
转化成数组:
for in
循环Array.prototype.slice.call()
let argsArr = Array.prototype.slice.call(arguments, 1);
1
Array.from()
let argsArr = Array.from(arguments);
1
- ES6展开运算符
let argsArr = [...arguments]
1
concat
+apply
// apply方法会把第二个参数展开
let argsArr = Array.prototype.concat.apply([], arguments)
1
2
2
# 构造函数
- 构造函数也是一个普通函数,创建方式和普通函数一样,但是构造函数 习惯上首字母大写
- 调用方式不一样,普通函数直接调用,构造函数要用关键字 new 来调用
- 调用时,构造函数内部会创建一个新对象,就是实例,普通函数不会创建新对象
- 构造函数内部的 this 指向实例,普通函数内部的 this 指向调用函数的 对象(如果没有对象调用,默认为 window)
- 构造函数默认的返回值是创建的对象(也就是实例),普通函数的返回 值由 return 语句决定
- 构造函数的函数名与类名相同
← 数组 Curry - 函数柯里化 →