今天主要來介紹一些JavaScript中一些基本的語句語法,首先我就這些語句語法列出了一個(gè)表,讓我們首先來看一下。
| 語句 | 語法 | 用途 |
|---|---|---|
| var | var name =[=expr][,...]; |
聲明并初始化一個(gè)或者多個(gè)變量; |
| let | let name =[=expr][,...]; |
聲明并初始化一個(gè)或者多個(gè)變量; |
| const | const name =[=expr][,...]; |
聲明并初始化一個(gè)或者多個(gè)常量; |
| class | class name {functions} |
聲明并初始化一個(gè)類; |
| extends | class name extends name{functions} |
繼承一個(gè)類; |
| function | function name([param[],...]){statement}; |
聲明一個(gè)函數(shù) |
| return | return [expression]; |
在函數(shù)執(zhí)行完成之后返回一個(gè)值; |
| if/else | if(expression){statement}else{statement}; |
用于條件判斷選擇執(zhí)行某個(gè)statement; |
| if/ else if /else | if(expression){statement}else if(expression){statement}else{statement}; |
if/else的強(qiáng)化版 |
| while | while(expression){statement}; |
基本的循環(huán)結(jié)構(gòu); |
| do/while | do{statement}while(expression); |
while循環(huán)的一種表現(xiàn)形式; |
| for | for(init;test;incr){statement}; |
一種簡(jiǎn)寫的for循環(huán); |
| for/in | for(var in object){statement}; |
遍歷一個(gè)對(duì)象的屬性; |
| for/of | for(let var of object); |
可遍歷數(shù)組字符串對(duì)象; |
| label | label:statement; |
給statement指定一個(gè)標(biāo)簽,可以引用標(biāo)簽的只有break和continue語句; |
| break | break [label]; |
退出最內(nèi)層循環(huán)或者退出switch語句,又或者退出label指定的語句; |
| continue | continue [label]; |
重新開始最內(nèi)層的循環(huán)或者重新開始label指定的循環(huán); |
| switch | switch(expression){expression}; |
重新開始最內(nèi)層的循環(huán)或者重新開始label指定的循環(huán); |
| case | case expression; |
在switch語句中標(biāo)記一條語句; |
| default | default; |
在switch中標(biāo)記默認(rèn)的語句; |
| empty | ; |
什么都不做; |
| debugger | debugger; |
斷點(diǎn)調(diào)試器; |
| throw | throw new Error(expression); |
拋出異常; |
| try/catch/finally | try{statement}[catch([param[],...]){statement}][finally{statement}]; |
捕獲異常 |
| use strict | "use strict"; |
對(duì)腳本和函數(shù)應(yīng)用嚴(yán)格模式; |
| with | with(object)statement; |
擴(kuò)展作用鏈; |
| ... | ...array; |
將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列; |
以上就是我總結(jié)的關(guān)于js的所有的語句語法(因?yàn)閷?duì)于ES6有點(diǎn)不熟,所以一些ES6里面的語法可能不全,請(qǐng)各位能及時(shí)提出建議),關(guān)于以上的語法,我主要把它們分為幾個(gè)部分:
- 聲明語句:
varletconst - 類聲明語句:
classextends - 函數(shù)語句:
function - 循環(huán)語句:
whiledo/whileforfor/infor/of - 判斷語句:
if/elseif/else if/elseswitch - 跳轉(zhuǎn)語句:
continuebreakthrowcasedefaultreturn - 標(biāo)簽語句:
label - 異常語句:
try/catch/finally - 其它語句:
with...'use strict' - 空語句:
;
1. 聲明語句
-
var
在ES6版本之前,主要的聲明語句還是var,在Js中我們可以利用var去聲明一個(gè)或者多個(gè)變量并初始化。與let不同,var可以聲明多個(gè)同名變量,var的作用域是[函數(shù)域或者全域],在使用var聲明變量的時(shí)候有一個(gè)需要注意的一個(gè)點(diǎn),就是聲明提前的問題。變量聲明語句會(huì)被“提前”到腳本或者函數(shù)體的頂部,具體請(qǐng)看下面的代碼:
function(){
console.log(he); //控制臺(tái)輸出的為undefined
var he = 4;
}
在本例中,我們事先打印了he變量,然后再在下一步中聲明了he變量,但是我們會(huì)發(fā)現(xiàn)函數(shù)在執(zhí)行的時(shí)候沒有報(bào)錯(cuò),反而打印出了he的值為undefined,這就是聲明提前的問題,he變量的聲明被提前到函數(shù)體頂部,并初始化為undefined,這和下面這段代碼是等價(jià)的。
function(){
var he;
console.log(he);
he = 4;
}
-
let
- ES6 新增了let命令,用來聲明變量。它的用法類似于var,但是所聲明的變量,只在let命令所在的[代碼塊]內(nèi)有效。
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
上面代碼在代碼塊之中,分別用let和var聲明了兩個(gè)變量。然后在代碼塊之外調(diào)用這兩個(gè)變量,結(jié)果let聲明的變量報(bào)錯(cuò),var聲明的變量返回了正確的值。這表明,let聲明的變量只在它所在的代碼塊有效。
- let相比較var,其中的特點(diǎn)之一就是let不存在變量提升,使用let聲明的變量,必須要在聲明之后才能使用,而不像var一樣在聲明之前會(huì)被提升初始化。
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;
// let 的情況
console.log(bar); // 報(bào)錯(cuò)ReferenceError
let bar = 2;
上面代碼中,變量foo用var命令聲明,會(huì)發(fā)生變量提升,即腳本開始運(yùn)行時(shí),變量foo已經(jīng)存在了,但是沒有值,所以會(huì)輸出undefined。變量bar用let命令聲明,不會(huì)發(fā)生變量提升。這表示在聲明它之前,變量bar是不存在的,這時(shí)如果用到它,就會(huì)拋出一個(gè)錯(cuò)誤。
- 使用let聲明的變量存在暫時(shí)性死區(qū),意思就是說let聲明變量的時(shí)候會(huì)綁定一個(gè)區(qū)域使這個(gè)區(qū)域中的變量不在受外界影響。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
上面代碼中,存在全局變量tmp,但是塊級(jí)作用域內(nèi)let又聲明了一個(gè)局部變量tmp,導(dǎo)致后者綁定這個(gè)塊級(jí)作用域,所以在let聲明變量前,對(duì)tmp賦值會(huì)報(bào)錯(cuò)。
ES6 明確規(guī)定,如果區(qū)塊中存在let和const命令,這個(gè)區(qū)塊對(duì)這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會(huì)報(bào)錯(cuò)。
總之,在代碼塊內(nèi),使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時(shí)性死區(qū)”(temporal dead zone,簡(jiǎn)稱 TDZ)。
注:let的存在使typeof不再是一個(gè)百分之百安全的操作。
- 使用let在同一個(gè)塊級(jí)作用域中不允許聲明兩個(gè)相同的變量。
// 報(bào)錯(cuò)
function func() {
let a = 10;
var a = 1;
}
// 報(bào)錯(cuò)
function func() {
let a = 10;
let a = 1;
}
-
const
const聲明一個(gè)只讀的常量。一旦聲明,常量的值就不能改變;const聲明的變量不得改變值,這意味著,const一旦聲明變量,就必須立即初始化,不能留到以后賦值;const的作用域與let命令相同:只在聲明所在的塊級(jí)作用域內(nèi)有效;const命令聲明的常量也是不提升,同樣存在暫時(shí)性死區(qū),只能在聲明的位置后面使用。const聲明的常量,也與let一樣不可重復(fù)聲明。
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
const foo;
// SyntaxError: Missing initializer in const declaration
if (true) {
const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is not defined
if (true) {
console.log(MAX); // ReferenceError
const MAX = 5;
}
var message = "Hello!";
let age = 25;
// 以下兩行都會(huì)報(bào)錯(cuò)
const message = "Goodbye!";
const age = 30;
2. 類聲明語句
-
class
ES6 提供了更接近傳統(tǒng)語言的寫法,引入了 Class(類)這個(gè)概念,作為對(duì)象的模板。通過class關(guān)鍵字,可以定義類?;旧?,ES6 的class可以看作只是一個(gè)語法糖,它的絕大部分功能,ES5 都可以做到,新的class寫法只是讓對(duì)象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法而已。ES5代碼都可用 ES6 的class改寫。
- 但是class和傳統(tǒng)的ES5語法不同的一點(diǎn)就是通過class聲明的方法都是不可以枚舉的,而在ES5中的構(gòu)造函數(shù)中是可以枚舉的。
class Point {
constructor(x, y) {
// ...
}
toString() {
// ...
}
}
Object.keys(Point.prototype)
// []
Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
var Point = function (x, y) {
// ...
};
Point.prototype.toString = function() {
// ...
};
Object.keys(Point.prototype)
// ["toString"]
Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
- 類的屬性名可以采用表達(dá)式
let methodName = 'getArea';
class Square {
constructor(length) {
// ...
}
[methodName]() {
// ...
}
}
- 相對(duì)于ES5的構(gòu)造函數(shù),還有不存在變量提升、不能像使用函數(shù)一樣使用類、class表達(dá)式
const class = new Class{};、可使用靜態(tài)屬性等特點(diǎn),在此就不一一列舉了。 - 靜態(tài)方法,在其中涉及到的一個(gè)概念就是靜態(tài)方法,靜態(tài)方法只能通過類的實(shí)列去調(diào)用而不能通過對(duì)象去調(diào)用,這個(gè)方面js和java是一樣的。
tips:其中新增了一個(gè)new.target屬性可以用來判斷這個(gè)對(duì)象是不是通過構(gòu)造函數(shù)調(diào)用的,如果不是的話就會(huì)返回一個(gè)undefined。
-
extends
我們?cè)谶M(jìn)入extends實(shí)現(xiàn)繼承之前我們先回想一下在es5中有的幾種繼承方式:
注:這里的原型鏈獲取都是采用的.prototype,這里是構(gòu)造對(duì)象的原型鏈獲取方式,如果是非構(gòu)造對(duì)象,則采用Object.getPrototypeOf(o)或者o.__proto__獲取。
- 默認(rèn)模式,也就是通過原型鏈繼承
child.prototype = new parent();
tips:繼承了父類的模板和原型,但是子類在初始化的時(shí)候是用的父類的傳參方法,在實(shí)際開發(fā)中必須要手動(dòng)糾正,即在末尾加上一句child.prototype.constructor = child把其子類的原型鏈的構(gòu)造方法改為自己的構(gòu)造方法。 - 借用構(gòu)造函數(shù)和apply、call;
child: parent.apply(this,arguments);
tips:只繼承了父類的模板而沒有繼承他的原型鏈。 - 借用和設(shè)置原型;
child: parent.apply(this,arguments);
child.prototype = new parent();
tips:子類擁有超類的兩份屬性,程序較大的時(shí)候會(huì)影響性能。 - 共享原型;
child.prototype = parent.prototype
tips:這里共享了兩個(gè)對(duì)象的原型鏈實(shí)現(xiàn)了繼承,但是缺點(diǎn)就是其中一個(gè)實(shí)列對(duì)于原型鏈的修改都會(huì)影響到另一個(gè)實(shí)列。 - 利用空對(duì)象作為中介;可用于非構(gòu)造函數(shù)對(duì)象的繼承
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
tips:上述方法的一個(gè)改良,依舊沒有類的概念。
- 拷貝繼承; 淺拷貝,只適用于基本類型的拷貝繼承
function extend(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}
tips:其實(shí)這種方法就是對(duì)原型鏈的一個(gè)深拷貝,實(shí)現(xiàn)了對(duì)實(shí)列的繼承,缺點(diǎn)就是如果原型鏈中的屬性設(shè)置了不能枚舉,那么其中的屬性就不會(huì)被拷貝。
- Object.create;
function extend(child,parent){
child.prototype = Object.create(parent);
child.prototype.constructor = child;
}
tips:Object.create()方法是ECMAScript 5中新增的方法,這個(gè)方法用于創(chuàng)建一個(gè)新對(duì)象。被創(chuàng)建的對(duì)象繼承另一個(gè)對(duì)象的原型,在創(chuàng)建新對(duì)象時(shí)可以指定一些屬性。
語法: Object.create(proto[,propertiesObject])
這個(gè)方法其實(shí)就是 上述的第五種方法。
- extends;
class child extends parent{
...
}
最后一種方法也就是我們今天的重點(diǎn),es6中新出現(xiàn)的語法extends就是最后一種實(shí)現(xiàn)繼承的方式,這個(gè)語法的特點(diǎn)和含義對(duì)于學(xué)習(xí)過java等面向?qū)ο笳Z言的同學(xué)來說應(yīng)該不難理解,兩者的方式都是一樣的。
tips:判斷父子類的函數(shù)
cp instanceof point;
Object.getPrototypeOf(ColorPoint) === Point;
3. 函數(shù)語句
-
function
關(guān)鍵字function用于在js中定義一個(gè)函數(shù),函數(shù)定義在js中有以下幾種寫法:
//最平常的寫法
function func(args){
...
}
//賦值寫法
var func = function(args){
...
}
//回調(diào)函數(shù)寫法
function func(callback){
...
callback();
}
/**函數(shù)體內(nèi)聲明寫法
* 這種寫法在ES5中是錯(cuò)誤的寫法,但是在ES6中是支持這種寫法的,因此這種寫法在大部分的瀏覽器中是不會(huì)報(bào)錯(cuò)的
*/
function func(){
...
function get(){}
}
//立即調(diào)用寫法
function(){
...
}();
4. 循環(huán)語句
-
while/do...while/for
以上的三個(gè)循環(huán)我相信大家對(duì)它的用法應(yīng)該都很了解,在這里我就不詳細(xì)介紹了,這三個(gè)語句在java,js中用法大同小異,大家不熟悉可以去回顧一下。
-
for/in
for/in循環(huán)也用來for關(guān)鍵字,但是用法卻和它有些不同,for/in循環(huán)主要是用于枚舉對(duì)象的屬性成員
// for/in可以枚舉出對(duì)象中屬性成員
var object = {
a: 1,
b: 2
...
}
for(item in object){
console.log(item);
}
// for/in可以枚舉出數(shù)據(jù)的下標(biāo)(不是其中的對(duì)象)
var arr = [1,2,...];
for(index in arr){
console.log(arr[index]);
}
-
for/of
for/of是ES6中的一個(gè)新的語法,可以把它看作一個(gè)遍歷器,其中遍歷對(duì)象的方式和for/in是一樣的,而遍歷數(shù)組的方式和其中的forEach是相同的。
let arr = [1,2...];
for(item off arr){
console.log(item);
}
5. 判斷語句
這個(gè)語句也是在各大編程語句中很常見的一種語句if/else和if/else if/else還有switch,在這里我就不詳細(xì)講述它的用法,我就簡(jiǎn)要地說幾個(gè)要注意的點(diǎn)。
-
嵌套if else的解析
在現(xiàn)實(shí)的開發(fā)中我們經(jīng)常會(huì)遇到嵌套的if else,其中就會(huì)有一下的情況
if(a === b)
...
if(b === c)
...
else
...
//因?yàn)榭s進(jìn)的誤導(dǎo)我們會(huì)以為第二個(gè)if是被套在里面,但是在js中,其中if和else的配對(duì)中沒有花括號(hào)就近地配對(duì),所以會(huì)解析為以下的內(nèi)容:
if(a === b){
...
if(b === c){
...
}
else{
...
}
}
//所以我們?cè)趯?shí)際的開發(fā)中,還是要多寫花括號(hào),以防止發(fā)生這樣的錯(cuò)誤
-
switch的代替方式
雖然我們的switch已經(jīng)可以方便地實(shí)現(xiàn)很多的功能,但是在某些情況下我們也會(huì)發(fā)現(xiàn)它的不足之處,所以在這里有一中可以用對(duì)象的方法去代替switch的方法:
//原switch的寫法
switch(type){
case type1:
func1;
break;
case type2:
func2;
break;
....
}
//對(duì)象寫法
var switcher = {
type1: func1,
type2: func2,
...
};
switcher["typeX"]();
// 利用對(duì)象的方式,在很多的場(chǎng)合可以很清晰地選擇要執(zhí)行的方式,代碼量也比switch小
6. 跳轉(zhuǎn)語句
對(duì)于跳轉(zhuǎn)語句,熟悉循環(huán)語句的同學(xué)都會(huì)對(duì)跳轉(zhuǎn)語句有所了解或者說熟悉跳轉(zhuǎn)語句,以上的continue break throw case default return這幾個(gè)跳轉(zhuǎn)語句大家再熟悉不過了,這幾個(gè)跳轉(zhuǎn)語句也經(jīng)常出現(xiàn)在java中,它們的用法是一樣的,在這里我也不做過多的陳述了,著重要提的一點(diǎn)就是break語句和continue語句,他們可以和標(biāo)記語句label一起使用,來實(shí)現(xiàn)對(duì)特定語句的跳轉(zhuǎn),具體在下一節(jié)會(huì)做詳細(xì)地陳述。
7. 標(biāo)簽語句
js中的標(biāo)記語句lable是js特有的一種語法,因?yàn)闃?biāo)簽語句只能與break continue聯(lián)合使用,所以一般來說標(biāo)簽語句主要放在循環(huán)體處,用于循環(huán)跳轉(zhuǎn)操作,以下是代碼示列:
var temp=0;
start:
for(var i=0; i<5; i++) {
for(var m=0; m<5; m++) {
if(m==1) {
break start;
}
temp++;
}
}
alert(temp);
上面的代碼,通過標(biāo)簽語句可以輕松地break掉外層循環(huán),如果不使用標(biāo)簽語句的話,我們break只能跳出內(nèi)層的循環(huán),要實(shí)現(xiàn)外層循環(huán)得多添加幾個(gè)判斷語句,所以有時(shí)候標(biāo)簽語句帶給我們的便利還是很多的。
8. 異常語句
try{
...
}
catch(exception){
...
}
finally{
...
}
參數(shù)說明:
tryStatements:必選項(xiàng)。可能發(fā)生錯(cuò)誤的語句序列。
exception:必選項(xiàng)。任何變量名,用于引用錯(cuò)誤發(fā)生時(shí)的錯(cuò)誤對(duì)象。
catchStatements:可選項(xiàng)。錯(cuò)誤處理語句,用于處理tryStatements中發(fā)生的錯(cuò)誤。
編碼時(shí)通常將可能發(fā)生錯(cuò)誤的語句寫入try塊的花括號(hào)中,并在其后的catch塊中處理錯(cuò)誤。錯(cuò)誤信息包含在一個(gè)錯(cuò)誤對(duì)象(Error對(duì)象)里,通過exception的引用可以訪問該對(duì)象。根據(jù)錯(cuò)誤對(duì)象中的錯(cuò)誤信息以確定如果處理。
9. 其它語句
-
with
with將綁定的對(duì)象添加至作用域鏈頭部,然后執(zhí)行語句,執(zhí)行之后又恢復(fù)作用域鏈到原始狀態(tài),如下所示:
with(document.forms[0]){
// 直接訪問表單元素
name.value = 0;
address,value = 0;
email.value = 0;
}
使用with語句還可以為當(dāng)前對(duì)象的屬性賦值或者添加屬性,比如下面的列子:
with(o) x = 1;
-
...
擴(kuò)展運(yùn)算符( spread )是三個(gè)點(diǎn)(...)。它好比 rest 參數(shù)的逆運(yùn)算,將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列。
/**
* 函數(shù)調(diào)用
*/
console.log([1,2,3,4,...]);
console.log([1,2,...[3,4],...]);
// 打印出來的結(jié)果 1,2,3,4,...
function(array,...items){
array.push(...items);
}
/**
* 替代數(shù)組的apply方法
*/
// ES5 的寫法
function f(x, y, z) {
...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6 的寫法
function f(x, y, z) {
...
}
var args = [0, 1, 2];
f(...args);
/**
* 拼接數(shù)組
*/
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
[...arr1, ...arr2, ...arr3];
/**
* 解構(gòu)賦值
*/
const [first, ...rest] = [1, 2, 3, 4, 5];
// first: 1; rest: [2,3,4,5];
/**
* 函數(shù)返回值
* 有時(shí)候需要返回多個(gè)值的時(shí)候可以用spread
*/
var dateFields = readDateFields(database);
var d = new Date(...dateFields);
/**
* 字符串轉(zhuǎn)數(shù)組
*/
console.log(...["array"]);
// 輸出 ['a','r','r','a','y'];
/**
* 實(shí)現(xiàn)了 Iterator 接口的對(duì)象,可以用其轉(zhuǎn)換為數(shù)組
*/
-
'use strict'
使用'use strict'可以消除js中語法的很多不合理不嚴(yán)謹(jǐn)?shù)牡胤剑旅媸且恍╆P(guān)于嚴(yán)格模式與非嚴(yán)格模式的區(qū)別:
- 在函數(shù)內(nèi)部聲明是局部作用域 (只在函數(shù)內(nèi)使用嚴(yán)格模式)
- 不允許使用未聲明的變量
- 不允許刪除變量或?qū)ο?/li>
- 不允許刪除函數(shù)
- 不允許變量重名
- 不允許使用八進(jìn)制
- 不允許使用轉(zhuǎn)義字符
- 不允許對(duì)只讀屬性賦值 (在非嚴(yán)格模式下對(duì)其賦值沒有效果,但是不會(huì)報(bào)錯(cuò))
- 不允許對(duì)一個(gè)使用getter方法讀取的屬性進(jìn)行賦值
- 不允許刪除一個(gè)不允許刪除的屬性
- 變量名不能使用 "eval" 字符串
- 變量名不能使用 "arguments" 字符串
- 不允許使用with(){....}運(yùn)算符
- 由于一些安全原因,在作用域 eval() 創(chuàng)建的變量不能被調(diào)用
- 禁止this關(guān)鍵字指向全局對(duì)象(在嚴(yán)格模式下,全局this指向的undefined,因此,使用構(gòu)造函數(shù)時(shí),如果忘了加new,this不再指向全局對(duì)象,而是報(bào)錯(cuò))
- 保留關(guān)鍵字:
implementspublicinterfaceletpackageprivateprotectedstaticyield
10. 空語句
如果在語句中只有一個(gè);,則不會(huì)發(fā)生任何的執(zhí)行。