## 函数
2016-09-19 本文已影响0人
成熟稳重的李先生
1.函数声明和函数表达式有什么区别
- 声明方式不同:
- 函数声明:function lol(
参数(可选)
){函数体};函数声明会前置
- 函数表达式:var a = function函数名称
可选
(参数(可选)
){函数体};还有一种常见函数表达式:(function () { })()
,表示立即执行,常用于匿名函数的调用。函数表达式不会前置
- 函数声明:function lol(
2.什么是变量的声明前置?什么是函数的声明前置
- 变量的声明前置:
console.log(a)//输出undefined,虽然此处a尚未出现,但声明已经前置,即var a
,赋值的动作并不会前置
var a = 1; - 函数的声明前置:js解析器会首先解析函数声明,确保所有代码执行之前已经全部被解析,无论在哪里调用此函数都会执行
a()
function a(){
console.log (ok
) }//这是函数声明,会被单独前置
和下面代码等价
function fuc(){
console.log (ok
) }
fuc();
3.arguments 是什么 ?
- arguments是一个包含函数运行时的所有参数的对象,
只有在函数开始时才可用,不能被显式创建
,可通过arguments[i]依次对参数进行访问和修改,与数组元素的方式相同,但并不是一个数组。
4.函数的重载怎样实现?
- 在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的,可通过length属性提供了一种机制,判断定义时和调用时参数的差异,实现面向对象编程的”方法重载“(overload)。 (函数名.length=形参长度),根据判断语句,然后传递不同数量的参数,来实现一种类似重载的效果。
但声明函数的时候就不能将形参的个数具现化,因为这样的话,传入的实参个数如果与形参不等,便会报错
。
5.立即执行函数表达式是什么?有什么作用
- 立即执行函数表达式本质上是一个表达式,可以让你的函数在定义后立即被执行
- 书写方式:
(function fx(){
console.log('name');
}()); - 作用:隔离作用域,立即执行函数定义的所有变量都会成为函数的局部变量,所以不用担心这些临时变量会污染全局空间
- 立即执行函数可以让你将独立的功能封装在自包含模块中,而不会影响其他模块。
6. 什么是函数的作用域链
- 任何执行上下文时刻的作用域, 都是由作用域链来实现.
- 当一个函数被声明的时候,会给这个函数添加一个scope属性.
- 在一个函数对象被调用的时候,会创建一个活动对象(也就是一个对象), 然后对于每一个函数的形参,都命名为该活动对象的命名属性, 然后将这个活动对象做为此时的作用域链(scope chain)最前端, 并将这个函数对象的[[scope]]加入到scope chain中.
- 作用域链的原理和原型链很类似,如果这个变量在自己的作用域中没有,那么它会寻找父级的,直到最顶层。
代码题:
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,'男'](arguments会输出所有传入的实参,这是个类数组对象)
//给第一位重新赋值‘valley’ ,输出name :valley
getInfo('hunger', 28);
//name:hunger
//age:28
//undefined
//[‘hunger’,28]
//给第一位重新赋值‘valley’ ,输出name valley
getInfo('男');
//name:男
//undefined
//undefined
//['男']
//给第一位重新赋值‘valley’ ,输出name valley
2.写一个函数,返回参数的平方和?
function sumOfSquares(){
var result = 0;
for(var i = 0;i < arguments.length; i++){
var sum = arguments[i]*arguments[i];
result += sum;
};
return result;
}
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
3.如下代码的输出?
console.log(a); //undefined,`声明前置`,但值没有前置,此处只是有a的声明,但未初始化。
var a = 1; //此处为a赋值,约等于`a=1`,没有输出。
console.log(b);//b is not defined,因为未对b做出声明。
4.如下代码的输出?为什么
sayName('world');//输出“`hello world`”,因为如果用函数声明的方式定义的函数,卸载哪里都会被调用。
sayAge(10); //报错,sayAge是用函数表达式定义的,变量提升,即此处sayAge只是一个变量,而sayAge(10)是以函数调用的形式出现,因此报错。
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
5.如下代码的输出?为什么
function fn(){
}
var fn = 3;
console.log(fn);//输出3,虽然变量与函数都会被提升,但名为`fn`的函数首先会覆盖掉名为`fn`的变量,但紧接着,fn被赋值为3,所以输出3。
6.如下代码的输出?为什么
function fn(fn2){
console.log(fn2);//function fn2(){console.log('fnnn2');} 因为函数声明和变量声明均会被前置, 但同名函数会覆盖变量,因此,此时的`fn2`是函数。
var fn2 = 3; //接着fn2被赋值为3.
console.log(fn2); //3 ,上一步已将fn2变为3。
console.log(fn); //输出整个fn函数 因为fn定义为函数 在函数内部是有效的
function fn2(){
console.log('fnnn2'); // 原因1:不会输出 因为fn2 已经被覆盖。原因二: 哪怕是函数,也没有调用,因此不会执行。
}
}
fn(10);
7.如下代码的输出
var fn = 1;
function fn(fn){
console.log(fn);
} //此时`var fn `已经形同虚设,被同名函数所覆盖。但紧接着,`fn = 1`,`fn`又称为一个值暂时未1的变量。
console.log(fn(fn));//上一步后,fn已经为1,不是函数,因此,以函数调用的方式`fn()`访问会报错。
8.以下代码如何输出?
console.log(j);//undefined,声明前置
console.log(i); //undefined,声明前置
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i);//10,i>=10才会跳出循环。
console.log(j);//100,j和此处打印语句均在一个作用域内。
9.以下代码如何输出?
fn(); 变量、函数提升后: var i;
var i = 10; var fn;
var fn = 20; function fn(){
console.log(i); var i;
function fn(){ function fn2(){
console.log(i); i = 100;
var i = 99; };
fn2(); console.log(i);//i未赋值。输出underfined。
console.log(i); i = 99;//i赋值99
function fn2(){ fn2();//执行fn2()。i赋值为100.
i = 100; console.log(i);//100,上一步得到结果。
} }
} fn();//执行fn()。
i = 10;//i赋值10.
fn = 20;
console.log(i);//输出10.
10.如下代码的输出?为什么
var say = 0;
(function say(n){
console.log(n); //立即执行函数,尾部给n赋值10,然后执行下边if语句,每过一次,就会输出一个值,直到n=3,还执行一次,因此,输出10.9.8.7.......2
if(n<3) return;
say(n-1);//递减操作
}( 10 ));
console.log(say);//外部不会受到内部函数影响,因此,输出0