前言

  JavaScript 語言在ES6中引入了 class 這一個關鍵字,在學習面試的中,經常會遇到面試官問到談一下你對 ES6 中class的認識,同時我們的程式碼中如何去使用這個關鍵字,使用這個關鍵字需要注意什麼,這篇來總結一下相關知識點。

正文

  1.es6之前建立物件

  先來看下es6之前我們要想建立一個物件,只能通過建構函式的方式來建立,將靜態方法新增在原型上面使得每一個例項能夠呼叫該方法。

        function Person(name, age) {
this.name = name
this.age = age
Person.prototype.sayHello = function () {
return "hello," + this.name + ",早上好"
}
}
let person = new Person("serendipity", 18)
console.log(person.sayHello())//hello,serendipity,早上好
console.log(person instanceof Person);//true
console.log(person instanceof Object);//true

  2.es6之後class的宣告

  類是用於建立物件的模板,他們用程式碼封裝資料以處理該資料。js中的 class 類建立在原型之上,但也具有某些語法和語義與ES5類相似語義共享。

  實際上,類是一種特殊的函式,就像定義函式宣告和函式表示式一樣,類的語法也有兩個部分組成:類宣告和類表示式。

        class Person {
constructor(name, age) {//自有屬性,該屬性出現在例項上,只能在類的構造器或者方法內部進行建立
this.name = name
this.age = age
}
sayHello() {//等價於Perosn.prototype.sayHello
return `hello,${this.name},早上好`
}
}
let person = new Person("serendipity", 18)
console.log(person.sayHello());//hello,serendipity,早上好
console.log(person instanceof Person);//true
console.log(person instanceof Object);//true
console.log(typeof Person);//function
console.log(typeof Person.prototype.sayHello);//function

  類宣告允許在class中使用 constructor 方法定義一個構造器,而不需要定義專門的構造方法來當構造器使用。

  class 類的語法與普通es5之前的函式語法相似,但是還存在一些特性需要注意:

  (1)類的宣告不會被提升,類的宣告行為和 let 相似,因此執行時類會存在暫時性死區;

  (2)類中所有程式碼自動執行在嚴格模式下,且改嚴格模式無法退出

  (3) 類中所有方法都是不可列舉的,普通自定義方法只有通過 object.defineProperty() 才能將方法定義為不可列舉

  (4)類中的所有方法內部都沒有 [[construct]] ,因此使用new 來呼叫他們會丟擲錯誤

  (5)呼叫類構造器時不使用 new 會丟擲錯誤

  (6)試圖在類的方法內部重寫類名會丟擲錯誤

  將上面的程式碼轉換為ES5之前的寫法如下:

        let PersonClass = (function () {
"use strict"
const PersonClass = function (name, age) {
// 判斷是否被new呼叫建構函式
if (typeof new.target === "undefined") {
throw new Error("Constructor must be call with new.")
}
this.name = name
this.age = age
}
Object.defineProperty(PersonClass.prototype, "sayHello", {
value: function () {
if (typeof new.target !== "undefined") {//保正呼叫時沒有使用new
throw new Error("Method cannot be called with new.")
}
return "hello," + this.name + ",早上好!"
},
enumerable: false,
configurable: true,
writable: true
})
return PersonClass
})()
var personClass = new PersonClass("serendipity", 18)
console.log(personClass.name);//serendipity
console.log(personClass.sayHello());///hello,serendipity,早上好!

  兩個PersonClass 宣告,一個在外部作用域的 let 宣告,另一個在立即執行函式內部的 const 宣告,這就是為何類的方法不能對類名進行重寫,而類的外部的程式碼則被允許。同時,只在類的內部類名才被視為使用了const宣告,這意味著你可以在外部(相當於let)重寫類名,但是不能在類的方法內部這麼寫。

  3.類的繼承

  ES6之前的繼承方式主要通過建構函式和原型鏈組合的方式來實現繼承,具體程式碼如下:

        function Rectangle(length, width) {
this.length = length
this.width = width
Rectangle.prototype.getArea = function () {
return this.length * this.width
}
}
function Square(length) {
Rectangle.call(this, length, length)
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
value: Square,
enumerble: true,
writeable: true,
configurable: true
}
})
var square = new Square(3)
console.log(square.getArea());//9
console.log(square instanceof Square);//true
console.log(square instanceof Rectangle);//true

  上面的程式碼通過建構函式和原型上面新增靜態方法實現了 Rectangle 父類,然後子類 Square 通過 Rectangle.call(this,length,length) 呼叫了父類的建構函式,Object.create 會在內部建立一個空物件來連線兩個原型物件,再手動將 constructor 指向自身。這種方法實現繼承程式碼繁雜且不利用理解,於是ES6 class 類的建立讓繼承變得更加簡單,使用extends 關鍵字來指定當前類所需要繼承的父類,生成的類的原型會自動調整,還可以使用 super() 方法來訪問基類的構造器。具體程式碼如下:

        class Rectangle {
constructor(length, width) {
this.length = length
this.width = width
}
getArea() {
return this.length * this.width
}
}
class Square extends Rectangle {
constructor(length) {
super(length, length)
}
getArea() {
return this.length + this.length
} }
var square = new Square(3)
console.log(square.getArea());//6
console.log(square instanceof Square);//true
console.log(square instanceof Rectangle);//true

  上面的程式碼中 Square 類重寫了基類的 getArea() 方法,當派生的子類中函式名和基類中函式同名的時候,派生類的方法會遮蔽基類的方法,同時也可以再子類中getArea () { return super.getArea() }中呼叫基類的方法進行擴充套件。

  4.繼承類的靜態成員

  靜態成員:直接在構造器上新增的額外的方法。例如ES5中在原型上新增的方法就屬於靜態成員,ES6 class類引入簡化了靜態成員的建立,只需要在方法與訪問器屬性的名稱前新增 static關鍵字即可。例如下面的程式碼用於區分靜態方法和例項方法。

    function PersonType(name) {
this.name = name;
}
// 靜態方法
PersonType.create = function(name) {
return new PersonType(name);
};
// 例項方法
PersonType.prototype.sayName = function() {
console.log(this.name);
};
  var person = PersonType.create("Nicholas");

  在ES6中要想使用靜態成員如下:

        class Rectangle {
constructor(length ,width) {
this.length = length
this.width = width
}
getArea() {
return this.length * this.width
}
static create(length,width) {
return new Rectangle(length , width)
}
}
class Square extends Rectangle{
constructor (length){
super(length,length)
}
}
var square =Square.create(3,4)
console.log(square.getArea());//12
console.log(square instanceof Square);//false
console.log(square instanceof Rectangle);//true

  上面的程式碼中,一個新的靜態方法 create() 被新增到 Rectangle 類中,通過繼承,以Square.create() 的形式存在,並且其行為方式與Rectangle.create() 一樣。需要注意靜態成員不懂通過例項來訪問,始終需要直接呼叫類自身來訪問他們。

寫在最後

  以上就是本文的全部內容,希望給讀者帶來些許的幫助和進步,方便的話點個關注,小白的成長踩坑之路會持續更新一些工作中常見的問題和技術點。