javaScript 語言中,生成實例對象的傳統方法是經過構造函數,與傳統的面嚮對象語言(好比 C++ 和 Java)差別很大,ES6 提供了更接近傳統語言的寫法,引入了 class(類)這個概念,做爲對象的模板。經過class
關鍵字,能夠定義類。java
es6 class 與es5的面向對象的區別:es6
1. 通常寫法(es5 與es6)數組
//一.ES5寫法: function Animate(name){ this.name = name; } Animate.prototype.getname = function(){ console.log(this.name) } var p =new Animate("lity"); p.getname(); //二.ES6,面向對象的寫法,calss, class Person{ //constructor():構造方法是默認方法,new的時候回自動調用,若是沒有顯式定義,會自動添加 //1.適合作初始化數據 //2.constructor能夠指定返回的對象 constructor(name,age){ this.name = name; this.age = age; } getval(){ console.log(`你是${this.name},${this.age}歲`); } } var c1 = new Person("lity",20);
c1.getval();
ES6 的class
能夠看做只是一個語法糖,它的絕大部分功能,ES5 均可以作到函數
注意 :class 類的本質仍是一個函數,類自己就指向構造函數。this
typeof Person //function Person === Person.prototype.constructor // true
咱們使用Object的一些屬性或者方法檢測一下 用es6 寫的實例對象es5
//1.查看實例對象c1的__proto__是否指向Person的原型(Person.prototype) console.log(c1.__proto__==Person.prototype)//true console.log(c1.__proto__)//原型對象的全部方法 //2.isPrototypeOf:檢測實例對象是不是某個函數的原型 console.log(Person.prototype.isPrototypeOf(c1));//true //3.constructor:查看某個對象的構造函數 console.log(c1.constructor); //4.hasOwnProperty:檢測某個屬性是不是本身的屬性;不是原型對象上的屬性和方法 console.log(c1.hasOwnProperty("name"))//true; //5.in:經過in能夠檢測屬性是否在本身中(this)或者是原型中存在 console.log("getval" in c1)//原型上存在,true console.log("name" in c1)//constructor(本身上存在),true //6.自定義檢測屬性是不是存在 function hasproperty(attr,obj){ return obj.hasOwnProperty(attr)&&(attr in obj); } console.log(hasproperty("name",c1));//true;
2.表達式寫法spa
//class表達式 const Myclass = class Me{//這裏的Me是沒有做用的 constructor(name,jog){ this.name = name; this.jog = jog; } getval(){ console.log(`name is ${this.name},job is a ${this.jog}`); } } var obj1 = new Myclass("lylt","teacher"); obj1.getval();
3.class的私有方法(ES6不提供寫法)和私有屬性(也不提供寫法,提案用#識別)prototype
4.ES6規定Class類沒有靜態屬性,只有靜態方法:static代理
class Foo { static classMethod() { return 'lity'; } } console.log(Foo.classMethod()) // 'hello'
5.new.target屬性code
//ES5:原始寫法對象 function objtarge(name){ if(new.target==undefined){ throw new Error("必須實例化對象"); }else{ this.name = name } } var targets = new objtarge("litys"); console.log(targets.name);//litys //es6寫法:class內部使用new.target,返回當前的calss class caltartget{ constructor(name){ console.log(new.target==caltartget);//true if(new.target!==caltartget){ throw new Error("實例化對象不是caltrget"); }else{ this.name = name; } } } var caltart = new caltartget("lity"); console.log(caltart.name);//lity
6.this指向
類的方法內部若是含有this
,它默認指向類的實例。可是,必須很是當心,一旦單獨使用該方法,極可能報錯
以下示例
class Logger { printName(name = 'there') { this.print(`Hello ${name}`); } print(text) { console.log(text); } } const logger = new Logger(); const { printName } = logger; printName(); // TypeError: Cannot read property 'print' of undefined
分析以上示例:prinName 的方法中this,默認指向 類Logger,可是將改方法單獨調用,就會報錯,this會指向所在運行的環境,因此由於找不到this.print()方法而報錯。
針對以上解決this指向的方法:
(1). 使用bind(this)
(2). 使用es6 的箭頭函數 ()=>{}
(3).使用Proxy 代理
//1.bind()方法 class Logger { constructor() { this.printName = this.printName.bind(this); } // ... } //2.箭頭函數 ()=>{} class Logger { constructor() { this.printName = (name = 'there') => { this.print(`Hello ${name}`); }; } // ... } //3. Porxy() .................
7.class 的get() 和set() 方法
與 ES5 同樣,在「類」的內部可使用get
和set
關鍵字,對某個屬性設置存值函數和取值函數,攔截該屬性的存取行爲。
class MyClass { constructor() { // ... } get prop() {// 使用 get 攔截了該方法的返回值 return 'getter'; } set prop(value) {//當對該方法賦值時能獲取到該賦值 console.log('setter: '+value); } } let obj = new MyClass(); obj.prop = 123; // setter: 123 inst.prop // 'getter'
8.繼承
Class 能夠經過extends
關鍵字實現繼承,這比 ES5 的經過修改原型鏈實現繼承,要清晰和方便不少。
//es5 的繼承 //父類 function Person(name,sex){ this.name = name;//屬性 this.sex = sex;//屬性 } //定義一個原型方法 Person.prototype.show = function(){ console.log("個人姓名是"+this.name+"==="+"個人性別是"+this.sex) } //子類 function Worker(name,sex,job){ //構成函數假裝:使用call()方法綁定this,假裝繼承父級的屬性 Person.call(this,name,sex); this.job = job; } //繼承父類的原型方法:(介紹三種方法) //寫法一:經過遍歷父級的原型一個個賦給子級的原型(es5 的原型是可枚舉的,es6的不能夠枚舉) (var i in Person.prototype){ Worker.prototype[i] = Person.prototype[i]; } //寫法:從新new一個父級對象賦給子級的原型 Worker.prototype = new Person(); Worker.prototype.constructor = Worker; //寫法三:建立一個原型對象賦給子級的原型;(es5 推薦) Worker.prototype = Object.create(Person.prototype); Worker.prototype.constructor = Worker; var workers = new Worker("小明","男","job") //es6 的繼承 class Person{ constructor(name,sex){ this.name = name;//屬性 this.sex = sex;//屬性 } } class Worker extends Person{ constructor(name,sex,job){ super(); this.job =job; } } var workers = new Worker("小明","男","job")
8.1:super關鍵字:在子類中不一樣狀況用法不一樣,既能夠看成函數使用,也能夠看成對象使用。
//父類 class Aniamte{ constructor(){ if(new.target == Aniamte){ throw new Error("本類不能實例化,只能有子類繼承"); } } //靜態方法 static getval(mgs){ console.log("父類的static",mgs) } //普通方法 setname(){ console.log("該方法有子類重寫") } } //子類 class Dog extends Aniamte{ constructor(){ super();//調用此方法,this才用能夠用,表明父類的構造函數,返回的倒是子類 //super() ==父類.prototype.constructor.call(子類/this) console.log(this)//Dog {} this.age = 20; } //靜態方法,super在靜態方法中做爲對象使用,指向父類; static getval(mgs){ super.getval(mgs)//父類的static niceday console.log("子類的static",mgs)//子類的static niceday } setname(name){ //普通方法,super做爲對象使用,指向父類的原型對象,父類.prototype; super.setname();//該方法有子類重寫 this.name = name; return this.name } }; Dog.getval("niceday");//靜態方法,直接調用 //var parAni = new Aniamte();//報錯 var dogs = new Dog();//new 一個示例對象 dogs.setname("DOYS");////DOYS
8.2.原生構造函數的繼承,ES5不支持,ES6利用extend能夠繼承原生構造函數
//ESMAScript的構造函數有如下幾種 /* Boolean() * Unmber() * String() * Array() * Date() * Function() * RegExp() * Error() * Object() */ //實例一:自定義類Myarray 繼承了原生的數組的構造函數,擁有原生數組的屬性和方法了 class Myarray extends Array{ constructor(){ super(); console.log(this.constructor.name)//Myarray } } var myarr = new Myarray(); console.log(Object.prototype.toString.call(myarr));//[object Array] myarr.push(1,2,1); console.log(myarr.length)//3