Awe JavaScript [1] 基本概念

前言

本文是 Awesome JavaScript 系列文章的第一篇,本系列文章主要爲 JavaScript 的一些常見知識點,是我在 JavaScript 學習過程當中的一些筆記。javascript


JavaScript 簡介

JavaScript 誕生於 1995 年,和博主同年哈哈。當時,它的主要目的是處理之前由服務器端語言(如 Perl)負責的一些輸入驗證操做。JavaScript 從一個簡單的輸入驗證器發展爲一門強大的編程語言,徹底出乎人們的預料。應該說,它既是一門很是簡單的語言,又是一門很是複雜的語言。html

1997 年,以 JavaScript 1.1 爲藍本的建議被提交給了歐洲計算機制造商協會(ECMA,European Computer Manufacturers Association)。不久後,該協會定義了一種名爲 ECMAScript 的新腳本語言的標準,即 ECMA-262。java

1998 年,ISO/IEC(International Organization for Standardization and International Electrotechnical Commission,國標標準化組織和國際電工委員會)也採用了 ECMAScript 做爲標準(即 ISO/IEC-16262)。自此之後,瀏覽器開發商就開始致力於將 ECMAScript 做爲各自 JavaScript 實現的基礎,也在不一樣程度上取得了成功。express

到如今呢,咱們能夠說 JavaScript 是一門專爲與網頁交互而設計的腳本語言,他其實由如下三部分組成:編程

  • ECMAScript,由 ECMA-262 定義,提供核心語言功能。
  • 文檔對象模型(DOM,Document Object Model),針對 XML 但通過擴展用於 HTML 的應用程序編程接口(API,Application Programming Interface)。提供訪問和操做網頁內容的方法和接口。
  • 瀏覽器對象模型(BOM,Browser Object Model),提供與瀏覽器交互的方法和接口。


在 HTML 中使用 JavaScript

JavaScript 放置位置

傳統的作法是將全部的 <script> 元素都放到頁面的 <head> 元素中。這樣作的目的是將全部的外部文件(包括 CSS 文件和 JavaScript 文件)的引用都放在相同的地方。可是這樣就意味着必須等到所有 JavaScript 代碼都被下載、解析和執行完成後,才能開始呈現頁面的內容(瀏覽器在遇到 <body> 標籤時纔開始呈現內容)。這種狀況下的用戶體驗就很是的很差。數組

其實咱們能夠將全部的 <script> 元素都放到頁面的 <body> 元素中頁面內容的後面,即 </body> 前。這樣在解析包含 JavaScript 代碼以前,頁面的內容將徹底呈如今瀏覽器中。而用戶也會由於瀏覽器窗口顯示空白頁面的時間縮短而感到打開頁面的速度加快了。瀏覽器

noscript 元素

早期瀏覽器都面臨一個特殊的問題,即當瀏覽器不支持 JavaScript 時如何讓頁面平穩退化。對這個問題的最終解決方案就是創造一個 <noscript> 元素,用以在不支持 JavaScript 的瀏覽器中顯示替代的內容。這個元素能夠包含可以出如今文檔 <body> 中的任何 HTML 元素(<script> 除外)。包含在 <noscript> 元素中的內容只有在瀏覽器不支持腳本或瀏覽器支持腳本可是腳本被禁用的狀況下才會顯示出來。服務器

<html>
  <head>
    <title>Example HTML Page</title>
    <script type="text/javascript" defer="defer" src="example1.js"></script>
    <script type="text/javascript" defer="defer" src="example1.js"></script>
  <head>
  <body>
    <noscript>
      <p>本頁面須要在瀏覽器支持(啓用)JavaScript。</p>
    </noscript>
  </body>
</html>複製代碼


基本概念

標識符

所謂標識符就是指變量、函數、屬性的名字,或者函數的參數。標識符能夠是按照下列格式規則組合起來的一或多個字符:編程語言

  • 第一個字符必須是一個字母、下劃線 _ 或一個美圓符號 $
  • 其餘字符能夠是字母、下劃線、美圓符號或數字;
  • 標識符中的字母能夠包含擴展的 ASCIIUnicode 字母字符,但不推薦這樣作。

註釋

註釋推薦像下面這樣寫:函數

// 單行註釋

/*
* 這是一個多行
* (塊級)註釋
*/複製代碼

嚴格模式

ECMAScript 5 引入了嚴格模式的概念,嚴格模式是爲 JavaScript 定義了一種不一樣的解析與操做模型。嚴格模式啓用方法以下:

function doSomething() {
 "use strict";
  //函數體
}複製代碼

"use strict"; 這行代碼實際上是一個編譯指示(pragma),用於高速支持的 JavaScript 引擎切換到嚴格模式。

變量

用 var 操做符定義的變量將成爲定義該變量的做用域中的局部變量。也就是說,若是在函數中使用 var 定義一個變量,那麼這個變量在函數退出後就會被銷燬。

function test() {
  var message = "hi";  //局部變量
}
test();
alert(message);       //錯誤!複製代碼
function test() {
  message = "hi";  //全局變量
}
test();
alert(message);       //"hi"複製代碼

不推薦濫用全局變量,由於在局部做用域中定義的全局變量很難維護。並且給未經聲明的變量賦值在嚴格模式下會致使拋出 ReferenceError 的錯誤。

可使用一條語句定義多個變量,只要把每一個變量(初始化與否都可)用逗號分隔開便可:

var message = "hi",
    found = false,
    age = 29;複製代碼

由於 ECMAScript 是鬆散類型的,於是使用不一樣類型初始化變量的操做能夠放在一條語句中完成。

注意,在嚴格模式下不能定義名爲 evalarguments 的變量,不然會致使語法錯誤。

數據類型

ECMAScript 中有五種簡單數據類型(基本數據類型):UndefinedNullBooleanNumberString。還有一種複雜數據類型 -- Object,在本質上,Object 是一組無序的明值對組成的。乍一看這幾種數據類型不足以表示全部數據,可是 ECMAScript 數據類型具備動態性,因此沒有必要再定義其餘類型的數據了。

typeof 操做符

返回值 含義
"undefined" 這個值未定義
"boolean" 這個值是布爾值
"string" 這個值是字符串
"number" 這個值是數值
"object" 這個值是對象或 null
"function" 這個值是函數
var message = "some string";
alert(typeof message);    //"string"
alert(typeof (message));  //"string"
alert(typeof 95);         //"number"複製代碼

上面幾個例子說明,typeof 操做符的操做數能夠是變量(message),也能夠是數值字面量。注 -- typeof 是一個操做符。

在 JavaScript 中,null 是一個 object,即 typeof null; 返回 object。這是設計的缺陷,在最初,使用標記位來區分對象類型和原始類型,對象型用 0 標識,原始型用 1 標識。致使了全零的 null 被識別爲 objectnull 被認爲是一個空的對象引用,也就是一個空的對象指針。這也正是使用 typeof 操做符檢測 null 值時會返回 object 的緣由。

在技術上講,函數在 ECMAScript 中是對象,不是一種數據類型。然而函數確實也有一些特殊的屬性,所以經過 typeof 操做符來區分函數和其餘對象是有必要的。

Undefined 類型

在 JavaScript 中,包含 undefined 值的變量與還沒有定義的變量仍是不同的。

var message;      //
alert(message);  //
alert(age);複製代碼
var message;
alert(typeof message);  //"undefined"
alert(typeof age);      //"undefined"複製代碼

即使未初始化的變量會自動被賦予 undefined 值,但顯示的初始化變量依然是明智的選擇。若是作到這一點,那麼當 typeof 操做符返回 undefined 值時,咱們就知道被檢測的變量是沒有被聲明仍是還沒有初始化。

對於未聲明的變量,只能執行一項操做即用 typeof 操做符檢測其數據類型(未聲明的變量調用 delet 不會報錯,但沒意義,並且在嚴格模式下也會報錯)。

未初始化和未聲明的變量的區別就是,在用 typeof 操做符檢測其數據類型時都顯示 undefined,可是在除此以外調用未聲明的變量時就會報錯。

由於在 JavaScript 中未定義和未聲明的變量用 typeof 操做符檢測其數據類型時都顯示 undefined,因此 DOM 相關函數都是返回 null,從 API 設計角度來說是合理的。

不管什麼狀況下,都沒有必要將一個變量的值顯示的設置爲 undefined

Null 類型

若是定義的變量準備在未來保存對象,那麼最好將該變量初始化爲 null 而不是其餘值。這樣只要檢查 null 值就能夠知道相應的變量是否已經保存了一個對象的引用,以下所示:

if(car != null) {
  //對 car 對象執行某些操做
}複製代碼

因此只要意在保存對象的變量尚未真正保存對象,就應該明確地讓該變量保存 null 值。

