JavaScript面向對象~ 作用域

聲明

代碼在執行的過程中會有一個預解析的過程,也就是在代碼的執行過程中,會先將代碼讀取到內存中,檢查其是否有錯誤,然後將所有聲明在此進行標記,讓js解析器知道有這樣的一個名字,後面使用時便不會出現未定義的錯誤,這個標記的過程就是提升。

  • 變量的聲明
    var num;沒有與之對應的數據,僅僅是讓js解析器知道,你定義了一個num的變量。
  • 函數的聲明
    function foo(){};一個獨立的結構,沒有任何語句。首先是將函數名進行提升,讓js解析器知道有一個foo函數,接着是將函數名與函數體連接起來,注意這裏並不執行函數體。

代碼演示:

var num = 10;
function foo(){
  console.log(num);
}
foo();

預解析的過程(變量提升,函數提升):

var num;
function foo(){
  console.log(num)
}
num = 10;
foo();

代碼執行時,首先會執行 num = 10; 然後執行foo(),進行函數體,打印出num的值。此時的num訪問到的是全局中定義的num,所以num的值爲10.

作用域

以上代碼涉及到作用域的問題,所謂的域,表示的是範圍,所以作用域表示的是作用範圍,也就是一個名字在什麼地方可以使用,在什麼地方不可使用。

1、詞法作用域

在js中,採用的是詞法作用域,詞法作用域是指在編寫代碼的過程中體現出來的作用範圍,一旦代碼寫好了,不用執行,作用範圍就確定好了,

2、詞法作用域的規則

  • 函數允許訪問函數外的數據
  • 整個代碼結構中只有函數可限定作用域
  • 作用域規則首先使用提升規則分析
  • 若當前作用域中有名字了,就不考慮外面的名字

3、作用域鏈

只有函數可以構成作用域結構。只要存在代碼,就至少有一個作用域,即全局作用域。凡是代碼有函數,那麼這個函數就構成一個作用域,如果函數中還有函數,那麼在這個作用域中就又誕生一個作用域,那麼將這樣的所有作用域列出來,就可以有一個:函數內指向函數外的鏈式結構。

作用域鏈變量訪問規則:看變量在當前作用域中,是否有變量的定義與賦值,如果有,則直接使用;如果沒有,則到外面的作用域中查看,如果有,則停止查找,使用外面一層作用域中定義的變量或值,如果沒有,則繼續往外查找,知道最外層的全局,如果全局也沒有定義,則會報錯: xx is not defined。

閉包

什麼是閉包

閉包,是一個具有封閉功能與包裹功能的一個結構或空間。在js中,函數可以構成閉包。因爲函數在當前的作用域中是一個封閉的結構,具有封閉性;同時根據作用域規則,只允許函數內部訪問外部的數據,而外部無法訪問函數內部的數據,即函數具有封閉的對外不公開的特性,就像把一個東西包裹起來一樣,因此函數可以構成閉包。

閉包的基本結構

因爲閉包不允許外界訪問,因此要解決的問題是:間接訪問函數內部數據,獲得函數內部數據的使用權

1、寫一個函數,函數內定義一個新函數,返回新函數,用新函數獲得函數內部的數據
function foo(){
  var num = 123;
  function func(){
    return num;
  }
  return func;
}
var f = foo();
var res1 = f();
var res2 = f(); 
// 此時,foo只調用了一次,不會再內存中重新創建一個函數,而通過f,可以訪問並獲取num的值,那麼調用f,即可獲得一樣的num值

改良:
function foo(){
  var num = 123;
  return function(){
    return num;
  }
}
var f = foo();
var res1 = f();
var res2 = f();

再改良:
var f = (function foo(){
  var num = 123;
  return function (){
    return num;
  }
})();
var res1 = f();
var res2 = f();
2、寫一個函數,函數內定義一個對象,對象綁定一個或多個函數(方法),返回對象,利用對象的方法訪問函數內部的數據
function func(){
  var num1 = Math.random();
  var num2 = Math.random();
  return {
    num1: function(){
      return num1;
    },
    num2: function(){
      return num2;
    }
  }
}
var p = func();
console.log(p.num1());
console.log(p.num1());// 這兩個訪問到的是同一個隨機數

閉包的基本用法

如上面代碼演示的那樣,閉包可以通過返回函數來間接訪問到函數內的數據,這樣,閉包可以實現具有私有訪問空間的函數,保護私有的數據。

閉包的性能問題

函數定義的變量會在函數執行結束後自動回收,但是因爲閉包結構引出的數據經常會被外界所引用,這些數據將不會被回收,因此過多的閉包會消耗內存資源,影響性能。所以要謹慎使用閉包,可以在使用閉包時,如果不再使用某些變量了,一定要賦值一個null。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章