ES6核心,值得駐足花一天時間來學習

扶牆哥發表於2018-08-11

1.let 和 const 命令

在es5時,只有兩種變數宣告,var 和function。在es6中新增了四種let和const,以及另外兩種宣告import和class。 我們先講解let和const,後續會補充import和class

(1)let

我們先來看基本語法

{
 let a = 10;
 var b = 1;
}
b // 1
a // ReferenceError: a is not defined.
複製程式碼

我們在程式碼塊中宣告瞭a,b。然後a is not defined.這是因為let命令只在對應的程式碼塊中有效,我們在外部去引用它,就會報錯。這就是let的塊級作用域的效果,如果不太清楚什麼是塊級作用域。我們來看下面的例子

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[0]();//10
a[6](); // 10
複製程式碼

這是一個老生常談的問題了。i在for迴圈中定義的是全域性變數。我們在呼叫函式時。函式內部的i引用的是全域性的i,所以列印出來的 是10. 我們之前是這樣解決的。

 var a = [];
    for (var i = 0; i < 10; i++) {
        a[i] = (function (a) {
            return function(){
                console.log(a);
            }
        }(i));
    }
    a[0]();//0
    a[6](); // 6
複製程式碼

我們使用了立即執行函式將i的值傳入了內部的函式,這樣內部的函式就能夠獲取到對應的i。

我們用let來代替var,最後輸出的是 6。

var a = [];
for (let i = 0; i < 10; i++) {
 a[i] = function () {
   console.log(i);
 };
}
a[6](); // 6
複製程式碼

這是因為我們每一次的迴圈都生成了一個新的塊級作用域,內部儲存著i的值,所以就會列印出6.

let不存在變數提升

   console.log(a);
   console.log(b);
   var a=0;//undefined
   let b=0;//ReferenceError: b is not defined
複製程式碼

TDZ(暫時性死區) let命令在塊級作用域中,即使不存在變數提升,它也會影響當前塊級作用域,即繫結在了當前作用域。在作用域中引用外部的變數將會報錯。

 var a=10;
  {
      console.log(a);  //ReferenceError: a is not defined
      let a=10;
  }
複製程式碼

同時,我們在TDZ中使用typeof也會報錯.

 console.log( typeof a);//undefined
複製程式碼
console.log( typeof a);//ReferenceError: a is not defined
  let a=10;
複製程式碼

let 不允許重複宣告變數

{
    var a=0;
    let a=1;//SyntaxError: Identifier 'a' has already been declared
}
複製程式碼

(2) const常量

const常量宣告一個只讀屬性的變數,不可更改,不可先宣告後賦值,生成塊級作用域。

 const a;//SyntaxError: Missing initializer in const declaration(const宣告中缺少初始值設定項)
 a=10;
複製程式碼

它同let有很多相似的地方。 .不可重複宣告

const a=10;
var a=10;//SyntaxError: Identifier 'a' has already been declared
複製程式碼

.變數不提升

console.log(a)//ReferenceError: a is not defined
const a=10;
複製程式碼

.同樣存在暫時性死區

var a=10;
{
    console.log(a);//ReferenceError: a is not defined
    const a=10;
}
複製程式碼

另外,const保證常量的值不被修改的原理是什麼呢?const實際上無法改變的只是常量在棧區的值不變,如果這個值是一個基本資料型別,那麼const能夠保障常量的值不變,但如果是引用型別的資料,棧區儲存的其實是對應常量的地址。地址無法改變,但是對應地址的堆區內容卻可以改變。

 const a=[1,2,3]
 a.push(4)
 console.log(a); //[1, 2, 3, 4]
複製程式碼

很顯然,我們通過push,直接修改了堆區的內容,間接改變了const常量的值。

如果要真正做到常量的功能,可以使用Object.freeze()

var a=[1,2,3];
Object.freeze(a)
a.push(4)  //Cannot add property 3, object is not extensibleat Array.push
console.log(a);
複製程式碼

