一、函数定义与调用
1.1、函数
如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined。
匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数,两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束
1.2、arguments
JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array:
即arguments指向传入的所有参数,如果是多个可以看成Array
利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:
实际上arguments最常用于判断传入参数的个数,要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值
1.3、ES6标准引入了rest参数
rest参数只能写在最后,前面用...标识,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。
如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。
二、变量作用域与解构赋值
作用域
在JavaScript中,用var申明的变量实际上是有作用域的。如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量
如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响
由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行:
JavaScript的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量
变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部,JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值(简单来说就是变量存在,但是值undefined)
严格遵守“在函数内部首先申明所有变量”这一规则
全局作用域
不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性
JavaScript实际上只有一个全局作用域。任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报ReferenceError错误
名字空间
全局变量会绑定到window上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中(放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能)
局部作用域
由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的
为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量
let和var的区别:
1、let用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效;
2、let不存在变量提升;
3、只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响
4、let不允许在相同作用域内,重复声明同一个变量
const和var的区别:
1、const声明一个只读的常量。一旦声明,常量的值就不能改变,在js中通常用全部大写的变量来表示“这是一个常量,不要修改它的值”
2、const一旦声明变量,就必须立即初始化,不能留到以后赋值
3、const命令声明的常量不存在提升
4、const声明的常量不可以重复声明
解构赋值
从ES6开始,JavaScript引入了解构赋值,可以同时对一组变量进行赋值
传统的解构赋值的方法:
ES6中,可以使用解构赋值,直接对多个变量同时赋值
对数组元素进行解构赋值时,多个变量要用[...]括起来
如果数组本身还有嵌套,也可以通过下面的形式进行解构赋值,注意嵌套层次和位置要保持一致
eg:属性名要一致
对一个对象进行解构赋值时,同样可以直接对嵌套的对象属性进行赋值,只要保证对应的层次是一致的
使用解构赋值对对象属性进行赋值时,如果对应的属性不存在,变量将被赋值为undefined,这和引用一个不存在的属性获得undefined是一致的。如果要使用的变量名和属性名不一致,可以用下面的语法获取
解构赋值还可以使用默认值,这样就避免了不存在的属性返回undefined的问题
eg:如果变量已经被声明了,再次赋值的时候,正确的写法也会报语法错误,解决方法:
解构赋值使用的场景:
1、解构赋值在很多时候可以大大简化代码。例如,交换两个变量x和y的值,可以这么写,不再需要临时变量
2、快速获取当前页面的域名和路径
3、如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。
例如,下面的函数可以快速创建一个Date对象
eg:使用解构赋值可以减少代码量,但是,需要在支持ES6解构赋值特性的现代浏览器中才能正常运行。
三、方法
对象的方法:在一个对象中绑定函数
方法和普通函数没有什么区别,关键是关键字this的指向
1、粗暴的解决方法:
解决办法;
2、使用apply或者call动态改变函数(包括this指向):
要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数
apply用法:
1、apply可以接受两个参数,所以其一可以改变this指向
2、apply可以接受两个参数,所以其二可以改变或者替换对象
apply和call的区别
唯一的区别就是传入的参数列表方式不同
apply()把参数打包成Array再传入
call()把参数按顺序传入