函数
2018-01-27
JavaScript 基础:函数
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions
1. 函数声明
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function
function name() {}
函数提升
提升整个函数定义,与变量仅提升声明不同。
后声明的函数会覆盖先声明的函数。
条件表达式中的函数声明
强烈推荐不要在条件表达式中使用函数声明,因为各种实现很混乱。以下测试仅为验证其混乱,实际编码中如有需要请使用函数表达式方式(const name = function() {}
)。
混乱原因:简单讲就是因为 ECMAScript 标准中并未规定函数声明在 Block(如 if、while、for 等)中的行为,所以各浏览器会有各自的实现。
来源:http://kangax.github.io/nfe/#function-declarations-in-blocks
注:桌面浏览器老版本及移动端暂未测试。
非严格模式下
经测试,Firefox 57、Chrome 63、IE 11、Edge 环境下:
- True:条件表达式内的函数声明在函数块将要执行时生效,且先提升到作用域最顶部,再执行其他代码。
- False:条件表达式内的函数声明无效。
name(); // 5,被 if 块外的最后一个声明覆盖。因还未执行到 if 块,所以 if 块内的函数声明尚未生效。
// 被最后的 ‘5’ 覆盖
function name() {
console.log(1);
}
// IIFE 内的代码是封闭的,不影响外部
(function () {
name(); // 2,name() 被提升到了作用域最顶部
function name() {
console.log(2)
}
name(); // 2
})()
// 与 IIFE 类似,函数内有效。
function func() {
name(); // 6
function name() {
console.log(6);
}
name(); // 6
}
func();
if (true) {
name(); // 3,name() 先被覆盖,再执行
function name() {
console.log(3);
}
name(); // 3
} else {
// 未执行,块内代码不影响其他地方
name();
function name() {
console.log(4);
}
name();
}
name(); // 3,因在 if 块内 name() 被重新声明
// 一开始被提升到最顶部,随着 if 内的代码执行而被覆盖。
function name() {
console.log(5)
}
name(); // 3
而 Safari 11 中条件表达式内的函数声明和其他不同(True 和 False 内的声明均有效并提升),不过理解起来倒也简单:相同作用域下同名函数声明只有最后一个有意义,且会被提升到作用域最顶部。
name(); // 4
// 被 false 块内的声明覆盖
function name() {
console.log(1);
}
// IIFE 内的代码是封闭的,不影响外部
(function () {
name(); // 2,name() 被提升到了作用域最顶部
function name() {
console.log(2)
}
name(); // 2
})()
// 与 IIFE 类似,函数内有效。
function func() {
name(); // 6
function name() {
console.log(6);
}
name(); // 6
}
func();
if (true) {
name(); // 4
// 此处的声明也会生效,只不过在本例中被后面的覆盖掉了
function name() {
console.log(3);
}
name(); // 4
} else {
name();
// 覆盖了所有前面的函数生命
function name() {
console.log(4);
}
name();
}
name(); // 4
// 如果下面的代码没有被注释掉,所有输出 4 的函数将输出 5。函数内的函数不受影响。
// function name() {
// console.log(5)
// }
name(); // 4
严格模式下
严格模式下以上浏览器效果是一致的,与非严格模式不同,严格模式 if
内的声明不会影响到外部。
因测试样本有限,请不要依赖严格模式。
'use strict'
name(); // 5,被 if 块外的最后一个声明覆盖。因还未执行到 if 块,所以 if 块内的函数声明尚未生效。
// 被最后的 ‘5’ 覆盖
function name() {
console.log(1);
}
// IIFE 内的代码是封闭的,不影响外部
(function () {
name(); // 2,name() 被提升到了作用域最顶部
function name() {
console.log(2)
}
name(); // 2
})()
// 与 IIFE 类似,函数内有效。
function func() {
name(); // 6
function name() {
console.log(6);
}
name(); // 6
}
func();
if (true) {
name(); // 3,函数被提升到 if 块顶部
function name() {
console.log(3);
}
name(); // 3
} else {
// 未执行,块内代码不影响其他地方
name();
function name() {
console.log(4);
}
name();
}
name(); // **5**,if 块内的声明未影响到外部
// 被提升到最顶部,if 块内的代码对其无影响
function name() {
console.log(5)
}
name(); // **5**,if 块内的声明未影响到外部
2. 函数表达式
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/function
// 此时函数是匿名函数,函数名称只是函数体中的一个本地变量。
const name_1 = function () {}
console.log(name_1.name); // name_1
const name_2 = function name () {}
console.log(name_2.name); // name
// ES2015
const name_3 = () => {}
console.log(name_3.name); // name_3
函数提升:不会被提升。
3. Function 构造函数
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function
const name = new Function(arg1, arg2, functionBody)
使用 Function 构造器生成的 Function 对象是在函数创建时解析的。比使用函数声明或函数表达式声明函数并调用更低效,因为这两种方式声明的函数是和其他代码一起解析的。
Function构造器生成的函数,在全局作用域中被创建
// 1、f()函数返回的function e()是闭包
var n = 1;
function f(){
var n = 2;
function e(){
return n;
}
return e;
}
console.log (f()()); //2
// 2、f()函数返回的function e()是全局作用域函数
var n = 1;
function f(){
var n = 2;
var e = new Function("return n;");
return e;
}
console.log (f()()); //1