JS函数

2016-12-26  本文已影响0人  周花花啊

概念

1、函数声明和函数表达式有什么区别?

ECMAScript规定了三种声明函数方式:

var printName = new Function("console.log('Byron');");```
这种创建对象的方式按理来说应该是最正规的方式,但是因为性能原因极少使用
 - 函数声明
**就像var声明一个变量一样,function声明一个函数**

function functionName(){
statement;
}```
使用function关键字可以声明一个函数,看个例子

function printName(){
    console.log('Byron');
}
printName();```
 - 函数表达式
函数表达式不是以function开始,而是像声明一个变量一样

var printName = function(){
console.log('Byron');
};```

函数声明和函数表达式比较容易混淆,它们的区别主要有:

2、什么是变量的声明前置?什么是函数的声明前置?

最后总结一下:

3、arguments是什么?

4、函数的重载是怎样实现?

5、立即执行函数表达式(IIFE)是什么?有什么作用?

//在最前最后加括号
(function atOnce(){
    console.log('abc');
}());
//在function外面加括号
(function atOnce(){
    console.log('abc');
})();

6、什么是函数的作用域链

console.log(j); //undefined
console.log(i); //undefined
for(var i=0;i<10;i++){   //不是函数,是控制语句,所以这里的i和j是全局作用域。 
    var j = 100;
}
console.log(i); //10
console.log(j); //100

最外层函数和在最外层函数外面定义的变量拥有全局作用域,只有函数才有局部作用域。

for(var i=0;i<10;i++){ 
    var j = 100;
}
function fn(){ 
var i = 99; 
console.log(i); //只有函数才有局部的作用域,先在内部找(找不到再一层层往上面的作用域找),所以输出为99。
}
fn(); // 99
console.log(i); //10,只能取到for里面的10.但是如果上面函数里面的var i = 99;改成i = 99;打印结果为99,所以如果不加var就是全局变量。

当然也不是说不带var的就是全局作用域,再来看个例子。

for(var i=0;i<10;i++){ 
    var j = 100;
}
function fn2(){ 
    console.log(i); 
    var i = 99; //如果去掉var,结果应该是10,100,100
    function fn2(){ 
        i = 100; //没有加var,可以认为这个函数里面变量的作用域在父亲的范围内
    }
    fn2(); //再执行这个,也就是内部的fn2(),得到100
    console.log(i);
}
fn2(); //先执行这个调用,也就是大函数fn2(),得到undefined
console.log(i); //最后执行。这里是全局变量的i,为10

总的来说

JavaScript 开发进阶:理解 JavaScript 作用域和作用域链

代码

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('男');

输出结果分别是:

name: hunger
age: 28
sex: 男
['hunger', 28,'男']
name valley
name: hunger
age: 28
sex: undefined
['hunger', 28]
name valley
name: 男
age: undefined
sex: undefined
['男']
name valley
控制台结果

2、写一个函数,返回参数的平方和

function sumOfSquares(){
    //首先这里肯定能想到用arguments
    var sumOfSquares=0;
    for(var i=0;i<arguments.length;i++){
        sumOfSquares=sumOfSquares+arguments[i]*arguments[i]
    }
    return sumOfSquares;  //最后将结果返回给调用函数语句
} 
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
控制台结果

3、以下代码的输出?为什么

console.log(a); 
var a = 1; 
console.log(b);

这题代码考察的就是变量声明的提升,相当于以下代码:

var a;
console.log(a);  //输出undefined
a=1;
console.log(b);  //报错
控制台结果

4、如下代码的输出?为什么

sayName('world');   //输出hello world
sayAge(10);   //输出错误,sayAge is not a function
function sayName(name){ 
    console.log('hello ', name); 
} 
var sayAge = function(age){
    console.log(age); 
};

这题涉及到函数的声明前置,函数声明和函数表达式的区别,相当于如下代码:

//一般提升的变量放在函数前面,如果变量名和函数名同则函数覆盖变量
var sayAge;  //对于函数表达式只是函数变量的声明会提前
function sayName(name){ 
    console.log('hello ', name); 
}  //对于函数声明,整个都会前置
sayName('world'); 
sayAge(10); 
sayAge = function(age){
    console.log(age); 
};
控制台输出结果

5、如下代码的输出?为什么

