1. 函数声明和函数表达式有什么区别?
函数声明 (Function Declaration):
function functionName () {
//statement
}
函数表达式 (Function Expression):
var funExp = function() {
//statement
};
区别:
- 函数声明以 function 开头
- 函数表达式要在语句后加分号,而函数声明不用(即使加了分号,也就视为空语句。)
- 函数声明在 JS 解析时,会进行函数提升,在同一个作用域内,不管函数声明在哪里(即使在非常靠后的位置)创建,它都会提升到作用域顶部。
代码演示:
printName('Tim');
function printName(name) {
console.log(name);
}
即使函数声明在后面,也能调用函数!--> (函数提升)
printNameAgain('Tim');
var printNameAgain = function(name) {
console.log(name);
}
报错了!!!
因为,JS 引擎室这样处理代码的:
var printNameAgain;
printNameAgain('Tim');
var printNameAgain = function(name) {
console.log(name);
}
可见,只是将声明了函数变量,并没有赋值(相当于 undefined)。
所以,函数表达式只把函数变量声明提前,而函数语句部分并没有提前。
2. 什么是变量的声明前置?什么是函数的声明前置?
变量的声明前置:变量的声明被提前到代码头部。
console.log(a);
var a = 1;
可见,这并没有报错!
因为,JS引擎解析代码时,相当于:
var a;
console.log(a);
a = 1;
2. 函数声明前置:将函数声明语句提前到代码头部
printName('Tim');
function printName(name) {
console.log(name);
}
相当于:
function printName(name) {
console.log(name);
}
printName('Tim');
3. arguments 是什么?
在函数内部,你可以使用 arguments 对象获取到该函数的所有传入参数
argu("T","i","m");
function argu() {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}
4. 函数的重载怎样实现?
在静态语言里,确定函数是靠:函数名+参数列表。
相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载
JavaScript没有函数重载这个概念,只要函数名字相同(参数不同也无所谓),就会被认为是同一个函数。
为了实现函数重载(实现一个函数参数不同,功能相同的功能),需要利用 argument。
function sum() {
var sum = 0; //注意:这里需要设置 sum = 0
for (var i=0; i<arguments.length; i++) {
sum = sum + arguments[i];
}
return sum; //如果没有 return,输出结果是 undefined
}
console.log(sum(1,2,3));
5. 立即执行函数表达式是什么?有什么作用?
用 ()
将“函数声明”变为“表达式”并立即执行该表达式。
(function() {statement}) ();
或者
(function() {statement} ());
因为这是一个语句,而不是函数声明,所以不会发生“函数前置”。
作用是,包裹一段代码,让这段代码拥有自己的作用域。
6. 什么是函数的作用域链?
作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。
例子:
var a;
function fn() {
var b = 2;
// var c = 3;
function fn2() {
console.log(a);
console.log(c);
}
fn2();
var c = 3;
}
fn();
a = 100;
作用域链:寻找变量,只会“往上”!!!不会“往下”!!!
拓展:
JavaScript 开发进阶:理解 JavaScript 作用域和作用域链
补充:
1. return
有时候我们希望在函数执行后给我们一个反馈,就像表达式一样,给我们个结果,我们可以通过return来实现
这样我们就能拿到函数希望给我的反馈了,调用return后,函数立即中断并返回结果,即使后面还有语句也不再执行
function sayName(name) {
if(typeof name !== 'string') {
return ;
}
console.log("hello ", name);
}
sayName(12);
sayName("Tim");
如果传入参数不是字符串,这里的 return 会跳出函数。
注意区别:,break 和 continue。
break 和 continue,是跳出循环。return 是跳出函数。
return 只有在函数里面用!!!
2. 命名冲突
当在同一个作用域内定义了名字相同的变量和方法的话,无论其顺序如何,变量的赋值会覆盖方法的声明
当函数执行有命名冲突的时候,函数执行时载入顺序是:变量、函数、参数
function fn2(fn2) {
console.log(fn2);
var fn2 = 3;
console.log(fn2);
function fn2() {
console.log('fnnn2');
}
}
fn2(10);
实际上,会像下面执行语句
function fn2(fn2) {
var fn2;
function fn2(){
console.log('fnnn2');
}
console.log(fn2);
fn2 = 3;
console.log(fn2);
}
fn2(10);
再补充:
var abc = 100;
var abc;
另外,作用域这个概念只适用于函数,平常的变量声明和循环都没有作用域这个概念。
这时,abc 并不是100,100并没有被抹掉。
3. 作用域
function fn() {
console.log(i);
var i = 99;
function fn2() {
i = 100;
}
fn2();
console.log(i);
}
fn();
console.log(i);
function fn2(){} 里面的 i=100 ,因为没有声明 i ,所以从上一级作用域去找,(找到了 var i=99;),然后将 i 赋值为 100。这样,就改变了 fn 里面声明的这个 i 的值了。
代码:
1. 以下代码输出什么?为什么?
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments);
arguments[0] = 'valley';
console.log('name', name);
}
getInfo('hunger', 28, '男');
getInfo('hunger', 28);
getInfo('男');
2. 写一个函数,返回参数的平方和?
function sumOfSquares() {
var sum = 0;
for (var i=0; i<arguments.length; i++) {
sum = sum + arguments[i] * arguments[i];
}
return sum;
}
3. 如下代码的输出?为什么?
console.log(a);
var a = 1;
console.log(b);
4. 如下代码的输出?为什么?
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
sayAge
只是函数表达式,不会有“函数声明前置”,只有“变量声明前置”。
5. 如下代码的输出?为什么?
function fn(){}
var fn = 3;
console.log(fn);
6. 如下代码的输出?为什么?
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
fn(10);
实际代码执行如下:
function fn(fn2) {
var fn2;
function fn2() {
console.log('fnnn2');
}
console.log(fn2);
fn2 = 3;
console.log(fn2);
console.log(fn);
}
7. 如下代码的输出?为什么?
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
实际代码执行如下:
var fn;
function fn(fn) {
console.log(fn);
}
fn = 1;
console.log(fn(fn));
8. 如下代码的输出?为什么?
//作用域
console.log(j);
console.log(i);
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i);
console.log(j);
实际代码执行如下:
var i;
var j;
console.log(j);
console.log(i);
for (i=0; i<10; i++) {
j = 100;
}
console.log(i);
console.log(j);
9. 如下代码的输出?为什么?
fn();
var i = 10;
var fn = 20;
console.log(i);
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2(){
i = 100; //这里的 i 对于 fn 来说,是"全局"变量
}
}
10. 如下代码的输出?为什么?
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
这个“立即执行函数”是语句,而不是函数。而且它包裹的这段代码拥有自己的作用域!