1.函数声明和函数表达式有什么区别 (*)
函数声明
function printName(){
console.log('1');
}
printName();
函数表达式
var printName = function(){
console.log('1');
};
printName();
函数声明:函数调用可以发生在函数声明之前,例如下面这种情况下不会报错
printName();//输出console.log('1')
function printName(){
console.log('1');
}
//正常,因为‘提升’了函数声明,函数调用可在函数声明之前
函数表达式:函数调用只能在函数表达式后面,不能再函数表达式前面,例如
printName();//浏览器提示Uncaught TypeError: printName is not a function(…)
var printName = function(){
console.log('1');
};
//报错,变量printName还未保存对函数的引用,函数调用必须在函数表达式之后
浏览器提示Uncaught TypeError: printName is not a function(…).原因:类似变量提升,函数作为一个变量赋值给printName,等价于
var printName;//此时printName为undefined
printName();
printName = function(){
console.log('1');
};
所以函数声明和函数表达式不同之处在于,
一、Javascript引擎在解析javascript代码时会‘函数声明提升’(Function declaration Hoisting)当前执行环境(作用域)上的函数声明,而函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式,
二、函数表达式后面可以加括号立即调用该函数,函数声明不可以,只能以fnName()形式调用
2.什么是变量的声明前置?什么是函数的声明前置 (**)
变量的声明前置
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升
我们写了一个赋值语句
var a = 2;
实际上执行过程是解释器在未执行的时候先解析出变量声明,然后给他初始值 undefined ,然后才逐句执行程序
var a;
a = 2;
这样看起来没什么区别,但是在多语句的情况下会有差别,我们知道一个变量如果不存在我们就使用会报错
console.log(xxx); // Uncaught ReferenceError: xxx is not defined
我们在使用一个变量之前必须声明变量,但是由于变量提升,我们如果声明了变量,即使在声明语句前使用也是可以的,只不过其值是初始值 undefined
var xxx = 2;```
函数的声明前置
>和变量的声明会前置一样,函数声明同样会前置,如果我们使用函数表达式那么规则和变量一样
console.log(fn); //undefined
var fn = function(){}
#### 3.arguments 是什么 (*)
>在函数内部,可以使用 arguments 对象获取到该函数的所有传入参数
function printPersonInfo(name, age, sex){
console.log('name : '+name);
console.log('age : '+age);
console.log('sex : ' +sex);
console.log(arguments);
}
printPersonInfo('liu', 21, 'boy')
name : liu
age : 22
sex : boy
["liu", 22, "boy"]
printPersonInfo('liu', 21, 'boy')
name : liu
age : boy
sex : undefined
["liu", "boy"]
#### 4.函数的重载怎样实现 (**)
>重载是很多面向对象语言实现多态的手段之一,在静态语言中确定一个函数的手段是靠方法签名——函数名+参数列表,也就是说相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载
>在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的,这是不是意味着JavaScript不能通过重载功能实现一个函数,参数不同功能不同呢?
在JavaScript中,函数调用没必要把所有参数都传入,只要你函数体内做好处理就行,但前提是传的参数永远被当做前几个
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);
printPeopleInfo('Byron', 26, 'male');
#### 5.立即执行函数表达式是什么?有什么作用 (***)
立即执行函数表达式```( function(){…} )()和( function (){…} () )```
var fnName=function(){
alert('Hello World');
}();
//函数表达式后面加括号,当javascript引擎解析到此处时能立即调用函数
function fnName(){
alert('Hello World');
}();
//不会报错,但是javascript引擎只解析函数声明,忽略后面的括号,函数声明不会被调用
function(){
console.log('Hello World');
}();
//语法错误,虽然匿名函数属于函数表达式,但是未进行赋值操作,
//所以javascript引擎将开头的function关键字当做函数声明,报错:要求需要一个函数名
>在理解了一些函数基本概念后,回头看看( function(){…} )()和( function (){…} () )这两种立即执行函数的写法,最初我以为是一个括号包裹匿名函数,并后面加个括号立即调用函数,当时不知道为什么要加括号,后来明白,要在函数体后面加括号就能立即调用,则这个函数必须是函数表达式,不能是函数声明
(function(a){
console.log(a); //firebug输出123,使用()运算符
})(123);
(function(a){
console.log(a); //firebug输出1234,使用()运算符
}(1234));
!function(a){
console.log(a); //firebug输出12345,使用!运算符
}(12345);
+function(a){
console.log(a); //firebug输出123456,使用+运算符
}(123456);
-function(a){
console.log(a); //firebug输出1234567,使用-运算符
}(1234567);
var fn=function(a){
console.log(a); //firebug输出12345678,使用=运算符
}(12345678)
>可以看到输出结果,在function前面加!、+、 -甚至是逗号等到都可以起到函数定义后立即执行的效果,而()、!、+、-、=等运算符,都将函数声明转换成函数表达式,消除了javascript引擎识别函数表达式和函数声明的歧义,告诉javascript引擎这是一个函数表达式,不是函数声明,可以在后面加括号,并立即执行函数的代码。
>加括号是最安全的做法,因为!、+、-等运算符还会和函数的返回值进行运算,有时造成不必要的麻烦。
>不过这样的写法有什么用呢?
>javascript中没用私有作用域的概念,如果在多人开发的项目上,你在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉,根据javascript函数作用域链的特性,可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。
>JQuery使用的就是这种方法,将JQuery代码包裹在( function (window,undefined){…jquery代码…} (window)中,在全局作用域中调用JQuery代码时,可以达到保护JQuery内部变量的作用。
参考http://dengo.org/archives/1004
#### 6.什么是函数的作用域链 (****)
>作用域是针对变量的,比如我们创建了一个函数,函数里面又包含了一个函数,那么现在就有三个作用域
全局作用域==>函数1作用域==>函数2作用域
作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。
如:
var a = 1;
function b(){
var a = 2;
function c(){
var a = 3;
console.log(a);
}
c();
}
b();
最后打印出来的是3,因为执行函数c()的时候它在自己的范围内找到了变量a所以就不会越上继续查找,如果在函数c()中没有找到则会继续向上找,一直会找到全局变量a,这个查找的过程就叫作用域链。
>不知道你有没有疑问,函数c为什么可以在函数b中查找变量a,因为函数c是在函数b中创建的,也就是说函数c的作用域包括了函数b的作用域
,当然也包括了全局作用域,但是函数b不能向函数c中查找变量,因为
作用域只会向上查找
参考:
http://www.cnblogs.com/pssp/p/5204324.html
http://www.cnblogs.com/dolphinX/p/3280876.html
### 代码
##### 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('男');
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); //undefined
var a = 1;
console.log(b); //报错Uncaught ReferenceError: b is not defined(…)
a输出undefined是因为变量提升,b没有定义,类似如下代码
var a;
console.log(a); //undefined
a = 1;
console.log(b);
##### 4.如下代码的输出?为什么 (难度*)
sayName('world'); //输出 'hello ', 'world'
sayAge(10); //报错 浏览器提示Uncaught TypeError: sayAge is not a function(…)
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
Javascript引擎在解析javascript代码时会‘函数声明提升’(Function declaration Hoisting)当前执行环境(作用域)上的函数声明,而函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式,
##### 5.如下代码的输出?为什么 (难度**)
function fn(){}
var fn = 3;
console.log(fn);//输出3
当在同一个作用域内定义了名字相同的变量和方法的话,无论其顺序如何,变量的赋值会覆盖方法的赋值
##### 6.如下代码的输出?为什么 (难度***)
function fn(fn2){
console.log(fn2);//1
var fn2 = 3;
console.log(fn2);//2
console.log(fn);//3
function fn2(){
console.log('fnnn2');
}//4
}
fn(10);
输出
//1
function fn2(){
console.log('fnnn2');
}
//2
3
//3
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
在函数体内```console.log(fn2);//1```与
function fn2(){
console.log('fnnn2');
}//4
在同一作用于内,在解析javascript代码时会‘函数声明提升’(Function declaration Hoisting)当前执行环境(作用域)上的函数声明,因此
console.log(fn2);//1
输出
function fn2(){
console.log('fnnn2');
}
然后```var fn2=3;```覆盖函数声明,下面```console.log(fn2);```
输出3
console.log(fn);
输出函数fn自身
##### 7.如下代码的输出?为什么 (难度***)
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
输出:报错fn不是一个函数
首先,这种情况
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn);//输出1;原因:同一个作用域内定义了名字相同的变量和方法的话,无论其顺序如何,变量的赋值会覆盖方法的赋值
如果改为
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn());//输出:报错fn不是一个函数
所以console.log(fn());无论传不传参数都会报错
##### 8..如下代码的输出?为什么 (难度**)
//作用域
console.log(j);
console.log(i);
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i);
console.log(j);
输出结果
undefined
undefined
10
100
原因:
//作用域
console.log(j);//循环体内变量提升undefined
console.log(i);//循环体内变量提升undefined
for(var i=0; i<10; i++){
var j = 100;
}//循环结束i=10;j=100;
console.log(i);//10
console.log(j);//100
for(var i=0; i<10; i++){
var j = 100;
}
for循环相当于
var i=0;
if(0<10){ var j = 100;}
i+=1;//i=1
if(1<10){ var j = 100;}
i+=1;//i=2
if(2<10){ var j = 100;}
i+=1;//i=3
.......................
if(9<10){ var j = 100;}
i+=1;//i=10
if(10<10){ var j = 100;}
理解js语句是一行一行执行的就很好理解
##### 9.如下代码的输出?为什么 (难度****)
fn();//1.
var i = 10;
var fn = 20;
console.log(i);//2.
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2(){
i = 100;
}
}
预想输出
>fn()//1.
undefined
100
99
console.log(i);//2
10
实际输出结果
fn()//1.输出
undefined
100
console.log(i);//2.输出
10
分析:
function fn(){
console.log(i);//变量提升i为undefined
var i = 99;
fn2();//函数执行但不返回结果
console.log(i);//执行fn2();后i值变为100
function fn2(){
i = 100;
}
console.log(i);//2.输出
10//作用域原因,函数内的i不影响外部的i
##### 10.如下代码的输出?为什么 (难度*****)
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
自执行函数输出结果为
10 9 8 7 6 5 4 3 2
当n=2时跳出自执行
console.log(say);输出结果为0
自己没做对,不知道自执行函数运行机制,根据结果分析出来的,自执行函数只运行自己不影响外部任何变量,运行完结束返回结果,拥有自己独立的作用域,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量
例如
var say = 0;
var i=4;
(function say(n){
console.log(n+i);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
输出结果为14 13 12 11 10 9 8 7 6 0
而
var say = 0;
(function say(n){
var i=4;
console.log(n+i);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
console.log(i);
输出结果为
14 13 12 11 10 9 8 7 6//自执行函数输出结果console.log(n+i);
0// console.log(say);输出结果
Uncaught ReferenceError: i is not defined// console.log(i);输出结果
本文版权属 饥人谷_刘晓东 所有,转载务必注明出处