2.字串擴充套件方法

(1)for of字串遍歷

使用for of可以遍歷字串,並將字串分解為單獨的字串

var a='lang'
for (item of a){
  
   console.log(item);
} 
// l
// a
// n
// g
複製程式碼

(2) codePointAt字串查詢.

根據下標,查詢對應字串。在Es5時,就有一個charAt()方法。但charAt()顯然沒想到,隨著Unicode編碼的擴充套件,原先的0x0000~0xFFFF已經無法滿足表示所有字元了。

var text = "?";
text.charAt(0); //''
text.charAt(1); //''
複製程式碼

所以es6中新增了codePointAt(),查詢,codePointAt()有著更好的unicode支援,能夠查詢>0xFFFF的字元。

var text = "?";
  console.log(text.codePointAt(0)); //134071 
複製程式碼

(3)includes()值存在判斷

在es6之前使用indexof也可以進行值存在判斷。includes與indexof既可以進行字串的判斷,也可以進行陣列值的判斷, 但是indexof在對NaN進行判斷時會出現不準確。

var text = [1,NaN]
console.log(text.indexOf(NaN));//-1
複製程式碼

另外,indexof的返回結果為-1||0,includes為true||false.

(4) repeat()字串重複

str=repeat(n)返回的是新的字串,並且會將str的字串重複n次。

var a='lang'
console.log(a.repeat(3));//langlanglang
複製程式碼

其中n會自動取整。n<=-1||n==infinaty將會報錯。

(5)startwith,endwith。

startWith('str',n):返回布林值,表示引數字串是否在原字串的頭部。

endsWith('str',n):返回布林值,表示引數字串是否在原字串的尾部。其中str表示要判斷的值,n表示從目標字串的第幾個元素開始。

 var str='hello world'
 console.log(str.startsWith('hello',0)); //true
 console.log(str.startsWith('world',6)); //true
 console.log(str.startsWith('world',0)); //false
複製程式碼

(6)padStart(),padEnd()

es6提供了兩個字串追加的方法String.prototype.padStart和String.prototype.padEnd,方便我們將一個新的字串追加到某個字串的頭尾。

我們常常使用padstart來使字串輸出時保持格式。

 var a='abc'
 var b='abcd'
 var c='abcd'
 console.log(a.padStart('10',0)); 
 console.log(b.padStart('10',0));
 console.log(c.padStart('10',0));
 //0000000abc
 //000000abcd
 //00000abcde
複製程式碼

但有時候使用endstart顯然會更好。

var a='abc'
 var b='abcd'
 var c='abcde'
 console.log(a.padEnd(10,'-------')); 
 console.log(b.padEnd(10,'-------'));
 console.log(c.padEnd(10,'-------'));
 //abc-------
 //abcd------
 //abcde-----
複製程式碼

也可以組合使用達到效果

var obj={
  name:'wangcai',
  car:'BMW',
  wife:'fatgirl'
}
for(var item in obj){
  console.log(item.padEnd(10,'-')+'value:'+obj[item].padStart(10,'**'));
}
//name------value:***wangcai
//car-------value:*******BMW
//wife------value:***fatgirl
複製程式碼

(7)**模板字串

模板字串的引入是es6的一大亮點,它使得輸出模板變得簡潔而方便。模板採用反引號(``),中間支援各種格式的輸出。 包括換行,空格,變數,表示式,呼叫函式等。我們可以在一個模板中組合使用它們

var age=22;
var name='lang'
var say=()=>{
  return 'hello'
}
var str=`myname is${name} my age is ${age} and i can say ${say()}`
console.log(str);  //myname islang my age is 22 and i can say hello
複製程式碼

在模板字串的 ${} 中可以寫任意表示式,但是同樣的,對 if / else 判斷、迴圈語句無法處理。

但在很多時候我們需要去使用if或者迴圈。我們可以先在外部使用邏輯處理語句,然後生成一個我們想要的模板,在用``進行轉義


