1. 程式人生 > 程式設計 >Node.js基礎語法和ES6新屬性(Node.js自學第一天)

Node.js基礎語法和ES6新屬性(Node.js自學第一天)

Node.js從4.0開始,支援ES6的大多數新特性,例如:classes、typed arrays、generators、Promises、Symbols、collections、arrowfunctions、block scoping、template strings等。

資料型別

(1)原始型別(Primitive Type):
string、number、bollean、null、undefined,原始型別資料直接賦值即可。

(2)引用型別(Reference Type):
包含ES原生物件、Node.js物件、使用者自定義物件三類;引用型別資料一般需要使用new關鍵字進行建立。

模板字串(Template String)

ES6標準中,可以使用"模板"方式定義字串:

var info=`
	使用者名稱:tom
	密碼:123456
`;
複製程式碼

模板字串中可以使用${}拼接變數,並執行運算:

var price=3.5,count=3;
var info=`
	單價:${price}
	數裡:${count}
	小計:${price*count}
`
console.log(info);
複製程式碼

變數和常量

(1)宣告常量

var empName1='tom';//區域性變數
empName2='Mary';//全域性變數
複製程式碼

注意:省略var的全域性變數在嚴格模式下是非法的

(2)宣告常量—ES6新特性

const fs=require('fs');
複製程式碼

變數的作用域

ES6中,變數的作用域分為三種:
(1)區域性作用域:只能在當前函式內使用
(2)全域性作用域:可以在任意函式內使用—是全域性物件的成員
(3)塊級作用域:只能在當前塊內使用—ES6新特性

"use strict";

for(let i=0;i<10;i++){
	console.log(i)//正常執行
}
console.log(i)//執行錯誤
複製程式碼

運運算元

(1)算術運算 +    -    *    /    %    ++    --
(2)比較運算 >    <    >=    <=    ==    ====    !=    !==
(3)邏輯運算 &&
(4)位運算 &
(5)賦值運算 +=    -=    *=    /=    %=
(6)三目運算 ? :
(7)特殊運算 typeof (判斷變數型別)     instanceof(判斷一個物件是否從屬於某種型別)    viod(對任何值返回undefined)   ,    .    [ ](取下標運運算元)    =>

邏輯結構

(1)迴圈結構

for
for...in... 常用於遍歷物件
for...of... 只能遍歷陣列,不能遍歷物件(ES6新特性)
while
do...while

(2)選擇結構

if...else...
switch...case...

for...in和for...of

(1) for...in迴圈可以遍歷陣列的下標或物件成員名

var arr=[90,80,70]
for(var i in arr){
	console.log(i);//將輸出0 1 2
}
複製程式碼

(2)ES6新增的for...of迴圈可以遍歷陣列的元素值

var arr=[90,70];
for(var v of arr){
	console.log(v);//將輸出90 80 70
}
複製程式碼

函式

函式:就是一系列語句的集合,為了實現某種可以重複使用的特定功能。

(1)命名函式:指定了名稱的函式物件

function add(num1,num2){
	return num1+num2;
}
add(10,20);
複製程式碼

(2)匿名函式:未指定名稱的函式物件

function(num){
	arguments.calle(num-1);//遞迴呼叫匿名函式
}
複製程式碼

自調函式(匿名函式的自調)

JS中,全域性變數會變成全域性物件的成員,造成全域性物件的汙染;很多JS工具和框架都在設計時,為了避免此問題,常常使用匿名函式的自調:

(function(g){
	var ns="myNamespace";
})(global);
複製程式碼
+function(g){
	var ns="myNamespace";
}(global)
複製程式碼

匿名函式在使用時必須使用function關鍵字,在大型的WEB應用中匿名函式會使用的很多很多,所以ES6中為了簡化這種匿名函式的用法,引入了箭頭函式的概念。

箭頭函式

ES6中,為了簡化匿名函式的編寫,引入了監聽函式語法:

setInterval(()=>{
	console.log('timer...');
},1000);
複製程式碼

箭頭函式()是形參列表,function關鍵字被省略,小括號和大括號中間使用箭頭指示符連線;大括號中還是普通函式一樣編寫函式體。今後在編寫Node.js程式中會經常使用箭頭函式,Node.js官方給出的例子也幾乎都是使用的箭頭函式。

fs.readFile('index.html',(err,data)=>{
	if(err)throw err;
  console.log(data);
});
複製程式碼

箭頭函式與普通匿名函式的區別:
1、普通匿名函式中使用了this,this指當前函式物件;
2、在箭頭函式中this指與箭頭函式本身同一級的this;
3、在箭頭函式中使用arguments.callee不在指向當前匿名函式。

閉包

閉包(Closure),是ECMAScript中特有的現象。一個閉包,可以看做一種特殊的物件,包含若干函式物件,以及這些函式物件執行時必須依賴的執行上下文物件。

function outer(){
	var num=10;
  function inner(){
  	console.log(num)
  }
  return inner;
}
var fn=outer();
fn();
複製程式碼

