廖雪峰JS学习总结-函数篇
2017-03-10 本文已影响91人
hlemon
最近在刷廖雪峰的JS教程,把里面的自己不太清楚的东西在刷一遍。
教程网址:http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000
函数的定义和调用:
- 如果没有
return
语句,函数执行完毕后也会返回结果,只是结果为undefined
。 - JavaScript允许传入任意参数,即使函数内部不需要这些参数,也不影响调用。
- JavaScript还有一个免费赠送的关键字
arguments
,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments
类似Array
但它不是一个Array
- 利用
arguments
即使函数不定义任何参数,还是可以拿到参数的值。
function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}
abs(); // 0
abs(10); // 10
abs(-9); // 9
- ES6引入了新的
rest
参数,他可以获得额外的rest
参数,rest
参数只能写在最后,前面用...标识,从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest
,所以,不再需要arguments我们就获取了全部参数。(如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined))
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
-
return
语句必须在一行上,如果必须为多行返回,需要在retrun
后紧跟{
,正确的多行写法如下:
function foo() {
return { // 这里不会自动加分号,因为{表示语句尚未结束
name: 'foo'
};
}
变量作用域:
- 如果用
var
在函数体内声明变量,该变量作用域为整个函数;因为这个原因,在不同函数内部用var申明的同名变量互相独立,互不影响。 - 由于函数可以相互嵌套,内部函数可以访问外部函数定义的变量,但是如果内部和外部都定义了同名变量怎么办了?JS函数查找变量会从自身定义函数开始,也就是从’内’向’外’,顺着作用域链查找,如果内部函数已经定义了,则会’屏蔽’掉外部函数变量。
- JS函数的
var
定义有个特点,它会先扫描整个函数体的语句,把所有var
申明的变量“提升”到函数顶部,所以定义变量时,我们应该严格遵守在函数内部先声明的规则。 - JavaScript默认有一个全局对象
window
,全局作用域的变量实际上被绑定到window
的一个属性上了。 - 为了防止造成命名冲突,比较好的方法是把自己的所有变量和函数,都绑定到一个全局变量中:
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
- 在for循环是无法定义具有局部作用域的的变量的。在ES6中可以使用
let
替代var
可以申明一个块级作用域的变量。 - 对于常量的定义,以前都是使用全部大写来规定,现在ES6总可以使用关键字
const
来定义常量,const
与let
都具有块级作用域,并且const
定义以后无法修改。 - 补充说明一下
let
和const
的特点,不存在变量提升、会造成暂时性死区、不允许重复定义。
方法:
在一个对象中绑定函数,称为这个对象的方法。这里要介绍一个很坑爹的概念,就是this
的指向问题。
那么对于不同的调用,这个this
的指向分别是什么了??
答:this
的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this
到底指向谁,实际上this
的最终指向的是那个调用它的对象。
在《javascript语言精髓》中大概概括了4种调用方式:
1. 方法调用模式
2. 函数调用模式
3. 构造器调用模式
4. apply/call调用模式
特别补充:
- 在构造器调用时,如果加入了
return
并且return
了一个对象,this
会指向这个return
的对象。 - 严格模式下在函数内部定义的函数,
this
指向undefined
(在非strict模式下,它指向全局对象window
)
那么有没有办法去控制this
的指向了?
有的,可以使用函数本身的apply
方法,它接收两个参数,第一个参数就是需要绑定的this
变量,第二个参数是Array
,表示函数本身的参数。另一个与apply()
类似的方法是call()
,唯一区别是:
-
apply()
把参数打包成Array
再传入; -
call()
把参数按顺序传入。
另外ES5还加入了一个bing()
方法,它会创建一个函数的实例,其this值会被绑定到传给bind()
函数的值。
利用apply()
,我们还可以动态改变函数的行为。
JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。
高阶函数:
- 一个函数接收另一个函数作为参数,这种函数就称之为高阶函数。
-
forEach
方法,是最基本的方法,就是遍历与循环,默认有3个传参:分别是遍历的数组内容item、数组索引index、和当前遍历数组Array。另外,除去第一个必须的回调函数参数,还可以接受一个上下文参数(改变回调函数的this
指向);并且forEach
不会遍历空元素。 -
map
方法,基本用法与forEach
一致,但是不同的,它会返回一个新的数组,所以在callback
需要有return
值,如果没有,会返回undefined
。(从字面理解,map就是映射的意思) -
filter
方法,用法和map
很相似,从字面理解,就是过滤、筛选的意思。但是函数的callback
需要返回布尔值true
或false
,并且返回值只需要为弱等==即可。 -
some
方法,对数组中每一项运行指定函数,如果该函数对任一项返回true
,则返回true
。(一旦遇到true
,就会中断循环,返回true,类似于||判断) -
every
方法,对数组中的每一项运行给定函数,如果该函数对每一项返回true
,则返回true
。(一旦遇到false
,就会中断循环,返回false
,类似于&&
判断) -
sort
方法,默认把所有元素先转换为String
再进行ASCII码排序,所以这个很坑爹。要想正确的排序,需要添加一个函数。sort
方法,可以接受一个回调函数,默认有两个传参:分别是比较的数组项。
闭包:
「闭包」,是指那些能够访问独立(自由)变量的函数 (变量在本地使用,但定义在一个封闭的作用域中)。换句话说,这些函数可以“记忆”它被创建时候的环境。特性:
- 函数嵌套函数
- 函数内部可以引用外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
箭头函数:
- 箭头函数使得表达更加简洁。
- 函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象。 - 不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。 - 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用Rest
参数代替。 - 不可以使用
yield
命令,因此箭头函数不能用作Generator
函数。
Generator:
-
Generator
函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。 -
next
法返回值的value
属性,是Generator
函数向外输出数据;next方法还可以接受参数,向Generator
函数体内输入数据。 -
Generator
函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。