var age=22;
var name='lang'
var name2='Lang'
var str=''
var say=()=>{
  return 'hello'
}
if(age>=18){str=name2}
var str=`myname is${str} my age is ${age} and i can say ${say}`
console.log(str);  //myname isLang my age is 22 and i can say hello
複製程式碼

當然,我們也可以使用陣列,將各個模板片段存入陣列之中,最後通過Array.join('')將其拼接為最終的模板。

3.數值擴充套件方法

(1)二進位制和八進位制表示法

之前在es5時的嚴格模式中,,我們已經無法使用二進位制和八進位制。在es6中提供了兩個新的二進位制和八進位制寫法。

二進位制(0bxxx||0Bxxx)八進位制(0oxxx||0Oxxx)

'use strict'
  var a=0b11;
  var b=0o11
  console.log(a);//3
  console.log(b);//9
複製程式碼

(2)Number.isNaN()

isNAN可以用來檢測資料是否是NAN型別,只有NAN才會返回true,其餘型別皆返回false。

 var x=NaN*2
 console.log(Number.isNaN(x));//true
 console.log(NaN==NaN);//false
 console.log(NaN===NaN);//false
複製程式碼

(3)Number.parseInt(), Number.parseFloat()

這兩個方法在es5中已經存在,es6將其從全域性物件中提取放入了Number物件中

(4)Number.isIntger()

 var a=3.00
var b=10;
var c=false;
var d=4.00000000000000000000000000000002
console.log(Number.isInteger(a));//true
console.log(Number.isInteger(b));//true
console.log(Number.isInteger(c));//false
console.log(Number.isInteger(d));//true
複製程式碼

只有整數,以及類似3.0這樣的浮點數才會被認為是整數,返回true,除此之外,js運算具有不準確性,超出精度範圍的值,會預設為o,所以4.0000000000000000000000002會被看做是4. (5)Math.trunc()

取整函式,會對值進行取整,會對傳入的值先進行Number()處理,正數將會進行Math.floor(),若為負數則進行Math.ceil();

console.log(Math.trunc(4.1));//4
console.log(Math.trunc(4.9));//4
console.log(Math.trunc(-1.2));//-1
console.log(Math.trunc(-1.9));//-1
console.log(Math.trunc(true));//1
console.log(Math.trunc('lang'));//NaN
複製程式碼

3.函式擴充套件

(1)函式指定預設值 可以為函式傳入的引數指定預設值,函式內部可以覆蓋使用。

function say(x,y=5){
    console.log(x,y);  //1,5
    y=10;
    console.log(x,y);  //1,10
  }
  say(1)
複製程式碼

需要注意以下兩點

.使用引數預設值時,函式不能有同名引數。

// 不報錯
function foo(x, x, y) {
  // ...
}

// 報錯
function foo(x, x, y = 1) {
  // ...
}
// SyntaxError: Duplicate parameter name not allowed in this context
複製程式碼

.不可使用let,const重複宣告

function say(x,y=5){
  let y=10;
  console.log(x,y);  //SyntaxError: Identifier 'y' has already been declared
 }
 say(1)
複製程式碼

(2)rest 引數 在函式形參中使用...擴充套件運算子,可以將不定形參傳入rest陣列中。

function say(...res) {
   for (var item of res) {
     console.log(item);
   }
 }
 say(1, 2, 3)  
 //1
 //2
 //3
複製程式碼

(3)箭頭函式(重點)

基本使用方法

 var f=(x,y)=>{ return x+y}
 console.log(f(1,2));  //3
複製程式碼

假如(x,y)只有一個引數,我們可以省略(),同樣返回語句中,若只有一條語句,也可以省略。

 var f=x=>x+10
 console.log(f(1));  //11
複製程式碼

使用注意點 箭頭函式有幾個使用注意點。

(1)函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。

(2)不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。

(3)不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用 rest 引數代替。

(4)不可以使用yield命令,因此箭頭函式不能用作 Generator 函式。

