1. 函数声明和函数表达式有什么区别
在ECMAScript中,创建函数的最常用的两个方法是函数表达式和函数声明,两者期间的区别是有点晕,因为ECMA规范只明确了一点:函数声明必须带有标示符(Identifier)(就是大家常说的函数名称),而函数表达式则可以省略这个标示符:
- 函数声明:
function 函数名称 (参数:可选){ 函数体 } - 函数表达式:
function 函数名称(可选)(参数:可选){ 函数体 }
函数声明在作用域内可以放到任何位置,在函数调用的后面也不会报错。但函数表达式与声明普通变量赋值本质上一样,当函数调用在函数表达式后面的时候因为变量提升,会报错。
函数声明会被提前,而函数表达式不会;函数声明必须要有标识符,而函数表达式不用;函数表达式往往用于立即执行的函数;函数声明不能出现在if语句,while循环或其他语句中。
2. 什么是变量的声明前置?什么是函数的声明前置
-
什么是变量的声明前置?JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,然后给他初始值undefined,然后才逐句执行程序,这就叫做“变量提升”,也即“变量的声明前置”。
-
什么是函数的声明前置?和变量的声明会前置一样,函数声明同样会前置,如果我们使用函数表达式那么规则和变量一样,如下图:
如果我们使用函数声明的方式,那么即使函数写在最后也可以在前面语句调用,前提是函数声明部分已经被下载到本地。
3. arguments 是什么
arguments 是一个类似数组的对象, 对应于传递给函数的参数。
arguments对象不是一个 Array
。它类似于数组,但除了 长度之外没有任何数组属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的数组:
let args = Array.prototype.slice.call(arguments); let args = [].slice.call(arguments);
你还可以使用 Array.from()
方法或 spread 运算符将 arguments 转换为真正的数组:
let args = Array.from(arguments);let args = [...arguments];
4. 函数的"重载"怎样实现
用 arguments 对象判断传递给函数的参数个数,即可模拟函数重载:
function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 5);
} else if(arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //输出 "15"
doAdd(40, 20); //输出 "60"
当只有一个参数时,doAdd() 函数给参数加 5。如果有两个参数,则会把两个参数相加,返回它们的和。所以,doAdd(10) 输出的是 "15",而 doAdd(40, 20) 输出的是 "60"。
虽然不如重载那么好,不过已足以避开 ECMAScript 的这种限制。
5. 立即执行函数表达式是什么?有什么作用
立即执行函数表达式(Immediately-Invoked Function Expression),简称IIFE。表示定义函数之后,立即调用该函数。
(function(){
var a = 1;
})()
其他写法:
(function fn1() {});
[function fn2() {}];
1, function fn3() {};
作用:隔离作用域。
6. 求n!,用递归来实现
function factorial(num)
{
// n不能小于0
if (num < 0) {
return -1;
}
// n=0时,阶乘结果是1
else if (num == 0) {
return 1;
}
// 否则,再次调用此递归过程
else {
return (num * factorial(num - 1));
}
}
var result = factorial(8);
document.write(result);
// Output: 40320
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:undefiend sex:undefined ["男"] name valley */
8. 写一个函数,返回参数的平方和?
function sumOfSquares(){
var result = 0
for (var i = 0; i < arguments.length; i++) {
result = result + arguments[i] * arguments[i]
}
console.log(result)
}
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 报错:b is not defined 原因:变量提升,没有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);
};
11. 如下代码输出什么? 写出作用域链查找过程伪代码
输出结果 x:10
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
//输出10
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
foo:function
},
Scope:bar.[[scope]]//globalContext.AO
}
bar() //结果 x:30
3.第三步:调用foo()
fooContext={
AO:{}
Scope:foo.[[scope]]=globalContext.AO
}
foo() //结果 x:10
*/
12. 如下代码输出什么? 写出作用域链查找过程伪代码
// 输出结果 x:30
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
/*
输出结果 30
第一步:执行上下文
globalContext{
AO:{
x:10
bar:function
}
Scope:null
}
bar.[[scope]]=globalContext.AO
第二步:调用bar()
barContext={
AO:{
x:30
foo:function
}
Scope:bar.[[scope]]=globalContext.AO
}
bar() //结果 x:30
第三步:调用foo()
fooContext={
A0:{ }
Scope:foo.[[scope]]=barContext.AO
}
foo() //结果 x:30
// bar(){
// foo()
// }
*/
13. 以下代码输出什么? 写出作用域链的查找过程伪代码
// 输出结果 x:30
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
输出30
/*
第一步:执行上下文
globalContext{
AO:{
x:10;
bar:function
}
Scope:null
}
bar.[[scope]]=globalContext.AO
第二步:调用bar()
barContext={
AO:{
x=30
:function
}
Scope:bar.[[scope]]=globalContext.AO
}
第三步:立即执行function ()
functionContext={
AO:{ }
Scope:function.[[scope]]//barContext.AO
}
*/
14. 以下代码输出什么? 写出作用域链查找过程伪代码
// 输出结果 a:undefined 5 1 6 20 200
var a = 1;
function fn(){
console.log(a)
var a = 5
console.log(a)
a++
var a
fn3()
fn2()
console.log(a)
function fn2(){
console.log(a)
a = 20
}
}
function fn3(){
console.log(a)
a = 200
}
fn()
console.log(a)
/*
//第一步:执行上下文
globalContext:{
AO:{
a:1
fn:function
fn3:function
}
Scope:null
}
fn.[[scope]]=globalContext.A0
fn3.[[scope]]=globalContext.AO
//调用 fn()
fnContext:{
AO:{
a:6
fn3:function
fn2:function
}
Scope:null
}
fn3[[scope]]=fnContext.AO
fn2[[scope]]=fnContext.AO
//调用 fn2()
fn2Context:{
AO:{
}
Scope:fn2.[[scope]]=fnContext.AO
}
//调用 fn3()
fn3Context:{
AO:{
}
Scope:fn3.[[scope]]=globalContext.AO
}
*/
网友评论