一句话:函数的作用域,与声明时有关,与调用时无关。
1. 函数声明和函数表达式有什么区别
函数声明,使用function关键字可以声明一个函数,声明不必放到调用的前面。
函数表达式,声明必须放到调用的前面
2. 什么是变量的声明前置?什么是函数的声明前置
在一个作用域下,var 声明的变量和function 声明的函数会前置。
变量的声明前置,var声明的变量按顺序提升到js最前,赋值为undefined
函数的声明前置,function声明的函数和变量一样前置,且都按照顺序提升。
3. arguments 是什么
argument是类数组对象,每个函数中都存在argument对象,argument并不是一个真正的数组,所以不具备除length属性之外的属性,这个对象维护着所有传入该函数的参数列表,通过arguments[1、2、3]等...可以获取到相应的传入参数。
4. 函数的"重载"怎样实现
在 JS 中没有重载, 同名函数会覆盖。 但可以在函数体针对不同的参数调用执行相应的逻辑。
例子:
function fn(a, b, c){
if( a !== void 0){ //若a不为undefined,就输出a
console.log(a);
}
if( b !== void 0){ //若b不为undefined,就输出b
console.log(b);
}
if( c !== void 0){ //若c不为undefined,就输出c
console.log(c);
}
}
5. 立即执行函数表达式是什么?有什么作用
立即执行函数表达式,首先它是一个表达式,而不是一个声明函数。其次,因为是表达式,所以可以用(), +, !, -等运算符来触发。
例如:(function(){…})()
函数会立即执行,并且可以隔离作用域,立即执行函数内的任何赋值都不会影响这个函数外的变量和函数。
6. 求n!,用递归来实现
function factorial(n){
if( n === 1 ){
return 1;
}
return n * factorial(n-1);
}
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('Llane', 2, '男');
//name: Llane
//age: 2
//sex: 男
//["Llane",2,"男"]
//name valley
getInfo('小L', 3);
//name: 小L
//age: 3
//sex: undefined
//["小L",3]
//name valley
getInfo('男');
//name: 男
//age: undefined
//sex: undefined
//["男"]
//name valley
8.写一个函数,返回参数的平方和?
function sumOfSquares(){
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);
var a = 1;
console.log(b);
变量提升后代码为:
var a;
console.log(a); //a此时还没赋值,所以输出 undefined
a = 1;
console.log(b); //变量b没有声明过,所以会报错 Uncaught ReferenceError: b is not defined
10.如下代码的输出?为什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
变量提升后代码为:
function sayName(name){
console.log('hello ', name);
}
var sayAge;
sayName('world');
sayAge(10); //函数表达式,声明必须在调用前
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()
}
//声明提升后为
var x
function foo() {
console.log(x)
}
function bar(){
var x
x = 30
foo()
}
x = 10
bar()
作用链伪代码:
globalContext = {
AO: {
x:10
foo:function
bar:function
}
scope:null
}
foo.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
barContext = {
AO:{
x:30
}
scope:globalContext.AO
}
fooContext = {
AO:{}
scope:globalContext.AO
}
bar()开始执行,声明局部变量x=30,
foo()开始执行,执行console.log(x),发现fooContext中没有x,
到scope:globalContext.AO中找x
发现:globalContext.AO中x为10
所以输出10
12.如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
//声明提升后为
var x;
function bar(){
var x
function foo(){
console.log(x)
}
x = 30;
foo();
}
x = 10
bar()
作用域伪代码为:
globalContext = {
AO:{
x:10
bar:function
}
scope: null
}
bar.[[scope]] = globalContext.AO
barContext = {
AO:{
x: 30
foo:function
}
scope:globalContext.AO
}
foo.[[scope]] = barContext.AO
fooContext = {
AO:{}
scope:barContext.AO
}
bar()执行,声明局部变量x=30
foo()执行,发现fooContext.AO中没有x
根据scope:barContext.AO去找
发现scope:barContext.AO中x为30
所以输出30
13.以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
//声明提升后
var x;
function bar(){
var x
x = 30;
(function (){
console.log(x)
})()
}
x = 10;
bar()
作用域链伪代码:
globalContext = {
AO:{
x:10
bar:function
}
scope:null
}
bar.[[scope]] = globalContext.AO
barContext = {
AO:{
x:30
(anomyous):function
}
scope:globalContext.AO
}
(anomyous).[[scope]] = barContext.AO
(anomyous)Context = {
AO:{}
scope:barContext.AO
}
bar()执行声明局部变量x = 30
执行立即执行函数,立即执行函数中没有x
所以去他的scope:barContext中找,发现x=30
所以输出30
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)
//声明提升
var a
function fn(){
var a
function fn2(){
console.log(a)
a = 20
}
console.log(a)
a = 5
console.log(a)
a++
fn3()
fn2()
console.log(a)
}
function fn3(){
console.log(a)
a = 200
}
a = 1;
fn()
console.log(a)
作用域伪代码:
globalContext = {
AO:{
a:1 => 200
fn:function
fn3:function
}
}
fn.[[scope]] = globalContext
fn3.[[scope]] = globalContext
fnContext = {
AO:{
a:undefined => 5 => 6 => 20
fn2:function
}
scope:globalContext
}
fn2.[[scope]] = fnContext
fn3Context = {
AO:{}
scope:globalContext
}
fn()开始执行
//输出 undefined 5 1 6 20 200
ps:13题的伪代码中匿名函数的AO写法有待商榷。
补充:
1.如果是带参数的函数
例如:
function exampleFn(a){
console.log(a);
}
example(10);
//相当于
function exampleFn(a){
var a = 10;
console.log(a);
}
它的伪代码作用域为:
exampleFnConext = {
AO:{
a:10
}
scope:globalContext.AO
}