1.函数声明和函数表达式有什么区别
函数声明使用function关键字声明一个函数,function fn() { },函数声明必须始终带有一个标识符即函数名,函数声明会在任何表达式被解析和求值之前先行被解析和求值,函数可以在任意地方调用fn(),声明不必放到调用的前面。
函数表达式通过赋值来声明函数,声明完毕后要加上分号表示该句结束,声明必须放到调用的前面,在表达式执行完后,函数才存在并可被调用。
2.什么是变量的声明前置?什么是函数的声明前置
在一个作用域下,var 声明的变量和function 声明的函数会前置。
javascript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。变量声明前置就是在一个作用域中,所有的变量都被放在开始处声明,即使声明位于源代码中的最后一行,它也会先于同一作用域中位于最前面的表达式执行。
console.log(a);
var a = 1;
即
var a;
console.log(a);
a = 1;
JavaScript引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。函数的声明前置是在一个作用域中,函数的声明会被放在代码开始处先执行。而函数内部的声明前置则指的是在执行该函数里面的语句的时候,声明会被首先执行。
3.arguments 是什么
arguments 是JavaScript里的一个内置对象,是比较特别的一个对象,在js中在调用一个函数的时候,我们经常会给这个函数传递一些参数,js把传入到这个函数的全部参数存储在arguments里,在函数内部,可以使用arguments对象获取到该函数的所有传入参数。
function printPersonInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
console.log(arguments);
}
它的属性名是按照传入参数的序列来的,第1个参数的属性名是0,第2个参数的属性名是1,以此类推,并且它还有length属性,存储的是当前传入函数参数的个数,很多时候我们把这种对象叫做类数组对象。
4.函数的"重载"怎样实现
重载是很多面向对象语言实现多态的手段之一,在静态语言中确定一个函数的手段是靠方法签名——函数名+参数列表,也就是说相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载。在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的,但可以在函数体针对不同的参数调用执行相应的逻辑。在函数定义中用f.arguments.length判断一下调用时传入的参数个数。然后对不同的情况采用不同的处理方式。
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(){
var a = 1;
})()
console.log(a); //undefined
其他写法
(function fn1() {});
// 在数组初始化器内只能是表达式
[function fn2() {}];
// 逗号也只能操作表达式
1, function fn3() {};
作用:不必为函数命名,避免了污染全局变量,隔离作用域,创建一个独立的作用域,这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
6.求n!,用递归来实现
function factor(n){
if(n === 1|| n === 0) {
return 1
}
return n * factor(n-1)
}
factor(5)
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
8.写一个函数,返回参数的平方和?
function sumOfSquares(){
var sum = 0;
for(var n = 0;n<arguments.length;n++{
sum = sum+arguments[n]*arguments[n];
}
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);//输出undefined,相当于var a声明前置,输出undefined,再a=1
var a = 1;
console.log(b);//error,报错,b没声明
10. 如下代码的输出?为什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
输出
hello world//函数声明不必放在调用前,函数声明前置
error//函数表达式须放在调用前面,函数表达式只有执行到这一行才会去声明
11. 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
1.
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
foo.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
2.调用bar()
barContext = {
AO:{
x:30
},
Scope:bar.[[scope]] = globalContext.AO
}
3.调用foo()
fooContext = {
AO:{},
Scope:foo.[[scope]] = globalContext.AO
}
输出10
12. 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
1.
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
bar.[[scope]] = globalContext.AO
2.调用bar()
barContext = {
AO:{
x:30
foo:function
},
Scope:bar.[[scope]] = globalContext.AO
}
foo.[[scope]] = barContext.AO
3.调用foo()
fooContext = {
AO:{},
Scope:foo.[[scope]] = barContext.AO
}
输出30
13. 以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
1.
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
bar.[[scope]] = globalContext.AO
2.调用bar()
barContext = {
AO:{
x:30
function(){}
},
Scope:bar.[[scope]] = globalContext.AO
}
function.[[scope]] = barContext.AO
3.调用立即执行函数
functionContext = {
AO:{},
Scope:function.[[scope]] = barContext.AO
}
输出30
14. 以下代码输出什么? 写出作用域链查找过程伪代码
var a = 1;
function fn(){
console.log(a)//undefined
var a = 5//fncontext.AO中的a赋值为5
console.log(a)//输出5
a++//fnContext.AO中的a加1为6
var a
fn3()//调用fn3(),去执行fn3()
fn2()//调用fn2()
console.log(a)//此时fnContext.AO中的a赋值为20,输出20
function fn2(){
console.log(a)//此时fnContext.AO中的a赋值为6,所以输出6
a = 20//fnContext.AO中的a赋值为20
}
}
function fn3(){
console.log(a)//因为fn3Context.AO中没有a值,所以去globalContext.AO找,a值为1,所以输出1
a = 200//globalContext.AO中a赋值为200
}
fn()
console.log(a))//此时globalContext.AO中a赋值为200
1.
globalContext = {
AO: {
a: 1 200
fn: function
fn3:function
},
Scope: null
}
fn.[[scope]] = globalContext.AO
fn3.[[scope]] = globalContext.AO
2.调用fn()
fnContext = {
AO: {
a: undefined 5 6 20
fn2: function
},
Scope: fn.[[scope]] = globalContext.AO
}
fn2.[[scope]] = fnContext.AO
3.调用fn3()
fn3Context = {
AO: { },
Scope: fn3.[[scope]] = globalContext.AO
}
4.调用fn2()
fn2Context = {
AO: { },
Scope: fn2.[[scope]] = fnContext.AO
}
输出:undefined 5 1 6 20 200