1.函数声明和函数表达式有什么区别
函数声明
使用function关键字可以声明一个函数
//函数声明
function sayHello(){
console.log('hello')
}
//函数调用
sayHello()
区别:声明不必放到调用的前面
函数表达式
var sayHello = function(){
console.log('hello');
}
sayHello()
区别:声明必须放到调用的前面
2.什么是变量的声明前置?什么是函数的声明前置
所谓的变量声明前置就是在一个作用域块中,所有的变量都被放在块的开始处声明。
和变量声明前置一样,执行代码之前会先读取函数声明,只要函数在代码中进行了声明,无论它在哪个位置上进行声明,js引擎都会将它的声明放在范围作用域的顶部。
3.arguments 是什么?
描述
arguments对象是所有函数中可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数的条目,第一个条目的索引从0开始。例如,如果一个函数传递了三个参数,你可以参考它们如下:
arguments[0];
arguments[1];
arguments[2];
参数也可以被设置:
arguments[1] = 'new value';
arguments对象不是一个 Array。它类似于数组,但除了 长度之外没有任何数组属性。例如,它没有 pop方法。但是它可以被转换为一个真正的数组:
let args = Array.prototype.slice.call(arguments);
let args = [].slice.call(arguments);
你还可以使用 Array.from()方法或 sprea 运算符将 arguments 转换为真正的数组:
let args = Array.from(arguments);let args = [...arguments];
对参数使用slice会阻止某些JavaScript引擎中的优化 (比如 V8 引擎 )。
如果你关心它们,尝试通过遍历arguments对象来构造一个新的数组。
另一种方法是使用 被忽视的/鄙视/轻视,/看不起 Array构造函数作为一个函数:
let args = (arguments.length === 1 ? [arguments[0]] :
Array.apply(null, arguments));
如果 Array generics可用的话,下面的代码可以作为替代:
var args = Array.slice(arguments);
arguments 对象仅在函数内部有效,在函数外部调用 arguments 对象会出现一个错误。
arguments的typeof返回'object'。
console.log(typeof arguments); // 'object'
可以使用索引来确定各个arguments的类型。
console.log(typeof arguments[0]); //
这将返回单个参数的typeof。
如果你调用一个函数,当这个函数的参数数量比它显式声明的参数数量更多的时候,你就可以使用 arguments
对象。这个技术对于参数数量是一个可变量的函数来说比较有用。 你可以用 arguments.length来得到参数的数量,然后可以用 arguments
object 来对每个参数进行处理。 (想要得到函数签名的参数数量, 请使用 Function.length
属性
arguments.callee指向当前执行的函数。
arguments.caller指向调用当前函数的函数。
arguments.length指向传递给当前函数的参数数量。
4.函数的"重载"怎样实现
在JavaScript中没有重载! 同名函数会覆盖。 但可以在函数体针对不同的参数调用执行相应的逻辑,实现重载。
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(){ /* code */ }();// SyntaxError: Unexpected token
一般情况下,也许有人认为立即执行函数可能会是这个样子的,但其实为了避免解析上的歧义,JavaScript引擎规定,如果function关键字出现在行首,一律解释成语句。因此,JavaScript引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
所以一般情况下,在写,IIFE的时候要写成
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称IIFE。
注意,上面两种写法最后的分号都是必须的。如果省略分号,遇到连着两个IIFE,可能就会报错。
推而广之,任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果,比如下面三种写法。
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
作用:
通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是IIFE内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
6.求n!,用递归来实现
n!算法函数:
function factor(n) {
if ( n>=0 ){
if ( n === 0 || n === 1 ){
return n=1
}
return n*factor(n-1)
}else {
console.log("n为正整数")
}
}
1+2+...+n 的值
function sum(n){
if(n === 1) {
return 1
}
return n + sum(n-1)
}
sum(10)
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('男');
输出结果2:
name: 男
age: undefined
sex: undefined
["男"]
name valley
8. 写一个函数,返回参数的平方和?
function sumOfSquares(){
var sum=0;
for(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);/*a被声明但是未赋值,undefined*/
var a = 1;/*var a前置至作用域前端*/
console.log(b);/*b未被声明,所以会报错: b is not defined*/
10. 如下代码的输出?为什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
输出
hello world
Uncaught TypeError: sayAge is not a function(…)
函数声明不需要前置,函数表达式要前置
11. 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
输出10
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
//声明 foo 时 得到下面
foo.[[scope]] = globalContext.AO
//声明 bar 时 得到下面
bar.[[scope]] = globalContext.AO
12. 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
输出10
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
//声明 foo 时 得到下面
foo.[[scope]] = globalContext.AO
//声明 bar 时 得到下面
bar.[[scope]] = globalContext.AO
当调用foo() 时,先从 bar 执行上下文中的 AO里找,找不到再从 bar 的 [[scope]]里找,找到后即调用
barContext = {
AO: {
x: 30
},
Scope: bar.[[scope]] //globalContext.AO
}
bar.[[scope]] = globalContext.AO
当调用 foo() 时,进入 foo 的执行上下文
fooContext = {
AO: {},
Scope: foo.[[scope]] //globalContext.AO
}
13. 以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
输出30
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
//声明 bar 时 得到下面
bar.[[scope]] = globalContext.AO
当调用 bar() 时, 进入 bar 的执行上下文
barContext = {
AO: {
x: 30,
foo: function
},
Scope: bar.[[scope]] //globalContext.AO
}
//在 bar 的执行上下文里声明 foo 时 得到下面
foo.[[scope]] = barContext.AO
当调用 foo() 时,先从 bar 执行上下文中的 AO里找,找到后即调用
fooContext = {
AO: {},
Scope: foo.[[scope]] // barContext.AO
}
当调用 foo() 时,进入 foo 的执行上下文
14. 以下代码输出什么? 写出作用域链查找过程伪代码
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)
输出结果
undefined
5
1
6
20
200
var a = 1; //全局上下文中有var a和 function fn(),function fn3(),声明前置
function fn(){ //函数中有var a 和function fn2()
console.log(a)//声明前置,但没有赋值,输出undefined
var a = 5;
console.log(a)//var a=5 故输出结果为5
a++//自增,即fnContext里的a值变为6
var a//同一个函数里前面已经声明,故没有变化
fn3()//执行函数fn3()转function fn3(){ } → 执行完之后跳回fn(){ }
fn2()//执行函数fn2(),转function fn2(){ } → 执行完之后跳回 fn(){ }
console.log(a)//此时a的值为20,故输出20
function fn2(){
console.log(a)//fn2Context里没有a,故查找fnContext.AO,此时fn里面a为6,故输出6
a = 20//fn2Context里没有a,故查找fnContext.AO,把20赋值给fnContext.AO里的a
}
}
function fn3(){
console.log(a)//fn3Context没有a,故向上查找global.AO,输出结果为1,
a = 200///fn3Context没有a,故向上查找global.AO,把200赋值给a,即global.AO里的a变为200.
}
fn()//函数调用
console.log(a)//此时globalontext里的a的值诶200,故输出200
网友评论