JavaScript 概述
ECMAScript 和 JavaScript的關系
1996年11月,JavaScript 的創造者 Netscape(網景) 公司,決定將 JavaScript 提交給國際標準化組織 ECMA ,希望這門語言能夠成為國際標準。次年,ECMA發布262號標準文件(ECMA-262)的第一版,規定了瀏覽器腳本語言的標準,并將這種語言稱為ECMAScript,這個版本就是1.0版。
該標準一開始就是針對JavaScript語言制定的,但是沒有稱其為JavaScript,有兩個方面的原因。一是商標,JavaScript本身已被Netscape注冊為商標。二是想體現這門語言的制定者是ECMA,而不是Netscape,這樣有利于保證這門語言的開發性和中立性。
因此ECMAScript和JavaScript的關系是,前者是后者的規格,后者是前者的一種實現。JavaScript = ECMAScript + JavaScript自己特有的東西(BOM+DOM)
ECMAScript的歷史
年份 | 名稱 | 描述 |
1997 | ECMAScript 1 | 第一個版本 |
1998 | ECMAScript 2 | 版本變更 |
1999 | ECMAScript 3 | 添加正則表達式 添加try/catch |
? | ECMAScript 4 | 沒有發布 |
2009 | ECMAScript 5 | 添加”strict mode”嚴格模式 添加JSON支持 |
2011 | ECMAScript 5.1 | 版本變更 |
2015 | ECMAScript 6 | 添加類和模塊 |
2016 | ECMAScript 7 | 增加指數運算符(**) 增加Array.prototype.includes |
注:ES6就是指ECMAScript 6。
盡管 ECMAScript 是一個重要的標準,但它并不是 JavaScript 唯一的部分,當然,也不是唯一被標準化的部分。實際上,一個完整的 JavaScript 實現是由以下 3 個不同部分組成的:
- 核心(ECMAScript)?
- 文檔對象模型(DOM) Document object model (整合js,css,html)
- 瀏覽器對象模型(BOM) Broswer object model(整合js和瀏覽器)
簡單地說,ECMAScript 描述了JavaScript語言本身的相關內容。
- JavaScript 是腳本語言
- JavaScript 是一種輕量級的編程語言。
- JavaScript 是可插入 HTML 頁面的編程代碼。
- JavaScript 插入 HTML 頁面后,可由所有的現代瀏覽器執行。
- JavaScript 很容易學習。
JavaScript語言規范
JavaScript引入方式
Script標簽內寫代碼
<script>// 在這里寫你的JS代碼
</script>
引入額外的JS文件
<script>可以定義在html頁面的任何地方。但是定義的位置會影響執行順序。
? ? ? ? <script>可以定義多個。
<script src="myscript.js"></script>
注釋(注釋是代碼之母)- 和 java 注釋基本一樣
// 這是單行注釋/*這是多行注釋
*/
結束符
JavaScript中的語句要以分號(;)為結束符。
JavaScript語言基礎
變量聲明
- JavaScript的變量名可以使用_,數字,字母,$組成,不能以數字開頭。
- 聲明變量使用?var 變量名;?的格式來進行聲明
- 變量名是區分大小寫的。
- 推薦使用駝峰式命名規則。
- 保留字不能用做變量名。
var name = "lp";
var age = 18;
ES6新增了 let 命令,用于聲明變量。其用法類似于 var,但是所聲明的變量只在 let 命令所在的代碼塊內有效。例如:for 循環的計數器就很適合使用 let 命令。
for (let i=0;i<arr.length;i++){...}
ES6新增 const 用來聲明常量。一旦聲明,其值就不能改變。
const PI = 3.1415;
PI // 3.1415
PI = 3 // TypeError: "PI" is read-only
保留字列表:
abstract
boolean
byte
char
class
const
debugger
double
enum
export
extends
final
float
goto
implements
import
int
interface
long
native
package
private
protected
public
short
static
super
synchronized
throws
transient
volatile
運算符
算數運算符
+ - * / % ++ --
比較運算符
> >= < <= != == === !==
注意:
1 == “1” // true
1 === "1" // false
邏輯運算符
&& || !
賦值運算符
= += -= *= /=
流程控制
if-else
var a = 10;
if (a > 5) {console.log("yes");
} else {console.log("no");
}
if-else if-else
var a = 10;
if (a > 5) {console.log("a > 5");
} else if (a < 5) {console.log("a < 5");
} else {console.log("a = 5");
}
switch
var day = new Date().getDay();
switch (day) {case 0:console.log("Sunday");break;case 1:console.log("Monday");break;default:console.log("...")
}
switch中的case子句通常都會加break語句,否則程序會繼續執行后續case中的語句。
for
for (var i=0;i<10;i++) {console.log(i);
}
while
var i = 0;
while (i < 10) {console.log(i);i++;
}
三元運算
var a = 1;
var b = 2;
var c = a > b ? a : b
函數
函數定義
JavaScript 中的函數和 Python 中的非常類似,只是定義方式有點區別。
// 普通函數定義
function f1() {console.log("Hello world!");
}// 帶參數的函數
function f2(a, b) {console.log(arguments); // 內置的arguments對象console.log(arguments.length);console.log(a, b);
}// 帶返回值的函數
function sum(a, b){return a + b;
}
sum(1, 2); // 調用函數// 匿名函數方式
var sum = function(a, b){return a + b;
}
sum(1, 2);// 立即執行函數
(function(a, b){return a + b;
})(1, 2);
補充:ES6中允許使用“箭頭”(=>)定義函數。
var f = v => v;
// 等同于
var f = function(v){return v;
}
如果箭頭函數不需要參數或需要多個參數,就是用圓括號代表參數部分:
var f = () => 5;
// 等同于
var f = function(){return 5};var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2){return num1 + num2;
}
函數中的arguments參數
function add(a,b){console.log(a+b);console.log(arguments.length)
}add(1,2)
注意:函數只能返回一個值,如果要返回多個值,只能將其放在數組或對象中返回。
函數的全局變量和局部變量
局部變量:在JavaScript函數內部聲明的變量(使用 var)是局部變量,所以只能在函數內部訪問它(該變量的作用域是函數內部)。只要函數運行完畢,本地變量就會被刪除。
全局變量:在函數外聲明的變量是全局變量,網頁上的所有腳本和函數都能訪問它。
變量生存周期:
- JavaScript變量的生命期從它們被聲明的時間開始。
- 局部變量會在函數運行以后被刪除。
- 全局變量會在頁面關閉后被刪除。
作用域
首先在函數內部查找變量,找不到則到外層函數查找,逐步找到最外層。
幾個例子:
// 1.
var city = "BeiJing";
function f() {var city = "ShangHai";function inner(){var city = "ShenZhen";console.log(city);}inner();
}f(); //輸出結果是?ShenZhen// 2.
var city = "BeiJing";
function Bar() {console.log(city);
}
function f() {var city = "ShangHai";return Bar;
}
var ret = f();
ret(); // 打印結果是?BeiJing// 3.閉包
var city = "BeiJing";
function f(){var city = "ShangHai";function inner(){console.log(city);}return inner;
}
var ret = f();
ret();
詞法分析(嘗試理解)
JavaScript中在調用函數的那一瞬間,會先進行詞法分析。
詞法分析的過程:
當函數調用的前一瞬間,會先形成一個激活對象:Avtive Object(AO),并會分析以下3個方面:
- 函數參數,如果有,則將此參數賦值給AO,且值為undefined。如果沒有,則不做任何操作。
- 函數局部變量,如果AO上有同名的值,則不做任何操作。如果沒有,則將此變量賦值給AO,并且值為undefined。
- 函數聲明,如果AO上有,則會將AO上的對象覆蓋。如果沒有,則不做任何操作。
函數內部無論是使用參數還是使用局部變量都到AO上找。看兩個例子:
var age = 18;
function foo(){console.log(age);var age = 22;console.log(age);
}
foo(); // 問:執行foo()之后的結果是?undefined 和 22// 第二題:
var age = 18;
function foo(){console.log(age);var age = 22;console.log(age);function age(){console.log("呵呵");}console.log(age);
}
foo(); // 執行后的結果是?
? age(){console.log("呵呵");} 和 22 和22
詞法分析過程:
1、分析參數,有一個參數,形成一個 AO.age=undefine;
2、分析變量聲明,有一個 var age, 發現 AO 上面已經有一個 AO.age,因此不做任何處理
3、分析函數聲明,有一個 function age(){...} 聲明, 則把原有的 age 覆蓋成 AO.age=function(){...};最終,AO上的屬性只有一個age,并且值為一個函數聲明執行過程:
注意:執行過程中所有的值都是從AO對象上去尋找1、執行第一個 console.log(age) 時,此時的 AO.age 是一個函數,所以第一個輸出的一個函數
2、這句 var age=22; 是對 AO.age 的屬性賦值, 此時AO.age=22 ,所以在第二個輸出的是 22
3、同理第三個輸出的還是22, 因為中間再沒有改變age值的語句了