實際上,undefined 值是派生自 null 值的,所以 ECMA-262 規定對他們的相等性測試要返回 true

alert(null == undefined);      //true複製代碼

Number 類型

  • 由於保存浮點數值須要的內存空間是保存整數值的兩倍,因此 ECMAScript 會不失時機的將浮點數值轉換爲整數值。

  • ECMAScript 可以表示的數的範圍爲 Number.MIN_VALUE ~ Number.MAX_VALUE,在大多數瀏覽器中爲 5e-324 ~ 1.7976931348623157e+308。當程序執行時,數值超過正負範圍時會被分別轉化爲 Infinity-Infinity。想肯定一個數是否超出 JavaScript 數值範圍,能夠用 isInfinite() 函數。

var result = Number.MIN_VALUE + Number.MIN_VALUE;
alert(isFinite(result));     //false複製代碼
  • NaN 即非數值(Not a Number)是一個特殊值。用於表示一個原本要返回數值的操做數未返回數值的狀況(這樣就不會拋出錯誤了)。其有兩個特色,首先任何涉及 NaN 操做都會返回 NaN,這一點在多步計算中可能會致使問題。其次, NaN 與任何值都不相等,包括其自己。ECMAScript 也定義了 isNaN(); 函數。這個函數接收一個參數,這個參數能夠是任何類型的,而函數會幫咱們肯定這個參數是否 不是數值。函數檢查過程是 `isNaN(); => valueOf(); => toString();

  • 有三個能夠把非數值轉化爲數值的函數:Number()parseInt()parseFloat()。在使用 parseInt() 轉換數據類型時,爲了不錯誤解析,建議不管什麼時候都要明確指定基數。多數狀況下咱們要解析的都是是進制數,所以始終將 10 做爲第二個參數是十分必要的。

var num1 = Number("Hello world!");  //NaN
var num2 = Number("");              //0
var num3 = Number("000011");        //11
var num4 = Number(true);            //1

alert(num1);
alert(num2);
alert(num3);
alert(num4);複製代碼
var num1 = praseInt("10", 2);       //2 (按二進制解析)
var num1 = praseInt("10", 8);       //8 (按八進制解析)
var num1 = praseInt("10", 10);      //10 (按十進制解析)
var num1 = praseInt("10", 16);      //16 (按十六進制解析)複製代碼

parseFloat() 只解析十進制值,因此其沒有第二個參數。

var num1 = parseFloat("1234blue");    //1234 - integer
var num2 = parseFloat("0xA");         //0
var num3 = parseFloat("22.5");        //22.5
var num4 = parseFloat("22.34.5");     //22.34
var num5 = parseFloat("0908.5");      //908.5
var num6 = parseFloat("3.125e7");     //31250000

alert(num1);
alert(num2);
alert(num3);
alert(num4);
alert(num5);
alert(num6);複製代碼

String 類型

字符串由雙引號或單引號表示均可以,在 ECMAScript 中的這兩種語言形式沒有什麼區別。

任何字符串的長度均可以經過訪問其 length 屬性取得,若是字符串中包含雙字節字符,那麼 length 屬性可能不會精確的返回字符串中的字符數目。

var text = "This is the letter sigma: \u030a.";
alert(text.length);   //輸出 28複製代碼

ECMAScript 中的字符串是不可變的,若是要改變某個變量保存的字符串,首先要銷燬原來的字符串,而後再用另外一個包含新值的字符串填充該變量,這個過程是在後臺完成的,這也就是某些舊版本瀏覽器在拼接字符串的時候速度很慢的緣由了。

要把一個值轉換爲字符串有兩種方法,第一種是 toString() 方法。數值、布爾值、對象和字符串值都有相應的 toString() 方法,可是 nullundefined 值沒有。通常調用 toString() 方法時不用傳遞參數,可是他也能夠傳遞參數。

var age = 11;
var ageAsString = age.toString();    //the string "11"
var found = true;
var foundAsString = found.toString(); //the string "true"

alert(ageAsString);
alert(typeof ageAsString);
alert(foundAsString);
alert(typeof foundAsString);複製代碼
var num = 10;
alert(num.toString());       //"10"
alert(num.toString(2));      //"1010"
alert(num.toString(8));      //"12"
alert(num.toString(10));     //"10"
alert(num.toString(16));     //"a"複製代碼

在不知道要轉換的值是否是 nullundefined 的狀況下可使用第二種方法:轉型函數 String()。使用這種方法時,若是值有 toString() 方法則會調用該方法,沒有的話就按本方法規則執行。

var value1 = 10;
var value2 = true;
var value3 = null;
var value4;

alert(String(value1));     //"10"
alert(String(value2));     //"true"
alert(String(value3));     //"null"
alert(String(value4));     //"undefined"複製代碼

Object 類型

ECMAScript 中的對象其實就是一組數據和功能的集合。

var o = new Object();複製代碼


操做符

在 ECMAScript 中,當對數值應用位操做符時,後臺發生以下的轉換過程:64 位的數值被轉換爲 32 位數值,而後執行位操做,最後再將 32 位的結果轉換回 64 位數值。可是這個轉換過程會致使特殊的 NaN 和 Infinity 值應用位操做時,這兩個值會被當成 0 來處理。對非數值能夠先使用 Number() 函數將該值轉換爲一個數值,而後再應用位操做。

var num1 = 25;             //binary 00000000000000000000000000011001
var num2 = ~num1;          //binary 11111111111111111111111111100110
alert(num2);               //-26複製代碼

按位非操做的本質就是操做數的負值減一。

左移操做:左移操做符爲 <<,左移不會影響操做數的符號位。

var oldValue = 2;             //equal to binary 10
var newValue = oldValue << 5; //equal to binary 1000000 which is decimal 64
alert(newValue);              //64複製代碼

右移操做分爲有符號 >> 和無符號 >>> 兩種。對於正數來講,這兩種方法的結果同樣。但對於負數來講,無符號右移是以 0 填充空位,而不是像有符號右移那樣以符號位的值來填充空位。

var oldValue = -64;              //equal to binary 11111111111111111111111111000000
var newValue = oldValue >>> 5;   //equal to decimal 134217726
alert(newValue);                 //134217726複製代碼

咱們能夠利用邏輯或的行爲特性來避免爲變量賦 nullundefined 值。例如:

var myObject = preferredObject || backupObject;複製代碼

上面這段代碼,若是 preferredObject 的值不是 null,那麼它的值將被賦給 myObject;若是是 null,則將 backupObject 的值賦給 myObject。ECMAScript 程序的賦值語句經常使用這種模式。

加性操做符有如下特性:+0+0 結果爲 +0-0-0 結果爲 -0+0-0 結果爲 +0。若是兩個操做數都是字符串,則將第二個操做數與第一個操做數拼接起來。若是隻有一個操做數是字符串,則將另外一個操做數轉換爲字符串,而後再將兩個字符串拼接起來。

var result1 = 5 + 5;     //two numbers
alert(result1);           //10
var result2 = 5 + "5";   //a number and a string
alert(result2);           //"55"複製代碼
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + num1 + num2;
alert(message);    //"The sum of 5 and 10 is 510"複製代碼
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + (num1 + num2);
alert(message);    //"The sum of 5 and 10 is 15"複製代碼

減性操做符有如下特性:+0+0 結果爲 +0-0+0 結果爲 -0-0+0 結果爲 +0

var result1 = 5 - true;    //4 because true is converted to 1
var result2 = NaN - 1;     //NaN
var result3 = 5 - 3;       //2
var result4 = 5 - "";      //5 because "" is converted to 0
var result5 = 5 - "2";     //3 because "2" is converted to 2
var result6 = 5 - null;    //5 because null is converted to 0複製代碼

相等操做符有相等 == 和不相等 !=、全等 === 和不全等 !== 兩種。前者先轉換再比較,後者僅比較不轉換。除此以外無區別。轉換指轉換成數值。

var result1 = ("55" == 55);    //true ?equal because of conversion
var result2 = ("55" === 55);   //false ?not equal because different data types

var result3 = ("55" != 55);    //false ?equal because of conversion
var result4 = ("55" !== 55);   //true ?not equal because different data types

alert(null == undefined);    //true
alert(null === undefined);   //false

alert("NaN" == NaN);        //false
alert("NaN" === NaN);       //false
alert(NaN == NaN);          //false
alert(NaN === NaN);         //false
alert(NaN != NaN);          //true
alert(NaN !== NaN);         //true

alert(false == 0);          //true
alert(false === 0);         //false
alert(true == 1);           //true
alert(true === 1);          //false

alert(null == 0);           //false
alert(undefined == 0);      //false

alert(5 == "5");            //true
alert(5 === "5");           //false複製代碼

注意:null == undefined 會返回 true,而 null === undefined 會返回 false,由於他們是不一樣類型的值。因爲相等和不相等操做符存在類型轉換問題,而爲了保持代碼中數據類型的完整性,咱們推薦使用全等和不全等操做符。

條件操做符:

var max = (num1 > num2) ? num1 : num2;複製代碼


語句

  • if 語句do-while 語句while 語句for 語句for-in 語句lable 語句break 和 continue 語句with 語句switch 語句

  • 由於 ECMAScript 中不存在塊級做用域,所以在循環內部定義的變量也能夠在外部訪問到。例如:

var count = 10;
for (var i=0; i < count; i++){
    alert(i);
}
alert(i);    //10複製代碼
  • for-in語句是一種精準的迭代語句,能夠用來枚舉對象屬性。用法是:
for (property in wxpression) statement複製代碼

下面是一個示例:這個例子循環顯示 BOM 中 window 對象的全部屬性。

for (var propName in window) {
  document.wright(propName);
}複製代碼

若是要迭代的對象的變量值爲 nullundefinedfor-in 語句會拋出錯誤。ECMAScript 5 已經更正了這一行爲,對這種狀況再也不拋出錯誤,而只是不執行循環體。爲了保證最大限度兼容性,建議在使用 for-in 循環以前先檢查確認該對象的值不是 nullundefined

  • lable 語句能夠在代碼中添加標籤,以便未來使用。語法爲:
lable: statement;複製代碼

代碼示例:這個例子中定義的 start 標籤能夠在未來由 breakcontinue 語句引用。加標籤的語句通常都要與 for 語句等循環語句配合使用。

start: for (var - = 0; i < count; i++) {
}複製代碼

下面這段代碼使得 break 語句不只會退出內部的 for 語句,並且也會退出外部的 for 語句。

var num = 0;

outermost:
for (var i=0; i < 10; i++) {
  for (var j=0; j < 10; j++) {
    if (i == 5 && j == 5) {
      break outermost;
    }
    num++;
  }
}

alert(num);    //55複製代碼
var num = 0;

outermost:
for (var i=0; i < 10; i++) {
  for (var j=0; j < 10; j++) {
    if (i == 5 && j == 5) {
        continue outermost;
    }
    num++;
  }
}

alert(num);    //95複製代碼
  • with 語句的做用是將代碼的做用域設置到一個特定的對象中,語法以下:
with (expression) statement;複製代碼

定義 with 語句的目的是簡化屢次編寫同一個對象的工做,以下面的例子所示:

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;複製代碼

with 語句寫的話就能夠簡化成下面這樣:

with (location) {
  var qs = search.substring(1);
  var hostName = hostname;
  var url = href;
}複製代碼

注意:嚴格模式下不容許使用 with 語句,不然將視爲語法錯誤。同時,大量使用這種語句會致使性能降低,同時也會給調試代碼形成困難,所以在開發大型應用程序時不建議使用 with 語句。

  • switch 語句,雖然 ECMAScript 的 switch 語句是借鑑其餘語言的,可是也有其特點。能夠在 ECMAScript 的 switch 語句中使用任何數據類型。其次,每個 case 的值不必定是常量,能夠是變量,也能夠是表達式。
switch ("hello world") {
  case "hello" + " world": 
    alert("Greeting was found.");
    break;
  case "goodbye": 
    alert("Closing was found.");
    break;
  default: 
    alert("Unexpected message was found.");
}複製代碼
var num = 25;
switch (true) {
  case num < 0: 
    alert("Less than 0.");
    break;
  case num >= 0 && num <= 10: 
    alert("Between 0 and 10.");
    break;
  case num > 10 && num <= 20: 
    alert("Between 10 and 20.");
    break;
  default: 
    alert("More than 20.");
}複製代碼


函數

對於函數的返回值,推薦的作法是要麼讓函數始終都返回一個值,要麼永遠都不要返回值,不然,若是函數有時候返回值,有時候不返回值,會給調試代碼帶來不便。

ECMAScript 不介意你傳遞的參數個數和參數的數據類型,由於 ECMAScript 中的參數只在內部是一個數組來表示的。實際上在函數體內能夠經過 arguments 對象來訪問這個參數數組,從而得到傳遞給函數的每個參數。arguments 對象只是與數組相似但並非 Array 的實例。

沒有傳遞值的命名參數將自動被賦予 undefined 值,這就和定義變量但爲初始化相似。

在 ECMAScript 中,定義了兩個名字相同的函數,則該名字只屬於後定義的函數。

相關文章
相關標籤/搜索