對於需要注意的第一點,我們經常會因為維護回撥函式的this而煩惱,而在箭頭函式中則不存在這個問題,箭頭函式內部的this是固定的,不會因為函式呼叫而改變。

在ES5,我們通常採用外部儲存this的方法,來維護this、

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var that= this;

  setTimeout(function () {
    console.log('id:', that.id);
  }, 100);
}
複製程式碼

argumet在箭頭函式中不存在,那麼使用argument將會使用外部函式的argument

function foo() {
  setTimeout(() => {
    console.log('args:', arguments);
  }, 100);
}

foo(2, 4, 6, 8)
// args: [2, 4, 6, 8]
複製程式碼

(4)尾呼叫

在函式的最後一步呼叫一個函式,這叫做尾呼叫。解釋很簡單,但卻很容易混淆。 .最後一步?什麼是最後一步,在函式中,return就是最後一步,沒有return的都不是尾呼叫。

 function g(){}
function f(){
  g()  //這不是尾呼叫
}
f()
複製程式碼

.即使return後面還有表示式,但這些函式不起作用,那麼它依舊是尾呼叫。

 function g(){}
function f(){
   return g()  //這是尾呼叫
   console.log('121');
}
f()
複製程式碼

.返回的必須是函式,不能是表示式。下面額例子中,返回了g()+1; g()+1;不是一個函式,而是一個表示式。

 function g(){}
function f(){
   return g()+1  //這不是尾呼叫
}
f()
複製程式碼

(5)尾遞迴

尾遞迴是尾呼叫的一種特殊情況,但尾遞迴是在最後一步呼叫自身。

我們在使用遞迴時,必須給一個終止條件,不然就會產生死迴圈

var a=0;
  function f(){
   a++
   return f()  //這顯然是一個死迴圈
  }
  f()
複製程式碼

我們常常使用遞迴等方法來求階乘等,但遞迴很容易發生棧溢位的情況。

非尾遞迴的 Fibonacci 數列實現如下。

function Fibonacci (n) {
  if ( n <= 1 ) {return 1};

  return Fibonacci(n - 1) + Fibonacci(n - 2);
}

Fibonacci(10) // 89
Fibonacci(100) // 堆疊溢位
Fibonacci(500) // 堆疊溢位
複製程式碼

尾遞迴優化過的 Fibonacci 數列實現如下。

function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
  if( n <= 1 ) {return ac2};

  return Fibonacci2 (n - 1, ac2, ac1 + ac2);
}

Fibonacci2(100) // 573147844013817200000
Fibonacci2(1000) // 7.0330367711422765e+208
Fibonacci2(10000) // Infinity
複製程式碼

4.陣列擴充套件

(1)擴充套件運算子(...)

使用擴充套件運算子可以 能夠直接深拷貝一個陣列。修改一個陣列內的引用值,不會改變另一個值

 var arr=[1,2,3,[4,5],6]
 var a=[...arr];
 console.log(a);//[1, 2, 3, Array(2), 6]
複製程式碼

擴充套件運算子可以用於陣列拼接

 var arr=[1,2,3]
 var arr2=[4,5,6]
 var str='12121'
 var a=[1,...arr,2,...arr2];
複製程式碼

另外...arr返回的並不是一個陣列,而是各個陣列的值。只有[...arr]才是一個陣列,所以...arr。可以用來對方法進行傳值

 var arr=[1,2,3]
function f(x,y,z){
    return x+y+z 
}
console.log(f(...arr));  //6
複製程式碼

(2)Array.from()

Array.from()可以將某些偽陣列轉換成真正的陣列結果,什麼是偽陣列呢,我們在實際開發中,有兩種常見的偽陣列,arguments和Dom中獲取的元素集合。

<body>
    <p></p>
    <p></p>
    <p></p>
    <p></p>
    <p></p>
</body>
<script> 
 var arr = document.getElementsByTagName('p')
 var arr2 = Array.from(arr)
 console.log(Array.isArray(arr2));//true