function fn(){
} 
var fn = 3; 
console.log(fn);  //输出3

这里有两个规则:

所以转换后的代码为:

var fn;  //变量的声明前置,此时fn为普通的变量
function fn(){
}  //函数声明覆盖变量的声明,此时fn又变为一个函数了
fn = 3;  //此时fn变为3,也就是变量的赋值覆盖了方法的声明
console.log(fn);  //输出结果3

可是结果,,什么鬼。。。。


什么鬼

原因是控制台并没有一个统一的标准,控制台也有bug,所以我们用html运行才是最可靠的:


用html运行

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;  //找到作用域下的变量声明,放在最前面,此时fn2为普通变量
    function fn2(){
       console.log('fnnn2');
    }   //函数声明前置,放在变量声明的后面,此时fn2变为一个函数
    console.log(fn2);  //所以这里输出函数
    fn2 = 3;  //fn2被赋值为3,覆盖前面方法的声明
    console.log(fn2);  //输出3
    console.log(fn);   //打印出函数fn
}
fn(10);  //调用函数fn()
控制台结果

7、如下代码的输出?为什么

var fn = 1;
function fn(fn){ 
    console.log(fn);
}
console.log(fn(fn)); 

相当于如下代码

var fn;  //变量声明在前面,位置不变,此时fn为普通的未初始化的变量
function fn(fn){
    console.log(fn);
}  //现在fn变成了一个函数
fn = 1;  //变量的赋值会覆盖方法的声明,所以变量赋值移动到这里,fn变成数字1
console.log( fn(fn) );  //这里是调用函数fn,但是此时fn是数字1,不能当作函数来调用,所以会报错
html输出结果

8、如下代码的输出?为什么

 //作用域
console.log(j); 
console.log(i); 
for(var i=0; i<10; i++){ 
    var j = 100; 
}   //这里面的变量都是全局变量,所以我们要将变量声明提前
console.log(i); 
console.log(j);

因为for是控制语句,不是函数,所以它里面的变量i和j都是全局的,所以它相当于如下的代码:

var i;  //变量提升,将变量声明前置到代码头部
var j;
console.log(j);  //所以这里输出的是undefined,也就是表示j有声明但是未被初始化
console.log(i);  //同上
for(i=0;i<10;i++){
    j = 100;
}
console.log(i);  //上面的for循环执行完后i变为10,所以打印出10
console.log(j);  //上面的for循环结束后输出j为100,所以打印出100
控制台结果

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; 
    } 
}

我们来排序,替换成下面的等价代码:

var i;  // 变量的声明放代码顶部,i为一未初始化的变量
var fn;  // 变量的声明放代码顶部,fn为一未初始化的变量
function fn(){ 
    var i;  //同样变量的声明放代码顶部,i为一未初始化的变量
    function fn2(){ 
        i = 100;   //这个i由于未声明,所以在上一级作用域下找,会改变上一级作用域下i的值
    }   //函数声明整体提前,放在变量声明的后面,此时fn2变为一个函数了
    console.log(i);   //undefined,因为fn2还未被执行,所以i还是未赋值状态
    i = 99;   //i被赋值为99了
    fn2();   //现在执行函数fn2,将fn作用域下的i 赋值为100了
    console.log(i);   // 所以这里打印出100
}  //把函数声明整体提前,放在变量声明的后面,此时fn变为一个函数了
fn();  //它的位置不变,依旧放在变量赋值的前面,调用函数fn
i = 10;  //变量赋值的位置,这里给i赋值10
fn = 20;  //变量赋值的位置,到这里fn就不是函数了,而是一个数字
console.log(i);   //打印全局作用域下的i,为10
输出结果
要注意的关键点

10、如下代码的输出?为什么

var say = 0; 
(function say(n){ 
    console.log(n); 
    if(n<3) return; 
    say(n-1); 
}( 10 )); 
console.log(say);

function外部加了一个括号,所以为一个立即执行函数,里面又嵌套了say(n-1),所以为递归函数。把函数最后面的参数10传递进去,所以一开始打印的就是10,依次递减直到等n小于3,也就是当n等于2的时候退出整个循环。然后再执行最后一句,打印出say的值,注意这里并不是函数调用哦,后面没有括号。


输出结果

(完)

上一篇下一篇

猜你喜欢

热点阅读