1. 程式人生 > 其它 >創優視覺科技企業網頁設計只需用一種顏色?

創優視覺科技企業網頁設計只需用一種顏色?

js的作用域與作用域鏈

    js的作用域

作用域(scope),程式設計概念,通常來說,一段程式程式碼中所用到的名字並不總是有效/可用的,而限定這個名字的可用性的程式碼範圍就是這個名字的作用域。

事例:

  var scope="global";

  function t(){

  console.log(scope);

  var scope="local"

  console.log(scope);

  }

t();

第一句輸出的是: "undefined",而不是 "global"

第二句輸出的是:"local"

我們可能會認為第一句會輸出:"global",因為程式碼還沒執行var scope="local",所以肯定會輸出“global"。

這想法完全沒錯,只不過用錯了物件。我們首先要區分Javascript的函式作用域與java等的塊級作用域

在java中,花括號內中的每一段程式碼都具有各自的作用域,而且變數在宣告它們的程式碼段之外是不可見的。

Javascript壓根沒有塊級作用域,而是函式作用域.

所謂函式作用域就是:

變數在宣告它們的函式體以及這個函式體巢狀的任意函式體內都是有定義的。

所以根據函式作用域的意思,可以將上述程式碼重寫如下:

var scope="global";

function t(){

var scope;

console.log(scope);

scope="local"

console.log(scope);

}

t();

第一句輸出的是: "undefined",而不是 "global"

第二講輸出的是:"local"

t函式裡面的 scope宣告覆蓋了全域性的scope , 但是還沒有賦值,所以輸出:”undefined“。

為什麼說Js沒有塊級作用域呢,有以下程式碼為證:

  var name="global";

  if(true){

  var name="local";

  console.log(name)

  }

  console.log(name);

都輸出是“local", 如果有塊級作用域,明顯if語句將建立區域性變數name,並不會修改全域性name,可是沒有這樣,所以Js沒有塊級作用域。

如此,理解下面程式碼就變得很容易了

function t(flag){

if(flag){

var s="ifscope";

for(var i=0;i<2;i++) ;

}

console.log(i);

console.log(s);

}

t(true);

結果是 2 ifscope

    變數作用域

先看事例:

function t(flag){

if(flag){

s="ifscope"; //window.s 這個變數不加var 預設是全域性變數的,而且是頂層物件的屬性。

for(var i=0;i<2;i++) ;

}

console.log(i);

}

t(true);

console.log(s);

最後結果是:ifscope

這主要是js中沒有用var宣告的變數都是全域性變數,而且是頂層物件的屬性

所以用console.log(window.s) 也是會輸出:ifcobfig

i = 2;

alert(window.i); // 沒有,受制於函式的作用域,i不屬window的屬性

當使用var宣告一個變數時候,建立的這個屬性是不可配置的,也就是說無法通過delete運算子刪除的

var name = 1 ->不可刪除

sex = 'girl' ->可刪除

this.age = 22 ->可刪除

比如:delete sex;//可刪除變數sex

  1. 函式與變數宣告區別

事例1:

console.log(add());//18;函式宣告全域性生效,全域性有定義

function add(){

i = 18;

return i;

}

事例2:

console.log(add());//報錯,找不到add這個方法,函式表示式,只有在宣告的時候才定義。

var add=function(){

i = 18;

return i;

}

事例3:

console.log(n);//undefined ,變數被var宣告以後,作用域中全域性有定義,最多就是沒有值。

var n = 100;

事例4:

console.log(n);//報錯,沒有被var宣告的變數,作為屬性存在的時候,它只有在出現的時候才有定義。

n = 100;

    作用域鏈

事例:

name="lwy";

function t(){

var name="tlwy";

function s(){

var name="slwy";

console.log(name); //slwy

}

function ss(){

console.log(name); //tlwy

}

s();

ss();

}

t();

console.log(name); //lwy

當執行s時,將建立函式s的執行環境(呼叫物件),並將該物件置於連結串列開頭,然後將函式t的呼叫物件連結在之後,最後是全域性物件。然後從連結串列開頭尋找變數name,很明顯

name是"slwy"。

但執行ss()時,作用域鏈是: ss()->t()->window,所以name是”tlwy"。