複製程式碼

同樣能夠將偽陣列轉換陣列的還有兩種方法 .之前提到的擴充套件運算子

 var arr = document.getElementsByTagName('p')
   var arr2 = [...arr]
   console.log(Array.isArray(arr2));//true
複製程式碼

.使用call,apply方法。

 var arr = document.getElementsByTagName('p')
    var newarr=Array.prototype.slice.call(arr,0)
    var newarr=Array.prototype.slice.apply(arr,[0])
    console.log(Array.isArray(newarr));//Var 新陣列 = 舊陣列.slice(起點下標,終點下標)返回值:陣列,是舊陣列中的一個部分。
    console.log(newarr);
複製程式碼

(3)Array.of()

也是用於將一組值,轉換為陣列。 Array.of並不是用於將轉換偽陣列的,它的作用是為了彌補Array構造器的不足,之前我們在想要構建一個長度為一的陣列,且值為number型別是無法用Array構建的

var arr=new Array(3)
console.log(arr);//[empty*3]
複製程式碼

很顯然,我們想要構建一個[3],可以使用Array.of()

var arr=Array.of(3)
console.log(arr); //[3]
複製程式碼

(4)find和findIndex 查詢第一個符合條件值/下標

find:用於找出第一個符合條件的陣列元素。找不返回 undefined 。

findIndex:返回第一個符合條件的陣列元素的索引。找不到返回-1;

var arr=[1,2,3,4,5]
var newarr1=arr.find(function(item,index){return item>2})
var newarr2=arr.findIndex(function(item,index){return item>2})
console.log(newarr1);  //3
console.log(newarr2);  //2
複製程式碼

基本語法如上:find和findindex內部是一個回撥函式,需要返回一個查詢條件,find則會執行這個返回條件,查詢第一個滿足條件的值。findindex則會返回下標。 我們可以直接用箭頭函式進行簡寫

var arr=[1,2,3,4,5]
var newarr1=arr.find(item=>item>2)
var newarr2=arr.findIndex(item=>item>2)
console.log(newarr1);  //3
console.log(newarr2);  //2
複製程式碼

(5)fill 填充初始化陣列

作用:給陣列填充指定值。fill 方法用於空陣列的初始化非常方便。已有資料會被覆蓋。 fill 方法還可以接受第二個和第三個引數,用於指定填充的起始位置和結束位置

var arr=[1,2,3,4,5]
  arr.fill('*',1,3)
  console.log(arr);//[1, "*", "*", 4, 5]
複製程式碼

5.物件擴充套件

(1).屬性的簡寫

屬性名是可以簡寫的,但是有前提條件:屬性的值是一個變數 變數名稱和鍵名是一致的。

var name ='lang'
var age=22;
var obj={
name:name,
age:age
}
複製程式碼

像這樣的物件,我們就可以進行簡寫

var name ='lang'
var age=22;
var obj={
name,
age,
}
複製程式碼

前提是屬性名和屬性值必須一致。

(2)方法的簡寫

var obj={
say:function(){}
}
複製程式碼

簡寫為

var obj={
say(){}
}
複製程式碼

(3)精細化設定物件的屬性

屬性的四個特徵:

1.configurable: 是否可以刪除。 預設為true 可以刪除:

2.writable: 是否可以修改。 預設為ture, 可以修改:

3.enumerable: 是否可以列舉。可以使用 for in 預設為ture, 可以列舉:

4.value: 值。 預設值為undefined

格式1:Object.defineProperty(物件名,“屬性名”,{上面的四個特徵});

var obj={
  name:'lang',
  age:22
}
 Object.defineProperty('obj','name',{
   configurable:false,
   writable:false,
   enumerable:false
 })
複製程式碼

