1.函数声明和函数表达式有什么区别
- 使用函数声明来声明的函数不需要放在调用的前面就可以被调用,使用函数表达式声明的函数需要放在调用函数的前面才能被正确调用。
2.什么是变量的声明前置?什么是函数的声明前置
- 在一个作用域下,var 声明的变量和function 声明的函数会前置。
- 使用var声明的变量会在执行代码的时候先预解析到作用域的头部,并被赋值为undefined.
- 使用function声明的函数也一样会被预解析读取到作用域的头部。
3.arguments 是什么
- arguments是一个函数自带的参数对象,他包含了函数所有的参数,而且可以像调用一个数组一样来调用,不过arguments并不是一个数组,如果用typeof来检测的话会返回"object",表示是一个对象。
4.函数的"重载"怎样实现
- 重载在一般的编程语言中,表示有相同的函数名,但是参数列表不相同,通过传递不同的参数可以让函数内部的处理方法不一样,得到也结果也可能不同。
- JaveScript中并没有重载,函数同名的话会被覆盖,但可以在函数体针对不同的参数调用执行相应的逻辑。
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
5.立即执行函数表达式是什么?有什么作用
- 立即执行函数表达式表示直接声明函数,声明后直接调用函数。不直接在声明函数直接加上‘()’调用时因为浏览器不识别会报语法错误。一般写法为直接将声明函数用小括号括起来然后再在后面添加上小括号调用。
- 作用是可以隔离作用域,防止污染全局作用域。
6.求n!,用递归来实现
function fn(n){
if (n === 1){
return 1;
}
return n*fn(n-1);
}
fn(n)
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, '男'); // name:饥人谷 age:2 sex:男 ['饥人谷', 2, '男'] name:valley
getInfo('小谷', 3); // name:小谷 age:3 sex:undefined ['小谷', 3] name:valley
getInfo('男'); // name:男 age:undefined sex:undefined ['男'] name:valley
8. 写一个函数,返回参数的平方和?
function sumOfSquares(){
if (arguments.length === 0){
alert("请输入至少一个参数")
}
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); //undefined
var a = 1;
console.log(b); // 报错
- 因为变量声明前置的关系,var a 会被提到作用域头部,赋值为undefined,然后运行到代码的时候会被赋值为1.而变量b并没有被声明,函数运行到代码console.log(b); 时在作用域内找不到变量b,所以浏览器报错。
10. 如下代码的输出?为什么
sayName('world'); //hello world
sayAge(10); // 浏览器报错 sayAge is not a function
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
- 使用函数声明方式来声明的函数,会因为函数声明前置被提到作用域的头部,所以调用sayName时即使调用函数写在声明函数之前依旧有效果,但是使用函数表达式声明函数的话,浏览器会先解析sayAge为一个变量,并赋值为undefined然后提到代码头部,然后执行到声明函数的代码时才会将这个变量赋值为一个函数。调用写在声明之前的话浏览器执行到调用函数的代码段时会认为sayAge是一个变量,使用函数调用方式是错误的,从而报错。
11. 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10
bar() // x= 10
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
==>
/*
globalContext = {
AO:{
x:10;
foo: function(){}
bar: function(){}
}
scope:null;
}
barContext = {
AO:{
x:30;
}
bar.[[scope]] =globalContext.AO
}
fooContext = {
AO:{
}
foo.[[scope]] =globalContext.AO
}
*/
- foo.scope为全局作用域,当执行bar时会现在bar的函数作用域bar.AO中创建一个x并被赋值为30,然后调用函数foo,在foo的作用域中找不到变量x,所以会返回到foo.scope中也就是全局作用域中寻找,得到x=10。
12. 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar() // 30
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
==>
/*
globalContext = {
AO:{
x:10
bar: function(){}
}
scope:null;
}
barContext = {
AO:{
x:30;
foo: function(){}
}
bar.[[scope]] =globalContext.AO
}
fooContext = {
AO:{
}
foo.[[scope]] =barContext.AO
}
*/
- 和上一题差不多,不过这题中foo.scope为barContext.AO,所以x值去barContext.AO里面找,找到x为30
- 以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar() // 30
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
==>
/*globalContext = {
AO: {
x: 10
bar: function
}
Scope: null
}
barContext = {
AO: {
x: 30
function: function
}
Scope: globalContext.AO
}
functionContext = {
AO: {}
Scope: barContext.AO
}
*/
- 与上一题差不多,只不过这里没有声明函数再调用,而是立即执行函数表达式的写法,函数的执行上下文依然还是barContext.AO,所以取到的x的值依旧是30。
14. 以下代码输出什么? 写出作用域链查找过程伪代码
var a = 1;
function fn(){
console.log(a) //undefined
var a = 5
console.log(a) // 5
a++
var a
fn3() // 1
fn2() // 6
console.log(a) // 20
function fn2(){
console.log(a)
a = 20
}
}
function fn3(){
console.log(a)
a = 200
}
fn() // undefined 5 1 6 20
console.log(a) // 200
==>
/*
globalContext = {
AO: {
x: 1
fn: function
fn3:function
}
Scope: null
}
fnContext = {
AO: {
a: undefined
a:5
a:6
fn2:function
}
Scope: globalContext.AO
}
fn2Context = {
AO: {
a:20
}
Scope: fnContext.AO
}
fn3Context = {
AO: {
a:200
}
Scope: globalContext.AO
}
*/
- 调用fn时,因为变量前置,所以第一个console.log(a)得到undefined,然后a被赋值为5,第二次console.log(a)得到 a=5,之后执行a++ 使a=6.
- 接着调用fn3,但是fn3中console.log(a)在a=200之前,且并没有使用var让变量声明前置,找不到变量a,便会去fn3的执行上下文中也就是全局作用域中寻找,得到a=1;然后再将全局作用域中的a赋值为200.
- 然后调用fn2,console.log(a)在a=20之前,但是依然没有变量前置,所以会在fn2的执行上下文fnContext.AO中寻找,得到a=6,然后降fnContext.AO中的a赋值为20.
- 最后一次console.log(a)调用得到的a = 20.到此fn执行完毕。
- fn调用后执行的console.log(a),因为之前全局作用域的a 在执行fn3是被赋值成了200,所以得到200