两种常见的function定义:
1⃣️
var func = function(){
...
}
2⃣️
function func(){
...
}
两种定义方式在表现形式上的不同:
第一种var方式定义的函数,不能先调用,后声明;只能先声明,后调用。
第二种function方式定义函数可以先调用,后声明。
(function($) {
var a = 1;
var b = 2;
func1();
var func1 = function () {
alert("func1");
}
func2();
function func2() {
alert("func2");
}
$(document).ready(function () {
alert("ready");
});
}($));
运行结果:
(function($) {
var a = 1;
var b = 2;
var func1 = function () {
alert("func1");
}
func1();
func2();
function func2() {
alert("func2");
}
$(document).ready(function () {
alert("ready");
});
}($));
运行结果:
两种定义方式效果不同的本质原因:声明“被提前”
变量声明“被提前”
(function() {
// Output: undefined
console.log(declaredLater);
var declaredLater = "Now it's defined!";
// Output: "Now it's defined!"
console.log(declaredLater);
})();
这其实是 JavaScript 解析器搞的鬼,解析器将当前作用域内声明的所有变量和函数都会放到作用域的开始处,但是,只有变量的声明被提前到作用域的开始处了,而赋值操作被保留在原处。上述代码对于解析器来说其实是如下这个样子滴:
(function() {
var declaredLater; //声明被提前到作用域开始处了!
// Output: undefined
console.log(declaredLater);
declaredLater = "Now it's defined!"; //赋值操作还在原地!
// Output: "Now it's defined!"
console.log(declaredLater);
})();
变量和函数经过“被提前”之后,declaredLater 变量其实就被放在了调用函数的前面。根据 JavaScript 语法的定义,已声明而未被赋值的变量会被自动赋值为 undefined 。所以,第一次打印 declaredLater 变量的值就是 undefined,后面我们对 declaredLater 变量进行了赋值操作,所以,第二次再打印变量就会输出Now it’s defined!
再来看一个更有意思的栗子:
var name = "haha";
(function () {
// Output: "Original name was undefined"
console.log("Original name was " + name);
var name = "test";
// Outputs: "New name is test"
console.log("New name is " + name);
})();
我们本来希望在第一次打印 name 变量时能够输出全局范围内定义的 name 变量,然后再在函数中定义一个局部 name 变量覆盖全局变量,最后输出局部变量的值。可是第一次输出的结果和我们的预期完全不一致,原因就是我们定义的局部变量在其作用域内被“提前”了,也就是变成了如下形式:
var name = "haha";
(function () {
var name; //注意:name 变量被提前了!
// Outputs: "Original name was undefined"
console.log("Original name was " + name);
name = "test";
// Outputs: "New name is test"
console.log("New name is " + name);
})();
函数声明“被提前”
上面讲述的是变量声明,接下来我们回归正题,说说函数。
函数的“被提前”还要分两种情况:
第一种:函数声明;
第二种:函数作为值赋值给变量;
函数声明:
func2();//输出“func2”
function func2() {
alert("func2");
}
如上所示,JavaScript 解释器允许你在函数声明之前使用,也就是说,函数声明并不仅仅是函数名“被提前”了,整个函数的定义也“被提前”了!所以上述代码能够正确执行。
函数作为值赋值给变量:
func1();//浏览器报错,提示“func1 is not a function”
var func1 = function () {
alert("func1");
}
func1变量“被提前”了,但是他的赋值(也就是函数主体实现)并没有被提前,从这一点上来说,和前面我们所讲的变量“被提前”是完全一致的;并且,由于“被提前”的变量的默认值是 undefined ,所以报的错误属于“类型不匹配”,因为 undefined 不是函数,当然不能被调用,如下图:
(function($) {
var a = 1;
var b = 2;
alert(func1);
var func1 = function () {
alert("func1");
}
func1();
func2();
function func2() {
alert("func2");
}
$(document).ready(function () {
alert("ready");
});
}($));
总结:
1⃣️变量的声明被提前到作用域顶部,赋值保留在原地;
2⃣️函数声明整个“被提前”;
3⃣️函数作为值赋给变量时只有变量“被提前”了,函数没有“被提前”;