javascript在ES6之前是沒(méi)有辦法定義一個(gè)類的,使用構(gòu)造函數(shù)模擬類的概念 ,class
? ES6已經(jīng)有類? class
什么是面向?qū)ο?
面向?qū)ο缶褪悄7氯祟惖男袨槿プ鲆恍┦虑?/p>
使用js得到一個(gè)對(duì)象有幾種方式
? ? ? ? ? ? 第一種得到對(duì)象的方式
var ?p=new object();
? ? ? ? ? ? ?第二種得到對(duì)象的方式
json 簡(jiǎn)單一種javascript對(duì)象
使用工廠模式的方案來(lái)解決代碼的冗余的問(wèn)題
//第一種方式
var person = new Object();
person.age = 18;
person.name = "小紅";
person.say = function() {
//必須加this,指向person對(duì)象所定義的屬性
alert("我的名字是:"+this.name+",我今年"+this.age+"歲了");
}
person.say();
使用這種定義的方式,雖然可以定義一個(gè)對(duì)象,但是因?yàn)闆](méi)有類的約束,所以無(wú)法實(shí)現(xiàn)
對(duì)象的重復(fù)使用,如存在 10 個(gè)人,就要定義 10 個(gè) person,太過(guò)于麻煩了,在操作過(guò)程中存
在問(wèn)題
使用 json? 得到
var person = {
name : "小雷",
age : 18,
say : function() {
alert("我的名字是:"+this.name+",我今年"+this.age+"歲了");
封裝--Javascript? 的 原型(prototype )
function Person() {
}
//使用原型來(lái)給對(duì)象賦值
//這樣就講一個(gè)對(duì)象的屬性和方法放在了該對(duì)象的原型中
//外界是無(wú)法訪問(wèn)到這樣數(shù)據(jù)的
Person.prototype.name = "劉帥哥";
Person.prototype.age = 18;
Person.prototype.say = function() {
alert("我的名字是:"+this.name+",我今年"+this.age+"歲了");
}
var p1 = new Person();
p1.say();//正常訪問(wèn)了
say();//報(bào)錯(cuò)了
原型是 js 中非常特殊一個(gè)對(duì)象,當(dāng)一個(gè)函數(shù)創(chuàng)建之后,會(huì)隨之就產(chǎn)生一個(gè)原型對(duì)象,當(dāng)
通過(guò)這個(gè)函數(shù)的構(gòu)造函數(shù)創(chuàng)建了一個(gè)具體的對(duì)象之后,在這個(gè)具體的對(duì)象中就會(huì)有一個(gè)屬性
指向原型。這就是原型的概念
常見(jiàn)的 原型檢測(cè)方式
可以通過(guò)如下的方式檢測(cè)p1是不是指向Person的原型對(duì)象
alert(Person.prototype.isPrototypeOf(p1))
//檢測(cè)p1的構(gòu)造器是否指向Person對(duì)象
alert(p1.constructor == Person)
//檢測(cè)某個(gè)屬性是不是自己內(nèi)存中的
alert(p1.hasOwnProperty("name"));
alert(p2.hasOwnProperty("name"))
同樣我們可以使用 delete 語(yǔ)句來(lái)刪除我們賦予對(duì)象的自己屬性(注意:原型中的是無(wú)法
刪除的),如
//可以使用delete語(yǔ)句刪除對(duì)象中自己的屬性,那么就會(huì)找到原型中的值
delete p2.name;
p2.say();
alert(p2.hasOwnProperty("name"));
檢測(cè)在某個(gè)對(duì)象自己或者對(duì)應(yīng)的原型中是否存在某個(gè)屬性。
alert("name" in p1);//true
delete p2.name;//雖然刪除了自己的name屬性,但是原型中有
alert("name" in p2);//true
//原型和自己中都沒(méi)有sex屬性
alert("sex" in p1);//false
那么問(wèn)題來(lái)了?如果檢測(cè)只在原型中,不在自己中的屬性呢?(提問(wèn))
//我們可以自己寫代碼來(lái)測(cè)試屬性不在自己,在原型中
function hasPrototypeProperty(obj,prop) {
if (!obj.hasOwnProperty(prop)) {
if (prop in obj) {
return true;
}
}
return false;
}
alert(hasPrototypeProperty(p1,"name"));
alert(hasPrototypeProperty(p2,"name"));
原型 重寫
在上面的寫法中,我們已經(jīng)解決了大量的問(wèn)題,使用原型。但是如果我們的對(duì)象中存在
大量的屬性或者方法的時(shí)候,使用上面的方式,感覺(jué)要寫大量的【對(duì)象.prototype.屬性名 】
這樣的代碼,感覺(jué)不是很好,那么我們可以使用 json 的方式來(lái)寫:
function Person() {
}
Person.prototype = {
name : "劉帥哥",
age : 18,
say : function() {
alert("我的名字是:"+this.name+",我今年"+this.age+"歲了");
}
}
var p1 = new Person();
p1.say()
var p2 = new Person();
p2.name = "張三";
p2.age = 20;
p2.say();
但是這種寫法,我們是將該對(duì)象的原型覆蓋(注意:這兩種寫法不一樣的,第一種是擴(kuò)
充,第二種是覆蓋),就會(huì)出現(xiàn)如下的問(wèn)題:
function Person() {
}
Person.prototype = {
constructor:Person,//手動(dòng)指向Person
name : "劉帥哥",
age : 18,
say : function() {
alert("我的名字是:"+this.name+",我今年"+this.age+"歲了");
}
}
var p1 = new Person();
p1.say()
var p2 = new Person();
p2.name = "張三";
p2.age = 20;
p2.say();
//此時(shí)p1的構(gòu)造器不在指向Person,而是指向了Object
//因?yàn)槲覀兏采w了Person的原型,所以如果constructor比較重要的話,
//我們可以手動(dòng)指向
alert(p1.constructor == Person)
此時(shí)就沒(méi)有問(wèn)題了。但是原型重寫會(huì)給我們帶來(lái)一些非常有趣的現(xiàn)象。下面我們來(lái)研究
研究。
function Person() {
}
var p1 = new Person();
Person.prototype.sayHello = function() {
alert("我的名字是:"+this.name+",我今年"+this.age+"歲了");
}
// p1.sayHello();
Person.prototype = {
constructor:Person,//手動(dòng)指向Person
name : "劉帥哥",
age : 18,
say : function() {
alert("我的名字是:"+this.name+",我今年"+this.age+"歲了");
}
}
var p2 = new Person();
p2.name = "張三";
p2.age = 20;
p1.sayHello();//此時(shí)找不到name和age,但是代碼正確
p2.say();//正確
p1.say();//錯(cuò)誤,因?yàn)樵椭貙懥?/p>
p2.sayHello();//錯(cuò)誤
繼承-- 原型創(chuàng)建對(duì)象
在面向?qū)ο蟮恼Z(yǔ)言中,存在了三大特性—封裝、繼承、多態(tài)。我們前面一直說(shuō) javascript
是面向?qū)ο蟮恼Z(yǔ)言,那么它應(yīng)該也有面向?qū)ο笳Z(yǔ)言這些特性,上面我們看來(lái)封裝,那么下面
我們來(lái)研究繼承。
繼承,望名而知意,就是我們現(xiàn)實(shí)社會(huì)中的子孫后代繼承了父輩的財(cái)富,我們一直在說(shuō),
面向?qū)ο蟮恼Z(yǔ)言就是在模擬現(xiàn)實(shí)世界,通過(guò)模擬現(xiàn)實(shí)世界來(lái)編程,那么在 javascript 中,如
何理解繼承,如何實(shí)現(xiàn)繼承呢?
實(shí)現(xiàn)繼承
//定義一個(gè)父類
function Parent() {
this.pv = "parent";
}
Parent.prototype.showParent = function() {
alert(this.pv);
}
//定義一個(gè)子類
function Son() {
this.sv = "Son";
}
//使用原型鏈來(lái)實(shí)現(xiàn)繼承
Son.prototype = new Parent();
Son.prototype.showSon = function() {
alert(this.sv);
}
var s1 = new Son();
s1.showParent();
s1.showSon();
但是使用原型鏈實(shí)現(xiàn)繼承要注意以下一些問(wèn)題:
1、 不要在設(shè)定了原型鏈之后,再原型重寫
2、 一定要在原型鏈賦值之后才能添加或者覆蓋方法
注意:javascript 中存在重寫,但是沒(méi)有重載
原型 鏈繼承的缺陷
原型鏈繼承存在的缺陷就是:
1、 無(wú)法從子類中調(diào)用父類的構(gòu)造函數(shù),這樣就沒(méi)有辦法把子類中屬性賦值給父類。
2、 父類中屬性是在子類的原型中的,這違背了我們前面所講的封裝的理念(屬性在對(duì)
象中,方法在原型中),會(huì)出現(xiàn)前面值的混淆問(wèn)題。
所以我們一般都不會(huì)使用單純的原型鏈來(lái)實(shí)現(xiàn)繼承。
基于 偽裝實(shí)現(xiàn)繼承
在前面我們學(xué)習(xí)了 call 和 apply 方法,這兩個(gè)方法我們知道可以使用:函數(shù)名.call(上下
文,參數(shù)列表),或:者函數(shù)名.apply(上下文,參數(shù)數(shù)組)的方式來(lái)調(diào)用函數(shù),這樣我們可以通過(guò)
第一個(gè)參數(shù)上下文來(lái)改變調(diào)用函數(shù)的對(duì)象,那么基于這兩個(gè)方法,我們可以實(shí)現(xiàn)一個(gè)基于偽
裝的繼承。
//定義一個(gè)父類
function Parent() {
this.pv = "parent";
}
//定義一個(gè)子類
function Son() {
this.sv = "Son";
Parent.call(this);//注意:此時(shí)的this指的是Son的對(duì)象
//那么就是Son對(duì)象調(diào)用Parent函數(shù)
}
var s1 = new Son();
alert(s1.pv);
在子類中的 this 指的就是子類實(shí)例化后的對(duì)象本身,當(dāng)我們?cè)谧宇愔惺褂?call 方法調(diào)用
父類后,就相當(dāng)于將父類的構(gòu)造方法綁定到了子類的對(duì)象身上,這樣就偽裝了子類可以使用
父類的構(gòu)造方法,完成了繼承。
偽裝 的缺陷
基于偽裝的繼承解決了基于原型鏈的問(wèn)題,但不是說(shuō)它就十分完美,它也存在了問(wèn)題,
如下:
由于使用偽造的方式繼承,子類的原型不會(huì)指向父類,所以父類中寫在原型中的方法不
會(huì)被子類繼承,所以子類調(diào)用不到父類的方法。
解決的辦法就是將父類的方法放到子類中來(lái),但是這樣的又違背了封裝的理念。
ECMAScript6— 面向 對(duì)象
ECMAScript6 是下一代 Javascript 標(biāo)準(zhǔn),這個(gè)標(biāo)準(zhǔn)將在 2015 年 6 月得到批準(zhǔn)。ES6 是
Javascript 的一個(gè)重大的更新,并且是自 2009 年發(fā)布 ES5 以來(lái)的第一次更新。 它將會(huì)在主
要的 Javascript 引擎實(shí)現(xiàn)以下新的特性
class? 關(guān)鍵字
ES6 在面向?qū)ο笫褂昧诵绿匦院驼Z(yǔ)法來(lái)實(shí)現(xiàn),啟用之前的保留字 class 來(lái)申明類,因此
在 ES6 之后,JavaScript 就有了類的定義和實(shí)現(xiàn):
雖然 ES6 的 Class 本質(zhì)上還是語(yǔ)法糖,但這么設(shè)計(jì)有它的目的,首先這樣的書寫形式是
的 JavaScript 的面向?qū)ο蟮膶懛ň秃?Java(一門后端面向?qū)ο蟮恼Z(yǔ)言)看起來(lái)很是類似了。其
次了簡(jiǎn)化了寫法,還讓我們之前將代碼書寫在構(gòu)造函數(shù)外面的那種方法不存在了