聲明前置和作用域也是JS 部分面試常考點
1.函數聲明和函數表達式有什么區別
函數聲明:使用function關鍵字可以聲明一個函數。
function sayHello(){
console.log('hello')
}
//函數調用
sayHello()```
聲明不必放到調用的前面,聲明的是一個函數,用時就是調用,該聲明位置可放在后面。函數聲明最重要的特征就是函數聲明提升,意思是在執行代碼之前就會讀取函數聲明。
函數表達式:用函數表達式定義的函數在使用之前必須先賦值。
```var sayHello = function(){
console.log('hello');
}
sayHello()```
聲明必須放到調用的前面,聲明的是一個變量,必須聲明過后才能使用。
####2.什么是變量的聲明前置?什么是函數的聲明前置
- 變量的聲明前置:JavaScript引擎的工作方式是,先解析代碼,獲取所有被聲明的變量,然后再一行一行地運行。這造成的結果,就是所有的變量的聲明語句,都會被提升到代碼的頭部,然后給他初始值undefined,然后才逐句執行程序,這就叫做“變量提升”,也即“變量的聲明前置”。在一個作用域塊中,所有的變量都被放在塊的開始出聲明,但是變量的賦值不會提升。
- 函數的聲明前置:在一個作用域下,同var 聲明的變量一樣,function 聲明的函數也會前置。函數的聲明前置優先級高于變量的聲明前置。
```console.log(a);
var a = 3;
console.log(a);
sayHello();
function sayHello(){
console.log('hello');
}```
執行時語句順序如下:
```var a
function sayHello(){}
console.log(a);//undefined
a=3
console.log(a); //3
sayHello();```
####3.arguments 是什么
arguments 是一個類似數組的對象, 對應于傳遞給函數的參數。在函數內部,可以使用arguments對象獲取到該函數的所有傳入參數。arguments 對象僅在函數內部有效,在函數外部調用 arguments 對象會出現一個錯誤。
嚴格模式下,
1. arguments 不能通過程序語法被綁定(be bound)或賦值。
2.函數的 arguments 對象會保存函數被調用時的原始參數。arguments[i] 的值不會隨與之相應的參數的值的改變而變化,同名參數的值也不會隨與之相應的 arguments[i] 的值的改變而變化。
3.不再支持 arguments.callee。arguments.callee 是一個不可刪除屬性,而且賦值和讀取時都會拋出異常。
``` function printPersonInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
}
可以寫為
function printPersonInfo(){
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}```
####4.函數的"重載"怎樣實現
在 JS 中沒有重載,同名函數會覆蓋。 但可以在函數體針對不同的參數調用執行相應的邏輯。
```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 fn0() {})();
(function fn1() {} ());
// 在數組初始化器內只能是表達式
[function fn2() {}];
// 逗號也只能操作表達式
1, function fn3() {};```
在Javascript中,一對圓括號“()”是一種運算符,跟在函數名之后,表示調用該函數。比如,print()就表示調用print函數。
作用:
一是不必為函數命名,避免了污染全局變量;
二是隔離作用域,IIFE內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。
####6.求n!,用遞歸來實現
```function fn1(i){
if(i===1){
return 1;
}
return i*fn1(i-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('饑人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');```
輸出:
name:饑人谷 age:2 sex:男 ['饑人谷',2,'sex'] name valley
name:小谷 age:3 sex:undefined ['小谷',3] name valley
name:男 age:undefined sex:undefined ['男'] name valley
####8. 寫一個函數,返回參數的平方和?
```function sumOfSquare() {
var result = 0;
for(var i=0; i<arguments.length; i++){
result+=arguments[i]*arguments[i];
}
return result;
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result) //10```
####9. 如下代碼的輸出?為什么
```console.log(a);
var a = 1;
console.log(b);```
輸出:
undefined /*因為變量聲明前置,var a,console.log(a)*/
b is not defined報錯 /*因為變量b沒有聲明*/
####10. 如下代碼的輸出?為什么
```sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};```
輸出:
hello world /*函數聲明可以放在后面*/
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.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
barContext{
AO:{
x:30
},
Scope:bar.[[scope]] //globalContext.AO
}
fooContext{
AO:{
},
Scope:foo.[[scope]] // globalContext.AO
}```
####12. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼
```var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}```
輸出:30
```globalContext{
AO:{
x:10
bar:function
},
Scope:null
}
foo.[[scope]] = barContext.AO
bar.[[scope]] = globalContext.AO
barContext{
AO:{
x:30
foo:function
},
Scope:bar.[[scope]] //globalContext.AO
}
fooContext{
AO:{
},
Scope:foo.[[scope]] // barContext.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.[[scope]] = globalContext.AO
barContext{
AO:{
x:30
}
Scope:bar.[[scope]]
}```
####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
```globalContext{
AO:{
a:200
fn:function
fn3:function
},
Scope:null
}
fn.[[scope]] = globalContext.AO
fn2.[[scope]] = fnContext.AO
fn3.[[scope]] = globalContext.AO
fnContext{
AO:{
a:20
fn2:function
},
Scope:fn.[[scope]] //globalContext.AO
}
fn2Context{
AO:{
},
Scope:fn2.[[scope]] // fnContext.AO
}
fn3Context{
AO:{
},
Scope:fn3.[[scope]] // globalContext.AO
}```