格式2:Object.defineProperties(物件名,{屬性名{四個特徵}},{屬性名{四個特徵}}});

  var obj = {
   name: 'lang',
   age: 22
 }
 Object.defineProperties(obj, {
   name: {
     configurable: false,
     writable: false,
     enumerable: false
   },
   age: {
     configurable: false,
     writable: false,
     enumerable: false
   }
 })
複製程式碼

(4)獲取精細化設定物件的屬性

Obect.getOwnProertyDescriptor(物件,屬性名) 可以獲取物件的精細化屬性裡面的值。

var obj={
name:'lang',
age:22
}
Object.defineProperty(obj,'name',{
 configurable:false,
 writable:false,
 enumerable:false
})

console.log(Object.getOwnPropertyDescriptor(obj,'name'));
複製程式碼

ES6核心,值得駐足花一天時間來學習

(5)Object.keys()

使用Object.getOwnPropertyNames()和Object.keys()都可以得到一個物件的屬性名,屬性名是放在一個陣列中的。

var obj={
name:'lang',
age:22
}
console.log(Object.keys(obj));   //["name", "age"]
複製程式碼

那麼我們目前有三種遍歷物件的方法了 對於物件的遍歷目前有三種方式:

        1. for in

        2.Object.keys()

        3.Object.getOwnPropertyNames()
複製程式碼

for in : 會輸出自身以及原型鏈上可列舉的屬性。

Object.keys() : 用來獲取物件自身可列舉的屬性鍵

Object.getOwnPropertyNames() : 用來獲取物件自身的全部屬性名

(6)Object.values();

獲取物件的值,放入陣列中。

var obj={
  name:'lang',
  age:22
}
console.log(Object.values(obj));   //["lang", 22]
複製程式碼

6.解構賦值

解構賦值語法是一個 Javascript 表示式,這使得可以將值從陣列或屬性從物件提取到不同的變數中。

物件字面量和陣列字面量提供了一種簡單的定義一個特定的資料組的方法。

let x = [1, 2, 3, 4, 5];
複製程式碼

解構賦值使用了相同的語法,不同的是在表示式左邊定義了要從原變數中取出什麼變數。

var x = [1, 2, 3, 4, 5];
var [y, z] = x;
console.log(y); // 1
console.log(z); // 2
複製程式碼

(1)陣列的解構

變數宣告並賦值時的解構

var foo = ["one", "two", "three"];

var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
Link to section變數先宣告後賦值時的解構
複製程式碼

通過解構分離變數的宣告,可以為一個變數賦值。

var a, b;