下面看一個很容易犯錯的例子:

<html>

  <head>

    <script type="text/javascript">

      function buttonInit(){

      for(var i=1;i<4;i++){

      var b=document.getElementById("button"+i);

      b.addEventListener("click",function(){ alert("Button"+i);},false);

      }

      }

      window.onload=buttonInit;

    </script>

  </head>

  <body>

    <button id="button1">Button1</button>

    <button id="button2">Button2</button>

    <button id="button3">Button3</button>

  </body>

</html>

當文件載入完畢,給幾個按鈕註冊點選事件,當我們點選按鈕時,會彈出什麼提示框呢?

很容易犯錯!三個按鈕都是彈出:"Button4"。

當註冊事件結束後,i的值為4,當點選按鈕時,事件函式即function(){ alert("Button"+i);}這個匿名函式中沒有i,根據作用域鏈,所以到buttonInit函式中找,此時i的值為4,所以彈出”button4“。

  1. 垃圾回收機制

記憶體管理機制就是分配記憶體管理,每種程式語言都有它的記憶體管理機制,JavaScript的記憶體管理機制是:記憶體基元在變數(物件,字串等等)建立時分配,然後在他們不再被使用時“自動”釋放。後者被稱為垃圾回收。

(自動 是容易讓人混淆,迷惑的,並給 JavaScript(和其他高階語言)開發者一個印象:他們可以不用關心記憶體管理。然而這是錯誤的。)

在js中的分配的記憶體一般有如下的生命週期:

記憶體分配(當我們宣告變數,函式,物件時系統自動為他們分配記憶體)

記憶體使用(使用變數,函式等)

記憶體回收(使用完畢,由垃圾回收機制自動回收不再使用的記憶體)

全域性作用域的回收

整個script標籤裡,頁面開啟時建立全域性作用域,頁面關閉的時候刪除

函式作用域的回收

函式裡面,函式呼叫的時候建立函式作用域,呼叫完刪除

  1. with語句

說到作用域鏈,不得不說with語句。with語句的作用是將程式碼的作用域設定到一個特定的物件中。

它主要用來臨時擴充套件作用域鏈,將語句中的物件新增到作用域的頭部。

看下面程式碼

person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};

with(person.wife){

console.log(name);//此時可以直接使用person物件的name屬性。

}

with語句將person.wife新增到當前作用域鏈的頭部,所以輸出的就是:“lwy".

with語句結束後,作用域鏈恢復正常。

with 語句用於設定程式碼在特定物件中的作用域。

語法:

with (expression) statement

提示:with 語句是執行緩慢的程式碼塊,尤其是在已設定了屬性值時。大多數情況下,最好避免使用它。

  知識拓展

this指向問題:

this是一個關鍵字,不是變數,也不是屬性名。JavaScript的語法不允許給this賦值(報錯)。

JavaScript的 this 關鍵詞指的是它所屬的物件。

它是函式執行時,在函式體內部自動生成的一個物件,只能在函式體內部使用。

它擁有不同的值,具體是什麼,取決於它的使用位置:

² 在方法中,this 指的是所有者物件。

² 單獨的情況下,this 指的是全域性物件。

² 在函式中,this 指的是全域性物件。

² 在函式中,嚴格模式下,this 是 undefined。

² 在事件中,this 指的是接收事件的元素。

像 call() 和 apply() 這樣的方法可以將 this 引用到任何物件。

總結一句話:這個方法屬於哪個物件,它裡面的this就指向誰(也就是說,是它所屬的物件)。

事例:

var obj = {

foo: function () {

console.log(this);//this指的就是obj這個物件,因為這個方法foo是屬於obj物件的

}

};

function test(){

console.log(this);//this指的就是window全域性物件,test方法屬於window物件的方法

}

test();

  • obj.foo();

但是,

關鍵字this和變數有所不同,首先它沒有作用域的限制(誰都可以使用this,但是它們不一定是同一個物件),再次巢狀的函式不會從呼叫它的函式中繼承this

事例:

var obj = {

foo: function () {

console.log(this);//this指向obj

function test(){

console.log(this);//this指向window

}

test();

},

bar: 1

};

obj.foo()