1. 函数的声明方式
1 | 1.function a(a,b){ |
2. 若重复声明函数,由于函数名的提升,前一次声明在任何时候都是无效的,这一点要特别注意。如下
function f() {
console.log(1);
}
f() // 2
function f() {
console.log(2);
}
f() // 2
函数的变量提升:
1 | f(); //不会报错,因为下面的变量提升了 |
1 | f(); |
所以如果同时采用function命令和赋值语句声明同一个函数,最后总是采用赋值语句的定义。
1 | var f = function () { |
3. 注意:不要在if语句和try语句里使用函数声明
1 | if (false) { |
4. 函数的属性
name
1 | function f1() {} |
length
1 | function f(a, b) {} |
toString
1 | function f(){ |
5. 局部变量
在函数内部声明的变量是局部变量,在函数以外声明的全是全局变量,在其他区块中声明的一律也是全局变量。
6. 函数内部也有变量提升!
7. 函数的作用域,就是其声明时所在的作用域,与其运行时所在的作用域无关。
1 | var a = 1; |
8. 传递方式
1 | var obj = { p: 1 }; |
如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。
1 | var obj = [1, 2, 3]; |
这是因为,o的值实际是参数obj的地址,重新对o赋值导致o指向另一个地址,保存在原地址上的值不受影响。复合类型是传地址
1 | var p = 2; |
原始类型的值,传入函数只是值的拷贝,所以怎么修改都不会影响到原始值
9. arguments对象
可以通过argument对象获得参数
1 | function f(a, a) { |
正常模式下,arguments对象还可以在运行时修改参数。严格模式下不行
1 | var f = function(a, b) { |
arguments不是数组,但可以转换为数组
10. 返回值
函数即使没有return,JS会自动加上return undefined;
11. function的不一致性
1 | function y(){}; |
12. 函数的调用
1 | f(1,2); |
13. this和arguments
this是call()的第一个参数
1 | f = function(){ |
面试题1:
1 | var obj = { |
面试题2:
1 | function fn (){ console.log(this) } |
我们可以把 arr0 想象为arr.0( ),虽然后者的语法错了,但是形式与转换代码一样,于是:
1 | arr.0.call(arr); |
arguments是伪数组
1 | f = function(){ |
arguments有数组的一些特性,但没有在Array的原型链中,所以arguments没有数组的方法,如push
1 | arguments.__proto__ === Array.prototype //false |
14. 函数的作用域
看到面试题先把代码改了,做变量提升!再做题
面试题1:
1 | var a = 1; |
答案:undefined(f1的console.log)、1(f4的console.log)
面试题2:
1 | var a = 1; |
答案:undefined、2
面试题3:
html
1 | <ul> |
JS
1 | var liTags = document.querySelectorAll('li'); |
答案:6
先JS变量提升
1 | var liTags; |
因为点3时,for循环已执行完了,i变成6,所以输出的是6
面试题4
1 | var x = function () { |
答案:a is not defined
因为函数x在外部,不会引用y的内部变量
15. 闭包
1 | var a = 1; |
若一个函数使用了它作用域外的变量,那 (这个函数+变量) 就是闭包。
函数外部无法访问函数内部的变量,但使用闭包就可以
1 | function f1() { |
本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的第二个作用就是让它读取的这些变量始终保持在内存中
1 | function createIncrementor(start) { |
闭包的另一个用处,是封装对象的私有属性和私有方法。
1 | function Person(name) { |
函数Person的内部变量_age,通过闭包getAge和setAge,变成了返回对象p1的私有变量。
16. 同名参数
1 | function f(a, a) { |
17 .立即调用的函数表达式(IIFE)
1 | function(){ /* code */ }(); |
因为JS把function在行首的,一律解释成语句,而语句后不应该出现(),最简单的处理,就是将其放在一个圆括号里面。
1 | (function(){ /* code */ }()); |
推而广之,任何以表达式来处理函数定义的方法,都是可以的
18. eval
eval命令的作用是,将字符串当作语句执行。
1 | eval('var a = 1;'); |
JavaScript 规定,如果使用严格模式,eval内部声明的变量,不会影响到外部作用域。
1 | (function f() { |
即使在严格模式下,eval依然可以读写当前作用域的变量。
1 | (function f() { |