JS函數作用域鏈

1.函數聲明和函數表達式

函數聲明和函數表達式都可以聲明函數,但使用函數聲明的方法,聲明不必放在調用前;使用函數表達式,聲明需要在調用前,可以省略函數名。
例:

 function sayHello(){
    console.log('hello')
  } 
//函數聲明

var sayHello = function(){
    console.log('hello');
  }
//函數表達式

2.變量與函數的聲明前置

在一個作用域下,var聲明的變量和function聲明的函數會前置,聲明的語句會優(yōu)先執(zhí)行。

3.arguments 對象

Arguments是個類似數組但不是數組的對象,說他類似數組是因為其具備數組相同的訪問性質及方式,能夠由arguments[n]來訪問對應的單個參數的值,并擁有數組長度屬性length。還有就是arguments對象存儲的是實際 傳遞給函數的參數,而不局限于函數聲明所定義的參數列表,而且不能顯式創(chuàng)建 arguments 對象。

4.函數的"重載"怎樣實現

JavaScript不支持函數的重載,即不能夠定義同樣的函數然后通過編譯器去根據不同的參數執(zhí)行不同的函數。但可以在函數內部定義多種模式,根據傳進來的參數信息進行匹配。

5.立即執(zhí)行函數表達式

立即執(zhí)行函數表達式是一種可以使函數在被定義后立即執(zhí)行的一種寫法,在javascript里,括號內部不能包含語句,當解析器對代碼進行解釋的時候,先碰到了(),然后碰到function關鍵字就會自動將()里面的代碼識別為函數表達式而不是函數聲明。例如下面的代碼:

(function(){
  var a  = 1;
})()
console.log(a); //undefined

立即執(zhí)行函數表達式的作用:一是不必為函數命名,避免了污染全局變量;二是IIFE內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。避免了污染全局變量。

6.求n!,用遞歸來實現

function factor(n){
  if(n === 1) {
    return 1
  }
  return n * factor(n-1)
}

var result=factor(5);
console.log(result)

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 undefined ["小谷", 3] name vally
getInfo('男');  //結果: name:男 undefined undefined ["男"] name vally

8. 寫一個函數,返回平方和

   function sumOfSquares(){
         var sum=0;
         for(var i=0;i<arguments.length;i++){
               sum=sun+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); //輸出undefined,因為變量a聲明提前,但此時還未被賦值
    var a = 1;
    console.log(b); //報錯“b is not defined”,因為b未被聲明

10. 如下代碼的輸出?

    sayName('world');
    sayAge(10);
    function sayName(name){
        console.log('hello ', name); //輸出hello world,因為函數聲明提前
    }
    var sayAge = function(age){
        console.log(age); //報錯,因為使用函數表達式必須在其后調用,否則認為sayAge不是函數
    };

11. 作用域鏈查找過程偽代碼 ,舉例如下:

var x = 10
bar() 
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo()
}
/*****************************************************************************/
//作用域鏈查找過程如下:
//首先全局作用域中聲明的變量有:x,函數有foo(),bar()
globalContext = {
    AO:{
        x:10
        foo:function
        bar:function
    },
    Scope:null
}
//此時被聲明的函數foo(),bar()的scope為 globalContext.AO
foo.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
//繼續(xù)執(zhí)行,進入bar的執(zhí)行上下文
barContext = {
    AO:{
     x:30
    }
    scope:bar.[[scope]] = globalContext.AO
}
//調用foo從scope中找到,進入foo的執(zhí)行上下文
fooContext = {
    AO:{    
    }
    scope:foo.[[scope]] = globalContext.AO
}
//從foo的scope:globalContext.AO中找到x:10,所以輸出10。

輸出10

12. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}
/***********************************************************************/
//全局作用域中聲明變量x,函數bar()
globalContext = {
  AO: {
    x: 10
    bar: function
  }
  Scope: null
}
//此時被聲明的bar()的scope為globalContext.AO
bar.[[scope]] = globalContext.AO
//進入bar執(zhí)行上下文
barContext = {
  AO: {
    x: 30
    foo: function
  }
  Scope: bar.[[scope]] = globalContext.AO
}
//foo()被聲明,它的scope為barContext.AO
foo.[[scope]] = barContext.AO

fooContext = {
  AO: {  }
  Scope: foo.[[scope]] = barContext.AO
}

輸出為30

13. 以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼

var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}
/************************************************************************************************/
//全局作用域聲明變量x,函數bar()
globalContext = {
  AO: {
    x: 10
    bar: function
  }
  Scope: null
}
bar.[[scope]] = globalContext.AO

barContext = {
  AO: {
    x: 30
    anonymous:function //匿名函數anonymous
  }
  Scope: bar.[[scope]] = globalContext.AO
}
anonymous.[[scope]] = barContext.AO

anonymousContext = {
  AO: { }
  Scope: anonymous.[[scope]] = barContext.AO
} 

輸出為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)
/************************************************************************************************/
globalContext = {
  AO: {
    a: 1
    fn: function
    fn3: function
  }
  Scope: null
}
fn.[[scope]] = globalContext.AO
fn3.[[scope]] = globalContext.AO

fnContext = {
  AO: {
    a: undefined
    fn2: function
  }
  Scope: fn.[[scope]] = globalContext.AO
}
fn2.[[scope]] = fnContext.AO
//進入fn后先輸出undefined,a賦值為5后輸出5
fn3Context = {
  AO: {}
  Scope: fn3.[[scope]] = globalContext.AO
}
 //輸出:1
fn2Context = {
  AO: {}
  Scope: fn2.[[scope]] = fnContext.AO
}
console.log(a) //輸出200

最后結果為:undefined 5 1 6 200

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 第5章 引用類型(返回首頁) 本章內容 使用對象 創(chuàng)建并操作數組 理解基本的JavaScript類型 使用基本類型...
    大學一百閱讀 3,665評論 0 4
  • 繼承 一、混入式繼承 二、原型繼承 利用原型中的成員可以被和其相關的對象共享這一特性,可以實現繼承,這種實現繼承的...
    magic_pill閱讀 1,124評論 0 3
  • 作用域鏈:JavaScript需要查詢一個變量x時,首先會查找作用域鏈的第一個對象,如果以第一個對象沒有定義x變量...
    風___________閱讀 299評論 0 0
  • 昨晚經不住老公一再申請,家里今年第一次開了空調,睡覺時,就覺腳底呼呼過風,把毛巾被裹在腳上,才得一夜安睡。 上午幾...
    misang閱讀 214評論 1 4
  • 在這給大家分享一下我的大學生活,有點空虛有點冷,但是我在慢慢改變自己,也希望能在畢業(yè)之前活出一個像樣的自己,也能過...
    ShaulQiao閱讀 478評論 0 2

友情鏈接更多精彩內容