有一個function,外部函式叫outer,outer有一個形參叫num=10,我們知道num實在outer函式體內,那麼他的作用範圍也是僅限於outer函式內,離開outer那麼num也沒有作用了。在outer函式內又定義了一個內部函式叫inner,inner函式需要輸出num變數,由於inner內部函式內並沒有定義,所以會使用outer內定義的區域性變數num。outer函式自身並沒有呼叫inner,而是將inner內部函式return返回了。outer函式被呼叫,就會有一個返回值指向了inner函式,也就說fn指向了inner函式,inner函式被外部呼叫。inner函式不能直接被呼叫,因為inner函式執行必須依賴一個外部函式執行時,他建立的上下文物件所遺留的num變數。每一次呼叫outer函式,都返回了一個函式物件,以及這個函式物件執行所必須依賴的一個外部函式提供的上下文。(每呼叫一次outer函式都會產生一個閉包物件)

閉包引起的錯誤

無論是前端JS還是Node.js,閉包使用不當,都有可能引起看似奇怪的錯誤:

//假設前端專案有三個button元素
var list=document.querySelectAll("button");
for(var i=0;i<list.length,i++){
	list[i].onclick=function(){
  	console.log(i);
  }
}
//點選每個按鈕,會分別輸出什麼?
複製程式碼

理想結果:三個按鈕,點選第幾個按鈕就輸出數字對應的下標
實際結果:點選每個按鈕都會輸出數字3
原因?:這段程式碼中給這三個按鈕各自綁定了一個匿名的監聽函式,相當於這段程式碼執行完成後給外界返回了三個函式物件,這三個函式執行都需要依賴於外部產生的執行上下文物件,他裡邊有且只有一個i(三個函式物件,外加一個執行上下文物件裡的i,這是一個典型的閉包)。迴圈結束變數i停留在3上,最終任何一個按鈕被點選時,他們再去查詢變數i,變數i已經被固定在3了,所以不會拿到0、1、2這種結果。

使用Node.js,也可以產生類似前端中的閉包錯誤:

//目標:1s後,先輸出0、1、2
for(var i=0;i<3;i++){
	setTimeout(()=>{
  	console.log(i)
  },1000)
}
//實際的執行結果呢?
3
3
3
複製程式碼

那麼我們怎麼解決呢?

for (var i = 0; i < 3; i++) {
    setTimeout(((num) => {
        return () => {
            console.log(num)
        }
    })(i),1000);
}
複製程式碼

物件

ECMAScript中提供了多種建立物件的語法:
(1)物件直接量方式(這種物件不具有反覆使用性)

var e1={ename:'tom',work:function(){}}
複製程式碼

(2)建構函式方式

function Emp(ename){
	this.ename=ename;
  this.work=function(){}
}
var e2=new Emp('tom');
複製程式碼

這裡邊指定emp所需要的成員屬性和成員方法,我們在需要emp型別物件時,可以直接new一個emp物件。

(3)原型繼承方法

var parent=new Object();
var child=Object.create(parent);
複製程式碼

先建立一個parent物件,再使用Object.creaet()方法建立一個parent物件的子物件。

(4)class方式—ES6新特性
ES6借鑑了其他程式語言宣告物件的方式,正式啟用了class關鍵字,有了"類"的概念。
class:類,是一組相似物件的屬性和行為的抽象集合。
instance:例項,是從屬於某個類的一個具體物件。

//class關鍵字必須用嚴格模式
"use strict"
//宣告一個類
class Emp{
  //構造方法
	constructor(ename){
  	this.ename=ename;
  }
  //例項方法
  work(){
  	console.log(`ENAME:${this.ename}`);
  }
}
//建立類的例項
var e3=new Emp('tom');
e3.work();
複製程式碼

物件的繼承

繼承,是面向物件程式設計的一個重要概念,使子物件可以繼承父物件中宣告的成員,從而極大的提高程式碼的複用性。
ES6之前的繼承都是通過物件的原型(prototype)來實現的:

var graphic={bgColor:'red',borderColor:'blank'}
var rect={width:500,height:300}

Object.setPrototypeOf(rect,graphic);//原型繼承
console.log(rect.width);
console.log(rect.hight);
console.log(rect.bgColor);//繼承來的成員
console.log(rect.borderColor);//繼承來的成員
複製程式碼

ES6中的繼承通過使用class配合extentds關鍵字來實現。

//宣告父類
class Emp{
	constructor(ename){
  	this.ename=ename;
  }
  work(){
  	return `ENAME:${this.ename}`;
  }
}
//宣告子類
class Programmer extends Emp{
	constructor(ename,skills){
    //呼叫父類構造方法
  	super(ename);
    this.skills=skills;
  }
  work(){
  	return super.work()+`SKILLS:${this.skills}`;
  }
}
var p1=new Programmer('tom','js');
console.log(p1.work());
複製程式碼

物件的分類

(1)ECMAScript預定義物件
String、Boolean、Number、Date、Array、Math、RegExp、function、Object、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、UriError等16個物件;

(2)Node.js核心模組定義的物件
Bufefer、WriteStream、Socket、ChildProcess等數百個;

(3)等三方模組定義的物件

(4)使用者自定義的物件
注意:Node.js中不支援BOM和DOM物件,如:window、document等