[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
Link to section預設值
複製程式碼

為了防止從陣列中取出一個值為undefined的物件,可以為這個物件設定預設值。

var a, b;

[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
Link to section交換變數
複製程式碼

在一個解構表示式中可以交換兩個變數的值。

沒有解構賦值的情況下,交換兩個變數需要一個臨時變數(或者用低階語言中的XOR-swap技巧)。

var a = 1;
var b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
Link to section解析一個從函式返回的陣列
複製程式碼

從一個函式返回一個陣列是十分常見的情況.。解構使得處理返回值為陣列時更加方便。

在下面例子中,[1, 2] 作為函式的 f() 的輸出值,可以使用解構用一句話完成解析。

function f() {
  return [1, 2];
}

var a, b; 
[a, b] = f(); 
console.log(a); // 1
console.log(b); // 2
複製程式碼

(2)物件的解構

基本賦值

var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true
複製程式碼

給新的變數名賦值

可以從一個物件中提取變數並賦值給和物件屬性名不同的新的變數名。

var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
 
console.log(foo); // 42 
console.log(bar); // true
複製程式碼

預設值

變數可以先賦予預設值。當要提取的物件沒有對應的屬性,變數就被賦予預設值。

var {a = 10, b = 5} = {a: 3};

console.log(a); // 3
console.log(b); // 5
複製程式碼

混合解構(巢狀物件和陣列) 解構巢狀物件和陣列

var metadata = {
    title: "Scratchpad",
    translations: [
       {
        locale: "de",
        localization_tags: [ ],
        last_edit: "2014-04-14T08:43:37",
        url: "/de/docs/Tools/Scratchpad",
        title: "JavaScript-Umgebung"
       }
    ],
    url: "/en-US/docs/Tools/Scratchpad"
};

var { title: englishTitle, translations: [{ title: localeTitle }] } = metadata;

console.log(englishTitle); // "Scratchpad"
console.log(localeTitle);  // "JavaScript-Umgebung"
複製程式碼

7.class類

之前在es5中,我們如何去實現一個類的功能呢?我們通常採用構造器的方法去實現,然而,使用構造器去模仿類的實現並不方便,不僅需要經常維護this,而且在繼承的時候更是不僅需要使用call拷貝父類的基本數值,還需要繼承父類的原型來繼承方法。我們簡單來看看程式碼就知道了

   function Parent(name) {
        this.name = name;
    }
    Parent.prototype.sayName = function () {
        console.log('parent name:', this.name);
    }

    function Child(name, parentName) {
        Parent.call(this, parentName);
        this.name = name;
    }

    function inheritPrototype(Parent, Child) {
        Child.prototype = Object.create(Parent.prototype);   //修改
        Child.prototype.constructor = Child;
    }

    inheritPrototype(Parent, Child);

    Child.prototype.sayName = function () {
        console.log('child name:', this.name);
    }

    var parent = new Parent('father');
    parent.sayName();      // parent name: father

    var child = new Child('son', 'father');
    child.sayName();       // child name: son
複製程式碼

在es6中,我們可以直接使用class來定義,如果你有Java基礎的話,那麼理解起來將非常簡單。 基本上,ES6 的class可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,新的class寫法只是讓物件原型的寫法更加清晰、更像物件導向程式設計的語法而已。

//定義類
class Point {
 constructor(x, y) {
   this.x = x;
   this.y = y;
 }

 toString() {
   return '(' + this.x + ', ' + this.y + ')';
 }
}
複製程式碼

我們使用typeof去檢測class的資料型別,會發現class類的本質就是一個方法,也就是構造器。我們不僅僅可以使用new方法來新建一個類,我們也可以使用prototype來訪問類的原型。

(1)constructor

可以看到裡面有一個constructor方法,這就是構造方法,而this關鍵字則代表例項物件。這裡面通常儲存著類基本資料型別

(2)定義類方法

我們可以直接在類中新增自己的方法,前面不需要加上function這個關鍵字,另外,為了使類更加的符合大眾的寫法,去掉了逗號分隔,我們不需要在方法之間使用逗號進行分隔。

(3)類的繼承

es6還給類提供了一個extends的繼承方法。使用方法與java如出一轍。

 class NBAPlayer2 {
       constructor(name, height) {
           this.name = name;
           this.height = height;
       }
       say() {
           console.log(`name is${this.name} height is${this.height}`);
       }
   }
   class MVP2 extends NBAPlayer {
       constructor(name, height, year) {
           super(name, height)
           this.year = year
       }
       say() {
           console.log(`name is${this.name} height is${this.height} mvpyear is${this.year}`);
       }
   }
   var n1 = new MVP2('老庫裡', '201', '2016')
   var m1 = new NBAPlayer2('老庫裡', '201')
   n1.say()
   m1.say()
複製程式碼

注意:使用 extends 關鍵字來實現繼承在子類中的構造器 constructor 中,必須要顯式呼叫父類的 super 方法,如果不呼叫,則 this 不可用

我們如果使用原型去檢視父子類,就會發現,他們其實是通過原型鏈來進行繼承的。

結尾

ES6的新特性還有很多,本次只概述了一些較為常用的方法。適合初識es6的人對es6進行一個大概的瞭解。

關於es6的更多特性,將會在後續進行補充。具體重要內容還有以下

1.Promise 物件

2.Generator

3.async 函式

4.Module 語法

具體深入瞭解可以參考阮大大的 ECMAScript 6 入門

相關文章