第二章-函数
1 函数的定义和调用
基本格式
function 函数名(参数列表){
函数体
}
函数体中的return一旦执行, 函数就不在执行而是返回了
如果没有return, 则函数执行完毕就结束, 返回的值是undefined
第二种函数定义
var 函数名 = function (参数列表){
函数体
};
注意最后严谨一点加上分号表示赋值语句结束, 整个句子表示将函数赋值给一个变量, 该变量(参数列表) 就可以执行函数了
调用函数
函数名(参数列表);
函数赋值的变量(参数列表);
JavaScript有个十分随意的设定, 传入的参数是, 可以传入多余需要的参数, js会按照顺序得到需要的参数, 剩余的参数不管, 不会报错, 同理少传入参数也没有关系, 缺少的参数会设置为undefined
在函数内部, 有个特殊变量arguments
该变量存储传入进来的所有参数, 可以用类似于数组的方式获得数据
配合arguments使用的是rest, 它可以排除函数定义的参数列表的参数
当传入的参数少于参数列表的参数, rest得到的是一个空数组, 而不是undefined
特殊注意:
JavaScript尽管可以不加分号, 但是它实际上会在一行的末尾自动添加上分号
这点就可能造成一下误会, 比如return与后面的返回值写成了两行, 那么其实际情况会是return; 返回语句;这样就出意外了
2 变量作用域
在函数内定义的变量的作用域只是函数, 函数外面无法引用到函数内部定义的变量
函数可以嵌套, 内部函数可以使用外部函数的变量, 但反过来不行
变量的查找也是从内向外查找的
特殊注意:变量提升
JavaScript在函数中有一个十分诡异的操作
它会先过一遍函数体, 然后把所有变量声明提到函数体首部
因此在函数中, 一定要养成先定义变量的好习惯
不在任何函数内定义的变量就具有全局作用域
事实上, 是将该变量绑定给了特殊对象windows
因此JavaScript只有一个全局作用域
为了解决这个问题, 可以使用名字空间
定义一个全局变量, 这个变量是个对象类型, 以后就往这个对象上添加内容就好了, 这样就会减少重名的情况
for循环不能形成局部作用域, 要使得for中的变量是局部的, 需要使用关键字let
let用于代替var声明一个块级作用域的变量
常量, 名字的所有字母用大写形式表示, 尽管它确实可以被修改, 但是不要修改它
常量可以用const来定义
3 方法
绑定给对象的函数叫做方法
在方法中, 有个特殊的变量this, 这个值始终指向当前对象
但是如果直接调用计算age的方法, 就会出现预期之外的答案
原因是, this会视情况而定指向谁, xiaoming.age就是执行的xiaoming, getAge()实际上是windows.getAge()所以指向的是windows
可以使用apply或者来实现具体制定this指向
apply(指向的对象, [原函数的参数列表])
call(指向的对象, 原函数的参数列表)
装饰器
装饰器的意思是在不改变原有函数的基础上, 给其新增功能
JavaScript的实现是, 将原来的函数保存起来, 在定义同名的函数, 这个函数内部先执行添加功能的代码, 再执行原函数
代码如下
var count = 0;
var oldParseInt = parseInt;
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
parseInt('10');
parseInt('20');
parseInt('30');
count;
记得使用原函数的时候, 要使用apply函数防止原函数中的this失效
4 高阶函数
高阶函数, 这个函数的参数是另一个函数(一个函数作为另一个函数的参数, 这种函数就是高阶函数)
(1) map和reduce
扩展阅读: MapReduce: Simplified Data Processing on Large Clusters
map会传入一个函数作为参数, 会让一个序列的所有值都让该函数执行, 然后将结果返回最后组成一个新的序列
reduce方法是取两个参数给函数, 函数再返回一个结果加上一个新元素, 继续运算, 直到运算完毕
奇怪的现象
(2) filter
filter用于过滤, 传入一个函数, 该函数的返回值是true和false, 当返回值为true时, 该值被保留, 为false时不保留
filter接受的函数事实上是一个回调函数, 可以接受三个参数, 分别是: 元素, 索引, 调用者本身
利用filter删除重复的元素
(3) sort
用于排序, 但是这个排序十分的诡异
排序是按照ASCII的顺序排序的, 非字符串会转成字符串排序
数字自己不能比较大小的吗? 嗯?
因此sort()可以传入一个排序函数作为排序的手段, 用返回值标记大小, 如-1, 0, 1
5 闭包
函数也可以作为结果, 被一个函数返回(返回值也可以是一个函数)
闭包的应用
6 箭头函数
箭头函数的定义基本格式是:
(参数列表) => {函数体}
如果函数体比较简陋, 就是一个表达式, 那么可以省略花括号和return
如果返回一个对象, 对象的花括号要记得写
注意, 如果使用箭头函数, 调用call和apply的时候, 平时传递的第一个参数对象时不会生效的, 箭头函数会直接忽略它
可以看到结果是25而不是15
7 生成器
在js中, 可以使用yield来生成生成器, 且函数同时还可以使用return关键字
生成器形成之后需要调用next()来获取值
可以直接使用for..of来获取全部结果