问答:
函数声明和函数表达式有什么区别?
- 函数声明必须带有标示符(即函数名称),而函数表达式则可以省略这个标示符。
function 函数名称 (参数:可选){ 函数体 }
函数表达式:
function 函数名称(可选)(参数:可选){ 函数体 }
- 可以看出,如果不声明函数名称,它肯定是表达式,可如果声明了函数名称的话,如何判断是函数声明还是函数表达式呢?ECMAScript是通过上下文来区分的,如果function foo(){}是作为赋值表达式的一部分的话,那它就是一个函数表达式,如果function foo(){}被包含在一个函数体内,或者位于程序的最顶部的话,那它就是一个函数声明。还有一种函数表达式不太常见,就是被括号括住的(function foo(){}),他是表达式的原因是因为括号 ()是一个分组操作符,它的内部只能包含表达式。
什么是变量的声明前置?什么是函数的声明前置?
- JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行,这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升。例如:
var a=1;
而在实际工作的时候JavaScript是这样读取代码的,如下:
var a;先读取变量而不读取其赋值,也就是说在运行过程中第一时间知晓有这么个定义变量存在。
a = 1; 当读取完变量之后才会读取其赋值。
综上这就是传说中的变量声明前置。
- 和变量的声明会前置一样,函数声明同样会前置,如果我们使用函数表达式那么规则和变量一样.例如:
console.log(fn); //undefined javascript中运行代码是一行一行逐一执行的,因此在这里就变量中读取到 (var a;)这里一样,console.log中需要执行的语句存在但是并没有定义,因此才会出现undefined。
var fn = function(){}
如果我们使用函数声明的方式,那么即使函数写在最后也可以在前面语句调用,前提是函数声明部分已经被下载到本地,例如:
fn(); // "1"
执行函数fn;
function fn(){
console.log('1');
}
arguments 是什么?
在JavaScript中,arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性。同时arguments对象的长度是由实参个数而不是形参个数决定的。形参是函数内部重新开辟内存空间存储的变量,但是其与arguments对象内存空间并不重叠。对于arguments和值都存在的情况下,两者值是同步的,但是针对其中一个无值的情况下,对于此无值的情形值不会得以同步。再次利用函数的arguments属性可以实现函数的重载。
函数的重载怎样实现 ?
- 在这里首先我们要明确函数重载的定义:重载是很多面向对象语言实现多态的手段之一,在静态语言中确定一个函数的手段是靠方法签名——函数名+参数列表,也就是说相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载。
- 在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);这里两个参数在执行的时候会对参数进行判定,到底属于name age sex中的那一个;满足其中的两个,那么另一个就不会执行。
printPeopleInfo('Byron', 26, 'male');
立即执行函数表达式是什么?有什么作用?
- 先创建了一个匿名函数,然后不传入参数调用它,这就变成了立即执行函数。例如:
(function(){})();
其实他的实际结构就是:
(函数定义表达式)函数调用表达式
再看一个例子:
function fn(){
console.log(1);
}
这里定义了一个函数fn,也就是说fn这个函数就是 前面function fn(){}; 这个整体,那么他的直接调用就是后边:(function fn(){
console.log(1);
})();当然这里我们没有加入实参。
fn();调用此函数
什么是函数的作用域链?
在大多数语言中都是用花括号{}来形成一个作用域,但是在JavaScript中{}并没有带来块作用域,JavaScript的作用域是靠函数来形成的,也就是说一个函数内定义的变量函数外不可以访问,从而就形成了一个特有的作用区域,俗称作用域。看个例子:
function fn(){
var a =1;
if(a > 2){
var b = 3;
}
console.log(b);
}
fn(); // undefined
console.log(a); // "ReferenceError: a is not defined 报错a没有被定义,个人觉得函数中并没有执行a,因此在函数外执行console.log(a)就没法执行,因为获取不到a的信息,也就是没有在函数的作用域中。
代码:
1
输出内容为:
function getInfo(name, age, sex){
console.log('name:',name); 1
console.log('age:', age); 2
console.log('sex:', sex); 3
console.log(arguments); 4
arguments[0] = 'valley'; 5这里重新定义name为valley
console.log('name', name); 6
}
getInfo('hunger', 28, '男');
输出//name: hunger 1 js中的代码逐行执行,因此对应上边的函数依次解析参数。
age: 28 2
sex: 男 3
["hunger", 28, "男"] 4 arguments数组
name valley 6
getInfo('hunger', 28);
输出://name: hunger 1
age: 28 2
sex: undefined 3
["hunger", 28] 4 arguments数组
name valley 6
getInfo('男');
输出:// name: 男 1
age: undefined 2 无参数 所以undefined
sex: undefined 3
["男"] 4
name valley 6
2、写一个函数,返回参数的平方和?如 (难度**)
function sumOfSquares(){ }
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
答案如下:
function sumOfSquares(){
var sum =0; 定义一个变量
for(var i=0;i<arguments.length;i++){
sum += arguments[i]*arguments[i]
}利用函数的arguments属性实现重载
console.log(sum); 打印出sum的值
}
sumOfSquares(1,3); 输出10
sumOfSquares(2,3,4); 输出29
3、如下代码的输出?为什么 ?
console.log(a); 输出undefined 变量前置
var a = 1;
console.log(b); 报错找不到b
4、如下代码的输出?为什么 ?
sayName('world'); // hello world
sayAge(10);// 报错 sayAge不是一个函数
function sayName(name){
console.log('hello ', name); }
var sayAge = function(age){ // 相当于是定义一个变量,因此并不是函数,所以不能执行。
console.log(age);
};
5、如下代码的输出?为什么?
function fn(){} //这里fn是一个函数
var fn = 3; // 此处对fn进行了重新定义,覆盖了前者。
console.log(fn);因此此处应该显示3,但是浏览器中执行的时候是报错。报错内容为:标识符的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){
function fn2(){
console.log('fnnn2');
}
var fn2;
console.log(fn2); 显示fnnn2
fn2 = 3;//此处重新定义fn2,因此下边的执行会显示3
console.log(fn2); //显示3
console.log(fn); //显示10
}
fn(10);
7、如下代码的输出?为什么 ?
var fn = 1; //定义fn为1
function fn(fn){ console.log(fn); } //这是一个函数声明,无法自动执行
console.log(fn(fn)); //因此在这里会报错,报错原因是由于前边对变量fn进行了定义,而且权重高于函数,如果后边是console.log(fn)则为1.
8、如下代码的输出?为什么?
console.log(j); undefined
console.log(i); undefined
for(var i=0; i<10; i++){ var j = 100; }
console.log(i); 10
console.log(j); 100
作用域存在于函数中的时候才存在局部作用域,当没有函数的时候,除了特殊定义,其余皆可视为全局变量,因此在该题中 第一行和第二行代码的执行结果为undefined,这也正好体现在js中代码是逐行执行的,当执行到for循环的时候,便将i和j视为全局变量,根据条件对i的限制有0-9共计执行10次,因此console.log(i)为10,与此同时变量j被定义为100,因此执行console.log(j)为100.
9、如下代码的输出?为什么?
fn(); // 这里是指执行函数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; } }
根据函数声明提前,上题中的代码可以写成:
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2(){ i = 100; }
代码逐行执行,后边覆盖前面,因此在这个局部作用域中i的最终值是100,所以该大函数fn的执行结果就是100
}
fn(); 显示100
var i = 10; 全局变量重新定义i
var fn = 20;
console.log(i); 因此此处显示为10
故而输出结果为:100 10
10、如下代码的输出?为什么?
var say = 0;
(function say(n){
console.log(n);打印出n
if(n<3) 条件判断,当n小于3的时候返回结果,后边就不执行。
return;
say(n-1);执行n-1 }( 10 ) );、
因此此处的执行结果为10 9 8 7 6 5 4 3 2 但是为什么没有1呢?
因为当n=3的时候 依次执行console.log(3) 显示3 同时后边执行say(3-1); 显示2 , 当n=2的时候 满足了后边的if条件,就执行return,所以没有1.
console.log(say); 最后在执行这个 因为前面定义了变量say=0,所以此处显示0.
首先声明一点,上题中
(function say(n){
console.log(n);
if(n<3)
return;
say(n-1); }( 10 ) );是一个立即执行函数相当于();只不过括号里边是一个函数声明而已,但是后边的10是实参,也就是N的初始值为10.
综上 执行结果为10 9 8 7 6 5 4 3 2 0