1 函数声明和函数表达式有什么区别?
函数声明:定义一个具有指定参数的函数,函数声明最重要的特征就是函数声明提升,意思是在执行代码之前就会读取函数声明.
sayHi();
function sayHi(){
alert("hi world");
}
//不会报错,因为函数声明在sayHi()在函数sayHi()之前已经读取
name :函数名
param:要传递给函数的参数的名称。不同引擎中的最大参数数量不同。一个函数最多有255个参数
statements:包含函数体的语句。
描述:
一个被函数声明创建的函数是一个 Function 对象,具有 Function 对象的所有属性、方法和行为。
参考
-
函数表达式
用函数表达式定义的函数在使用之前必须先赋值
sayHi();
var sayHi = function() {
alert("hi wrold");
}
//报错,函数sayHi()调用之前并未赋值
-
区别
1 函数表达式定义的函数在使用之前必须先赋值,而函数声明不必.
2 函数表达式与函数声明的最主要区别是函数名称(function name),在函数表达式中可忽略它,从而创建匿名函数.
2 什么是变量的声明前置?什么是函数的声明前置?
变量声明前置就是在一个作用域块中,所有的变量都被放在块的开始出声明
1 var a = 1;
2 function main() {
3 console.log(a);//1
4 }
5 main();//输出1
1 var a = 1;
2 function main() {
3 console.log(a);
4 var a = 2;
5 }
6 main()//输出undefined
为什么输出undefined,因为脚本在执行的时候会自动将变量声明前置
函数的声明前置:在一个作用域下,同var 声明的变量一样,function 声明的函数也会前置。函数的声明前置优先级高于变量的声明前置。
var a = 3;
console.log(a); //3
sayHello();
function sayHello(){
console.log('hello');//hello
}
执行时语句顺序如下:
var a
function sayHello(){}
console.log(a);//undefined
a=3
console.log(a); //3
sayHello();
3 arguments 是什么?
- arguments对象是所有函数中可用的局部变量,你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数的条目,第一个条目的索引从0开始。例如,如果一个函数传递了三个参数,你可以参考它们如下:
arguments[0]
arguments[1]
arguments[2]
参数也可以被设置:
arguments[1] = 'new value';
arguments对象不是一个 Array它类似于数组
4 函数的"重载"怎样实现?
- Javascript中,先定义的函数,可以被后定义的函数覆盖。因此Javascript不支持函数的重载。比如下面的例子:
<script type="text/javascript">
function p(a, b, c) {
alert(a+b+c);
}
function p(a, b) {
alert(a+b);
}
p(1,2,3);//alert 3;
</script>
虽然有函数p(a, b, c),但是由于语言的特性,该函数被后面的p(a,b)所覆盖
- 但是利用js的arguments,可以实现JavaScript的重载。
function showMessage(){
if(arguments.length==1){
console.log(arguments[0]);
}else if( arguments.length==2){
console.log(arguments[0]+"说:"+arguments[1]);
}else{
return false;
}
}
showMessage("Hi!");
showMessage("张三","Hi 你好");
5 立即执行函数表达式是什么?有什么作用
我们需要在定义函数之后,立即调用该函数.这时不能在函数的定义之后加上圆括号,这会产生语法错误.
function(){ /* code */ }();
// SyntaxError: Unexpected token
产生这个错误的原因是,function这个关键字即可以当作语句,也可以当作表达式。
// 语句
function f() {}
// 表达式
var f = function f() {}
为了避免解析上的歧义,JavaScript引擎规定,如果function关键字出现在行首,一律解释成语句。因此,JavaScript引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
- 通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。
它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是IIFE内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
// 写法一
var tmp = newData;
processData(tmp);
storeData(tmp);
// 写法二
(function (){
var tmp = newData;
processData(tmp);
storeData(tmp);
}());
上面代码中,写法二比写法一更好,因为完全避免了污染全局变量。
6 求n!,用递归来实现
function jiechen(n) {
if(n === 1){
return 1;
}
return n * jiechen(n-1);
}
jiechen(4);//24
7 以下代码输出什么?
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('饥人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');
输出:
name: 饥人谷
age: 2
sex: 男
["饥人谷", 2, "男"]
name valley
name: 小谷
age: 3
sex: undefined
["小谷", 3]
name valley
name: 男
age: undefined
sex: undefined
["男"]
name valley
undefined
8 写一个函数,返回参数的平方和?
function sumOfSquares() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += (arguments[i]) * (arguments[i]);
}
return sum;
}
var result = sumOfSquares(2, 3, 4);
var result2 = sumOfSquares(1, 3);
console.log(result); //29
console.log(result2); //10
9 如下代码的输出?为什么
console.log(a);
var a = 1;
console.log(b);
输出:
undefined //原因:变量声明前置var a;
"error" //没有声明变量b
10 如下代码的输出?为什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
输出:
"hello world"
"error" //报错原因:函数表达式定义的函数在使用之前必须先赋值.
改为如下:
var sayAge = function(age){
console.log(age);
};
sayAge(10);
11 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar() ;
function foo() {
console.log(x);
}
function bar(){
var x = 30;
foo();
}
输出:10
原因:
全局作用域: {
可使用变量: x : 10
可使用的函数: foo() , bar()
}
foo()作用域: {
可使用变量: x : 10
}
bar()作用域: {
可使用变量: x : 30
可使用的函数: foo()
}
运行逻辑:
先申明全局变量 x = 10;
执行bar()函数;
申明一个仅在bar()作用域内访问的局部变量x=30;
执行foo()函数,执行console.log(x)方法;
但没在当前作用域下找到�x变量,但全局作用域的x=10可以使用,完成输出;
12 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar();
function bar(){
var x = 30;
function foo(){
console.log(x);//此处输出30
}
foo();
}
输出:30
原因:
全局作用域: {
可使用变量: x : 10
可使用的函数: bar()
}
foo()作用域: {
可使用变量: x : 10
}
bar()作用域: {
可使用变量: x : 30
可使用的函数: foo()
}
运行逻辑:
运行bar()-->运行 foo(), 找到可使用的局部变量x=30,输出x=30;
13 以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar();
function bar(){
var x = 30;
(function (){
console.log(x);
})();
}
输出:30
原因:
因为是立即调用函数所以上面代码等价于下面的:
var x = 10;
bar();
function bar(){
var x = 30;
function fn(){
console.log(x);
};
fn();
}
全局作用域{
可用变量:x=10 ;
函数:bar()
}
bar()作用域{
可用变量 x=30
函数:fn()
}
14 以下代码输出什么? 写出作用域链查找过程伪代码
var a = 1;
function fn(){
console.log(a);//第一次输出:undefined:因为下面 var a = 5;所以提前申明了var a ;找不到a报错.
var a = 5;
console.log(a);//第二次输出5:因为在当前作用域下找到了a=5;
a++;//a=6
var a;
fn3();
fn2();
console.log(a);//第五次输出:20,因为a的值已经在调用fn2()时被修改.
function fn2(){
console.log(a);//第四次输出:6,因为这作用域里没有var a 申明 ,去上一级即fn()里作用域找,此时a++后,a=6.所以输出6.
a = 20;// 给fn()里的变量a赋值为20.并保存在内存里
}
}
function fn3(){
console.log(a);// 第三次输出:1,因为fn3()属于全局函数,这里没var a,就去全局找到var a =1
a = 200; //找到了全局a ,在这一步给全局变量a 赋值为200.并保存在内存里.
}
fn();
console.log(a);//第六次输出:200,因为去全局找,而a的值已经在调用fn3()时被修改.
输出:
undefined
5
1
6
20
200
原因:
全局作用域{
可用变量: a = 1
可用函数: fn() ; fn3(); ;
}
fn()作用域内{
可用变量: a =5;
可用函数:fn2()
}
fn2()作用域内{
可用变量: a =20
}
fn3()作用域内{
可用变量: a=200
}
运行逻辑:
代码//后内容:为解释