整理了在學習ES6關於類的筆記,從基礎使用語法到繼承的實現原理。
基本使用
ES5中建立類的例項,以及如何禁止使用者把類當作普通函式執行(
new target
)
function Person(name,age){
//console.log(new.target); //ES6增加的語法,如果是通過new執行的,返回的結果是當前建立的類;如果是當作普通函執行(Person()),返回的是undefined
if(typeof new.target === 'undefined'){
throw new SyntaxError('當前Person不能作為一個普通函式執行')
}
//new執行的時候,this是當前類的例項,this.xxx=xxx是給當前例項增加的私有屬性
this.name=name;
this.age=age;
}
//原型上存放的是公有的屬性和方法:給建立的例項使用
Person.prototype={
constructor:Person,
say:function(){
console.log(`my name is ${this.name},i am ${this.age} years old`)
}
}
//把Person當作一個普通的物件,給物件設定的私有屬性
Person.study=function(){
console.log('good good study day day up')
}
var p1=new Person('renee',18)複製程式碼
ES6中建立類
class的內部是通過Object.definePropterty來定義的,把公共方法定義在原型鏈上。把靜態方法定義再類上
console.log(Person); //報錯 不存在變數提示
class Person{
constructor(name='無名氏',age=18){
//給例項設定的私有屬性
this.name=name;
this.age=age;
}
//直接在大括號中編寫的方法都設定在類的原型上,ES6預設把constructor的問題解決了,此時原型上的constructor指向的就是Person
say(){
console.log(`my name is ${this.name},i am ${this.age} years old`)
}
//把Person當作普通物件設定屬性和方法,只需要在設定的方法前加static即可
static study(){
console.log('good good study day day up')
}
}
let p1=new Person('renee');
//Person(); //報錯 ES6中使用class建立的類,天生自帶new.target的驗證,不允許把建立的類當作普通函式執行複製程式碼
類的繼承
Object.create
function Parent(){
this.name = 'parent'
}
Parent.prototype.smoking = function(){
console.log('smoking')
}
function Child(){}
// 繼承公有屬性 Object.create是如何實現的
function create(Pproto){
let Fn = function(){} // 建立一個空函式 沒有私有屬性和公用屬性
Fn.prototype = Pproto; // 將父類的公有屬性放在這個函式上
return new Fn(); // 產生的例項就只有公有屬性了
}
Child.prototype =Object.create(Parent.prototype,{constructor:{value:Child}});
let child = new Child();
console.log(child.__proto__=== Child.prototype);
console.log(Child.prototype.constructor == Child);複製程式碼
extends繼承
class Person{
constructor(...arg){
let [x=0,y=0]=arg;
this.x=x;
this.y=y;
}
sum(){
return this.x+this.y;
}
}
class Child extends Person{
//建立了Child類,並且讓Child類繼承了Person類
//1.把Person中的私有屬性繼承過來設定給了子類例項的私有屬性
//2.讓子類例項的原型鏈上能夠找到Person父類的原型(這樣子類的例項就可以呼叫父類原型上的方法了)
//constructor(){}//報錯
//----------------
//我們可以不寫constructor,瀏覽器會預設建立它,而且預設就把父類私有的屬性繼承過來了(而且把傳給子類的引數值也傳遞給父類了)
//constructor(...arg){
//arg:傳遞給子類的引數(陣列),[剩餘運算子]
//super(...arg) //[展開運算子] 把arg中每一項值展開,分別傳遞給父類方法super(10,20,30)
//}
//----------------
//很多時候我們不僅要繼承父類私有的,還需要給子類增加一些額外私有的,此時就必須寫constructor,但是一定要在constructor中第一行寫上super,否則會報錯
constructor(...arg){
super(...arg) //super must be first
let [,,z]=arg;
this.z=z
}
//constructor(x,y,z){
// super() //Person.prototype.constructor.call(this)
// this.z=z;
//}
fn(){
}
}
let c=new Child(10,20,30)
複製程式碼
ES6繼承的實現原理
// 負責將原型的方法和靜態方法定義在建構函式上的
function defineProperties(constructor,properties){
for(let i = 0;i<properties.length;i++){
let obj = {...properties[i],enumerable:true,writeable:true,configurable:true}
Object.defineProperty(constructor,properties[i].key,obj);
}
}
// 對不同的屬性做處理 如果是原型上的方法掛載Class.prototype 如果是靜態方法放在 Class上
function _createClass(con,protoProperty,staticProperty){
if(protoProperty){
defineProperties(con.prototype,protoProperty);
}
if(staticProperty){
defineProperties(con,staticProperty);
}
}
// 父類
var Parent = function(){
function Parent(){
// 類的呼叫檢測
this.name = 'zfpx'
_classCallCheck(this,Parent);
return {a:100}
}
// 用來描述這個類的原型方法和靜態方法
_createClass(Parent,[ // 第一個陣列表示的是公共方法的描述 descirptor
{key:'getName',value:function(){
return 1000
}}
],[ //描述靜態的方法
{key:'fn',value:function(){
return 100;
}}
])
return Parent
}()
// 類的呼叫檢測
function _classCallCheck(instance,constructor){ //檢查當前類 有沒有new出來的,不是new出來的this屬於window
if(!(instance instanceof constructor)) throw Error('without new')
}
// 繼承共有方法和靜態方法
function _inherits(subClass,superClass){
// 子類繼承父類的公有方法
subClass.prototype = Object.create(superClass.prototype,{constructor:{value:subClass}});
// 也要讓子類繼承父類的靜態方法
subClass.__proto__ = superClass;
}
var Child = function(Parent){ // 表示兒子繼承Parent類,要包多一層不然傳參會傳到Child上
_inherits(Child,Parent); // 表示繼承 兒子繼承父親
function Child(){ // 類的呼叫檢查
// 在子類中應該呼叫父類的建構函式
// Parent.call(this);
_classCallCheck(this,Child);
let that = this;
let obj = Object.getPrototypeOf(Child).call(this); // Child.__proto__ = Object.getPrototypeOf(Child) 繼承父類的私有方法,為了保險不用Parent.call(this),因為不一定繼承父類
if(typeof obj === 'object'){ //如果是物件把obj作為例項
that = obj;
}
return that;
}
return Child
}(Parent);
let child = new Child;
console.log(child);複製程式碼