任务17
问答
1.函数声明和函数表达式有什么区别?
函数声明:
函数表达式:
函数声明:函数调用可以发生在函数声明之前,例如下面这种情况下不会报错
函数表达式:函数调用只能在函数表达式后面,不能在函数表达式前面,例如下面这种情况就会报错
综上所述函数声明和函数表达式的区别是:
函数声明会产生函数的声明前置,因此可以把函数的调用写在函数声明之前;但函数表达式只能产生变量的声明前置,如果把调用放在函数表达式之前则会报错。
函数声明语句之后不加分号;函数表达式是一个语句结尾需加分号。
2.什么是变量的声明前置?什么是函数的声明前置?
-
变量声明前置:
程序在执行前,会提取程序中var声明的变量,但不提取赋值,叫变量声明前置,如下图所示
上面的代码等同于:
var age;
console.log(age);//此时age被声明但没有被赋值,所以结果为undefined;
age=10;
-
函数的声明前置:
javaScript解释器允许在函数声明之前调用函数,此时不仅仅是函数名被前置了,整个函数定义也被前置了,所以就可以直接调用函数,如下图所示
3.arguments 是什么?
在函数内部,可以使用arguments对象获取到该函数的所有传入参数,类似数组.
function printPersonInfo(name, age, sex) {
console.log(name);
console.log(age);
console.log(sex);
console.log(arguments);
}
printPersonInfo('liu', 18, 'nan');
输出的结果为:
4.函数的重载怎样实现?
在JS中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的。所以只要在函数体内做好处理就行。
function sum(a,b){
console.log(a+b);
}
function sum(a,b,c){
console.log(a+b+c);
}
sum(1,4,5);
最后的结果为10.
5.立即执行函数表达式是什么?有什么作用?
立即执行函数表达式:指的是不需要进行函数的调用立即执行,可以将写在函数体内的语句立即执行。
function name() {
console.log('lulu');
}
name();
//这种写法必须通过name()调用后才可以执行,function name(){}只是声明这个函数,并没有执行。
//我们可通过对整个函数加小括号来使函数声明变成函数表达式,从而立即执行:
有两种写法:
(function name() {
console.log('lulu');
})();
或
(function name() {
console.log('lulu');
}());
作用:让这段代码拥有自己的作用域,主要是这是一个表达式,所以不会前置,而且立即执行后,在其他地方也无法调用.
6.什么是函数的作用域链?
函数的作用域链指的是:js中的作用域在函数里形成,我们在执行代码过程中,函数里可以使用函数中定义的变量,如果函数里没声明这个变量,它会直接访问到这个函数作用域外的全局变量.
for(var i=0; i<10; i++){
var j=200;
}
//for循环无作用域,它没有局部作用域;
function k() {
console.log(i);//程序在执行前,会提取程序中var声明的变量,但不提取赋值,这就是变量的声明前置,结果为undefined.
var i=100;
function k2() {
i=99;//此时i没被声明,就从它的上一级去找被声明的变量i.
}
k2();
console.log(i);//从它的上一级找到了var i=100;因为函数k2中的i赋值为99,所以把99赋给我们再上一级中找到的的var i=100,也就是此时var i=99;所以最后输出的结果为99;
}
k();
console.log(i);//没加var相当于声明全局变量.for循环中的i的结果为10,所以此时的结果为10;
代码
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, '男');
//name:hunger
//age:28
//sex:男
//["hunger", 28, "男"]
//name:valley
getInfo('hunger', 28);
//name:hunger
//age:28
//sex:undefined
//["hunger", 28]
//name:valley
getInfo('男');
//name:男
//age:undefined
//sex:undefined
//["男"]
//name:valley
2.写一个函数,返回参数的平方和?
function sumOfSquares(){
var sum=0;
for(var i=0; i<arguments.length; i++){
sum+=arguments[i]*arguments[i];
}
return sum;
}
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
3.如下代码的输出?为什么?
console.log(a);//程序在执行前,会提取程序中var声明的变量,但不提取赋值,这就是变量的声明前置,结果为undefined.
var a = 1;
console.log(b);//报错b is not defined,变量b没有被声明所以报错;
4.如下代码的输出?为什么?
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello', name);//hello world 由于存在函数声明前置的现象,所以在此调用之前函数sayName已经声明完毕,可以正常调用。
}
var sayAge = function(age){
console.log(age);//报错:sayAge is not a function,因为sayAge是一个函数表达式,所以遵从的是变量的声明前置。但虽然声明前置,但赋值仍在此调用之后。所以sayAge被当成一个普通变量而非函数进行处理,因此这里作为函数进行调用时会报错。
};
5.如下代码的输出?为什么?
function fn(){}
var fn = 3;
console.log(fn);
等价于
var fn;//因为变量声明的优先级高于函数声明所以先变量声明再函数声明
function fn(){}
fn=3;//fn赋值为3;
console.log(fn);//结果为3,当在同一个作用域内定义了名字相同的变量和方法的话,无论其顺序如何,变量的赋值会覆盖方法的赋值;
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) {//在函数fn()的局部作用域下,函数fn2()和变量fn2都提升到该作用域的顶部.
var fn2;//声明变量
function fn2() {//声明函数
console.log('fnnn2');//由于函数fn2()与变量fn2重名,函数执行时载入的顺序是变量,函数,参数;函数覆盖变量,所以得到的是函数fn2()极其函数体内部的代码.
}
console.log(fn2);
fn2=3;
console.log(fn2);//fn2此时被赋值为3,输出结果为3
console.log(fn);//在函数的作用域中找不到fn,所以会在全局中找,所以会输出整个fn函数.
}
fn(10);
7.如下代码的输出?为什么?
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
上面的代码等价于
var fn;
function fn(fn){ // 声明名为fn的函数,并且有一个fn的参数
console.log(fn);
}
fn = 1; // fn不再是函数,变成1
console.log(fn(fn)); // 此时fn是1,即number类型。不再是函数,所以报错,fn is not a function
8.如下代码的输出?为什么?
//作用域
console.log(j);//undefined jS中只有函数才具有作用域,普通循环语句不会改变作用域,循环体内变量提升未被赋值;
console.log(i);//undefined同上
for(var i=0; i<10; i++){
var j = 100;
}//循环结束时候i=10;j=100;
console.log(i);//10 执行循环后i值变为10
console.log(j);//100 循环体里j的值是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() { //定义一个函数fn
var i;//函数fn中先声明i
function fn2() { //再定义函数fn2
i=100;
}
console.log(i);//因为此时fn2()函数没有被调用,所以i没有被赋值,i仅被声明但没有赋值,所以输出结果为undefined
i=99;//i赋值为99
fn2();//此处调用了fn2()函数,但是函数fn2中的i赋值为100
console.log(i);//此时输出结果为100
}
fn();
i=10;//此处i被重新赋值为10
fn=20;
console.log(i);//此时输出结果为10
10.如下代码的输出?为什么?
var say = 0;
(function say(n){//立即执行函数
console.log(n);//初始传递的参数是10,第一次输出的结果为n=10,满足n<3这个条件,此时执行say(n-1);依此类推
if(n<3) return;//当n=2时不满足条件,return跳出
say(n-1);
}( 10 ));
console.log(say);//全局作用域中say=0,输出0;
依次输出:10,9,8,7,6,5,4,3,2,0
因为函数为立即执行函数,变量只在函数作用域内生效,并不会影响到函数作用域外的变量.所以最后console.log(say)输出0.