javascript入門


JavaScript 是一種動態類型語言,也就是說,變量的類型沒有限制,變量可以隨時更改類型。

數據類型

JavaScript 語言的每一個值,都屬於某一種數據類型。JavaScript 的數據類型,共有六種。(ES6 又新增了第七種 Symbol 類型的值)

  • 原始類型:數值(number):整數和小數(比如1和3.14)
  • 原始類型:字符串(string):文本(比如Hello World)。
  • 原始類型:布爾值(boolean):表示真僞的兩個特殊值,即true(真)和false(假)
  • 合成類型:對象(object):各種值組成的集合
  • undefined:表示“未定義”或不存在,即由於目前沒有定義,所以此處暫時沒有任何值
  • null:表示空值,即此處的值爲空。

只是聲明變量而沒有賦值,則該變量的值是undefined。undefined是一個特殊的值,表示“無定義”。


變量提升

:JavaScript 引擎的工作方式是,先解析代碼,獲取所有被聲明的變量,然後再一行一行地運行。這造成的結果,就是所有的變量的聲明語句,都會被提升到代碼的頭部,這就叫做變量提升(hoisting)


函數

函數是處理數據的方法,但是JavaScript 語言將函數看作一種值, 把它當成一種數據類型,可以賦值給變量,與其它值(數值、字符串、布爾值等等)地位相同。凡是可以使用值的地方,就能使用函數。由於函數與其他數據類型地位平等,所以在 JavaScript 語言中又稱函數爲第一等公民

JavaScript 引擎將函數名視同變量名,所以採用function命令聲明函數時,整個函數會像變量聲明一樣,被提升到代碼頭部。

function命令聲明的代碼區塊,就是一個函數

function f1() {}
f1.name // "f1"

var f2 = function () {};
f2.name // "f2"

var f3 = function myName() {};
f3.name // 'myName'

作用域

JavaScript 只有兩種作用域:一種是全局作用域,變量在整個程序中一直存在,所有地方都可以讀取;另一種是函數作用域,變量只在函數內部存在。
ES6 又新增了塊級作用域,

  • 全局變量(global variable) 函數外部聲明的變量,它可以在函數內部讀取。
  • 局部變量”(local variable) 在函數內部定義的變量,外部無法讀取, 會在該作用域內覆蓋同名全局變量

閉包

閉包(closure) 是 JavaScript 語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現。
函數內部聲明的變量,函數外是無法讀取, 只有通過變通方法才能實現。那就是在函數的內部,再定義一個函數
閉包的最大用處有兩個,

  1. 可以讀取函數內部的變量,封裝對象的私有屬性和私有方法
  2. 讓這些變量始終保持在內存中,即閉包可以使得它誕生環境一直存在。

注意,外層函數每次運行,都會生成一個新的閉包,而這個閉包又會保留外層函數的內部變量,所以內存消耗很大。因此不能濫用閉包,否則會造成網頁的性能問題。

function f1() {
  var n = 999;
  function f2() {
    console.log("函數f2就是閉包,可以讀取變量n:" + n );
  }
  return f2;
}

立即調用的函數表達式(IIFE)

圓括號()是一種運算符,跟在函數名之後,表示調用該函數
但是想在定義函數之後立即調用該函數。在函數的定義之後加上圓括號會報錯,原因是會出現歧義:function這個關鍵字即可以當作語句,也可以當作表達式
而JavaScript 引擎規定,如果function關鍵字出現在行首,一律解釋成語句。因此,JavaScript 引擎看到行首是function關鍵字之後,認爲這一段都是函數的定義,不應該以圓括號結尾,所以就報錯了。
解決方法就是不要讓function出現在行首,讓引擎將其理解成一個表達式。最簡單的處理,就是將其放在一個圓括號裏面

// 語句
function f() {}
// 表達式
var f = function f() {}

//錯誤寫法
function(){ /* code */ }();// SyntaxError: Unexpected token (
//IIFE正確寫法
(function(){ /* code */ }());
(function(){ /* code */ })();
//避免污染全局變量
(function () {
  var tmp = newData;
  processData(tmp);
  storeData(tmp);
}());

通常情況下,只對匿名函數使用這種“立即執行的函數表達式”。它的目的有兩個:

  1. 一是不必爲函數命名,避免了污染全局變量;
  2. 二是 IIFE 內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。

對象(object)

對象是 JavaScript 語言的核心概念,也是最重要的數據類型。
對象就是一組“鍵值對”(key-value)的集合,
對象的每一個鍵名又稱爲“屬性”(property),
如果一個屬性的值爲函數,通常把這個屬性稱爲“方法”,它可以像函數那樣調用。

var obj = {
  //obj對象的屬性foo
  'foo': 'Hello',
  //obj對象的方法p
  p: function (x) {
    return 2 * x;
  }
};

對象採用大括號表示, JavaScript 引擎會產生歧義: 是對象還是代碼塊
爲了避免這種歧義,JavaScript 引擎的做法是,如果遇到這種情況,無法確定是對象還是代碼塊,一律解釋爲代碼塊。
如果要解釋爲對象,最好在大括號前加上圓括號。因爲圓括號的裏面只能是表達式

{ foo: 123 } // 代碼塊  標籤foo指向表達式123
({ foo: 123 }) // 對象  一個包含foo屬性的對象

嚴格模式

早期的 JavaScript 語言有很多設計不合理的地方,但是爲了兼容以前的代碼,又不能改變老的語法,只能不斷添加新的語法,引導程序員使用新語法。

嚴格模式是從 ES5 進入標準的,主要目的有以下幾個。

  • 明確禁止一些不合理、不嚴謹的語法,減少 JavaScript 語言的一些怪異行爲。
  • 增加更多報錯的場合,消除代碼運行的一些不安全之處,保證代碼運行的安全。
  • 提高編譯器效率,增加運行速度。
  • 爲未來新版本的JavaScript 語法做好鋪墊。
//老版本的引擎會把它當作一行普通字符串,加以忽略。新版本的引擎就會進入嚴格模式。
'use strict';
//嚴格模式可以用於整個腳本,也可以只用於單個函數。
  1. 顯式報錯
    1. 只讀屬性不可寫
      設置字符串的length屬性,會報錯
    2. 只有取值器(getter)、沒有存值器(setter)的屬性賦值,會報錯
    3. 禁止擴展的對象不可擴展
    4. eval、arguments 不可用作標識名
    5. 函數不能有重名的參數
    6. 禁止八進制的前綴0表示法
  2. 增強的安全措施
    1. 全局變量顯式聲明
    2. 禁止 this 關鍵字指向全局對象
    3. 函數內部不得使用fn.caller、fn.arguments,否則會報錯。這意味着不能在函數內部得到調用棧了
    4. 函數內部使用arguments.callee、arguments.caller將會報錯。
    5. 禁止刪除變量
  3. 靜態綁定
    某些情況下,只允許靜態綁定。也就是說,屬性和方法到底歸屬哪個對象,必須在編譯階段就確定。
    1. 禁止使用 with 語句
    2. 創設 eval 作用域
    3. arguments 不再追蹤參數的變化
  4. 向下一個版本的 JavaScript 過渡
    1. 非函數代碼塊不得聲明函數
    2. 嚴格模式新增了一些保留字(implements、interface、let、package、private、protected、public、static、yield等)
發佈了28 篇原創文章 · 獲贊 22 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章