函数声明和函数表达式有什么区别
函数声明
function printInConsole(str) {
console.log(str);
}
函数表达式
var printInConsole=function (str) {
console.log(str);
};
区别
- 函数表达式结束后需要加
;
表示声明变量结束。 - 函数表达式的本质是用一个变量来存储一个函数。
- 由于在JavaScript中函数是提前声明的,所以使用函数声明方式只要在作用域中,写在哪里都可以,而函数表达式只能先声明在调用。
什么是变量的声明前置?什么是函数的声明前置?
变量的声明前置
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升。这种工作方式体现在我们可以先使用变量在声明变量。
console.log(a);
var a=6;
// 6
函数的声明前置
和变量的声明会前置一样,函数声明同样会前置,如果我们使用函数表达式来声明一个函数,那么规则和变量一样。
printInConsole('啦啦啦');
function printInConsole(str) {
console.log(str);
}
//啦啦啦
arguments 是什么
在函数内部,你可以使用arguments对象获取到该函数的所有传入参数
function printInConsole() {
for(var i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
}
printInConsole(1,2,3,4,5);
//1 2 3 4 5
函数的"重载"怎样实现
在JavaScript中,函数调用可以不把所有参数都传入,只要你函数体内做好处理就行,但前提是传的参数永远被当做前几个。只能按照顺序来写我们可能会传入的参数,通过判断参数的个数来达到重载的效果。比如上题中的例子,不管我们传入多少参数都会打印出来,打印的顺序就是我们传入参数的顺序,不能更改。
立即执行函数表达式是什么?有什么作用
立即执行表达式
(function(){console.log('1')})();
(function(){console.log('2')}());
!function(){console.log('3')}();
void function(){console.log('4')}()
作用
隔离作用域,说隔离作用域有些难以理解,如果说可以创建一个作用域就很好理解了。他可以将作用域分为两块,内部一块外部一块。
求n!,用递归来实现
function factor(num) {
if(num==0){
return 1;
}
else{
return num*factor(num-1);
}
}
以下代码输出什么?
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
- 写一个函数,返回参数的平方和
function sumOfSquares(){
var num=0;
for(var i=0;i<arguments.length;i++){
num+=arguments[i]*arguments[i];
}
return num;
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
- 如下代码的输出?为什么
console.log(a);
var a = 1;
console.log(b);
1 undefined
在JavaScript中变量的声明位置会提前,所以a不是undefined,而是1。没有定义变量b,所以输出undefined
- 如下代码的输出?为什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
world 报错:'sayAge不是一个函数'
使用函数声明函数的时候会将函数声明提前,所以无论在相同作用域中的哪里都能够使用,但是使用表达式声明函数的时候实际上我们只是声明了一个变量,并将一个函数赋值给了变量,所以他会报sayAge不是一个函数的错。
- 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
//进入全局执行上下文:
globalContext = {
AO: {
x: 10,
foo: function,
bar: function,
};
Scope: null;
//声明foo和bar时得到
foo.[Scope] = globalContext.AO;
bar.[Scope] = globalContext.AO;
//调用bar()时执行 bar()
}
//进入bar()的执行上下文,从globalContext.AO进入
barContext = {
AO: {
x: 30,
};
Scope: globalContext.AO;
//执行 foo() 在这个作用域内找不到,就从Scope中去找
}
//进入 foo()的执行上下文,从globalContext.AO进入
fooContext = {
AO: {};
Scope: globalContext.AO;
//执行 console.log(x)输出10,因为 foo()的作用域是globalContext.AO
}
- 如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
//进入全局执行上下文
gloabalContext = {
AO:{
x : 10,
bar : function
};
Scope : null;
bar[Scope] = gloabalContext.AO;
//执行 bar()
}
//当调用bar时进入bar的执行上下文,从globalContext.AO进入
barContext = {
AO:{
x:30,
foo: function
}
Scope: globalContext.AO;
//声明foo时得到
foo[Scope] = barContext.AO;
//调用foo
}
//调用foo()进入foo的执行上下文,从barContext.AO进入
fooContext = {
AO: {},
Scope: foo.[[scope]] // barContext.AO
}
//所以输出的值为30,foo在bar的作用域链中,使用bar中的变量。
- 以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
//进入全局的执行上下文
globalContext = {
AO: {
X: 10,
bar: function,
};
Scope: null;
bar.[Scope] = globalContext.AO;
//执行 bar();
}
//进入 bar() 的执行上下文
barContext = {
AO: {
x: 30,
function: function,
};
Scope: globalContext.AO;
function.[Scope] = barContext.AO;
//执行 function ()
}
//进入 function() 的执行上下文
functionContext = {
AO: {};
Scope: barContext.AO
//执行 console.log(x) // 输出30 因为 AO 中没有,就从 Scope 中去找
}
- 以下代码输出什么? 写出作用域链查找过程伪代码
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.AO;
fn3.[Scope] = globalContext.AO;
执行 fn();
}
进入 fn() 的执行上下文
fnContext = {
var a;
function fn2(){}
fn2.[Scope] = fnContext;
console.log(a)// undefined,var 声明前置未赋值
a = 5;
console.log(a);// 5,a 已经赋值 5
a++;
//执行 fn3(){
console.log(a);// 1,fn3 的作用域为 globalContext
a = 200; //改变了 globalContext 中的 a
}
执行 fn2(){
console.log(a);// 6,fn2 的作用域为 fnContext
a = 20; // 改变了 fnContext 中的 a 为 20
}
console.log(a);// 20,a 已经赋值 20
}
console.log(a);// 200,它的作用域为globalContext
// 最终输出为 undefined 5 1 6 20 200