javascript面向?qū)ο蟪绦蛟O(shè)計(jì)(一)
注釋里講解的十分細(xì)致了,這里就不多廢話了,直接上代碼:
<script type="text/javascript">
//ECMA-262把對(duì)象定義為:“無(wú)序?qū)傩缘?集合,其屬性可以包含基本值、對(duì)象或者函數(shù)”
//理解對(duì)象,最簡(jiǎn)單的方式就是通過(guò)創(chuàng)建一個(gè)Object的實(shí)例,然后為它添加屬性和方法
var person = new Object();
person.name = "Xulei";
person.age = "23";
person.job = "前端工程師";
person.sayName = function () {
alert(this.name);
}
//還可以這樣寫(xiě)
var person = {
name: "xulei",
age: 23,
job: "前端工程",
sayName: function () {
alert(this.name)
}
}
//一、屬性類(lèi)型:數(shù)據(jù)屬性和訪問(wèn)其屬性
//1、數(shù)據(jù)屬性,有4個(gè)描述其行為的特性
//[Configurable]:表示能否通過(guò)delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問(wèn)器屬性,默認(rèn)值為true
//[Enumerable]:表示能否通過(guò)for-in返回屬性,默認(rèn)值為true
//[Writable]:表示能否修改屬性,默認(rèn)值為true
//[Value]:包含這個(gè)屬性的數(shù)據(jù)值。默認(rèn)值為undefined
var person = {
name: "xulei"
}
//這里創(chuàng)建了一個(gè)person對(duì)象,value值就是“xulei”
//要修改屬性的默認(rèn)特性,必須使用ECMAScript5的Object.defineProperty(屬性所在的對(duì)象,屬性的名字,描述符對(duì)象)
//描述符對(duì)象必須是configurable、enumerable、writable、value
var peron = {}
Object.defineProperty(peron, "name", {
writable: false,//屬性不能被修改
value: "徐磊-xulei"
});
alert(peron.name);//徐磊-xulei
peron.name = "徐磊";
alert(peron.name);//徐磊-xulei
//以上操作在非嚴(yán)格模式下賦值操作會(huì)被忽略,如果在嚴(yán)格模式下會(huì)拋出異常
//一旦把屬性定義為不可配置的就不能把它變回可配置的了。
//在多數(shù)情況下都沒(méi)有必要利用Object.defineProperty()方法提供的這些高級(jí)功能。但是對(duì)理解javascript非常有用。
//建議讀者不要在ie8上使用此方法。
//2、訪問(wèn)其屬性,有4個(gè)特性
//[Configurable]:表示能否通過(guò)delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問(wèn)器屬性,默認(rèn)值為true
//[Enumerable]:表示能否通過(guò)for-in返回屬性,默認(rèn)值為true
//[Get]:在讀取時(shí)調(diào)用的函數(shù) 默認(rèn)值undefined
//[Set]:在寫(xiě)入屬性時(shí)調(diào)用的函數(shù) 默認(rèn)值Undefined
var book={
_year:2004,
edition:1
}
Object.defineProperty(book,"year",{
get:function(){
return this._year;
},
set:function(value){
if(value>2004){
this._year=value;
this.edition +=value-2004;
}
}
});
book.year=2005;
alert(book.edition);//2
//創(chuàng)建對(duì)象
//1、將構(gòu)造函數(shù)當(dāng)做函數(shù)
function Person(name,age,job) {
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
alert(this.name);
}
}
//當(dāng)做構(gòu)造函數(shù)使用
var person=new Person("xulei",23,"software");
person.sayName();
//作為普通函數(shù)使用
Person("xulei2",23,"job2");//添加到window中
window.sayName();
//在另一個(gè)對(duì)象的作用域中調(diào)用
var o=new Object();
Person.call(o,"xulei3",23,"job3");
o.sayName();
</script>
再來(lái)一段:
<script type="text/javascript">
//1、理解原型對(duì)象
//2、原型與in操作符
//3、更簡(jiǎn)單的原型語(yǔ)法
//4、原型的動(dòng)態(tài)性
//5、原生對(duì)象原型
//6、原型對(duì)象的問(wèn)題
//1、無(wú)論什么時(shí)候,只要?jiǎng)?chuàng)建了一個(gè)函數(shù),就會(huì)根據(jù)一組特定的規(guī)則,為該函數(shù)創(chuàng)建一個(gè)prototype屬性,該屬性指向函數(shù)的原型對(duì)象
//在默認(rèn)情況下,所有的原型對(duì)象都會(huì)自動(dòng)獲得一個(gè)constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性包含一個(gè)指向prototype屬性所在函數(shù)的指針
//如
function Person(){
}
//Person.prototype.constructor 指向Person
//創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得constructor屬性,至于其他方法則都是從Object繼承而來(lái)
//當(dāng)調(diào)用函數(shù)的創(chuàng)建一個(gè)新實(shí)例之后,該實(shí)例的內(nèi)部包含一個(gè)指針(內(nèi)部屬性)指向構(gòu)造函數(shù)的原型對(duì)象
//在Firefox、safari、chrome在每個(gè)對(duì)象上都支持一個(gè)屬性_proto_訪問(wèn)
var p1=new Person();
alert(Person.prototype.isPrototypeOf(p1))
alert(Object.getPrototypeOf(p1)==Person.prototype)
//雖然可以通過(guò)對(duì)象實(shí)例訪問(wèn)保存在原型中的值,但卻不能通過(guò)對(duì)象實(shí)例重寫(xiě)原型中的值。如果我們?cè)趯?shí)例中添加了一個(gè)屬性
//而該屬性的名稱(chēng)與原型的中的實(shí)例同名,那我們就在實(shí)例中創(chuàng)建該屬性,該屬性將會(huì)屏蔽原型中的那個(gè)屬性。eg:
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
person1.name="amber.Xu";
alert(person1.name);//amber.xu --來(lái)自實(shí)例
alert(person2.name);//amber --來(lái)自原型
delete person1.name;
alert(person1.name);//amber --來(lái)自原型
//使用hasOwnProperty()方法可以檢測(cè)一個(gè)屬性是存在于實(shí)例中還是存在于原型中,這個(gè)方法(從Object繼承而來(lái))
//只在給定屬性存在于對(duì)象實(shí)例中時(shí),才會(huì)返回true
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
alert(person1.hasOwnProperty("name"));//false 來(lái)自實(shí)例
alert(person2.hasOwnProperty("name"));//false 來(lái)自實(shí)例
person1.name="amber.xu";
alert(person1.name);
alert(person1.hasOwnProperty("name"));//true 來(lái)自實(shí)例
delete person1.name;
alert(person1.name);
alert(person1.hasOwnProperty("name"));//false 來(lái)自原型
//2、原型與in操作符
//in 有兩種使用方式,一個(gè)是的單獨(dú)使用和在for-in 中使用。在單獨(dú)使用時(shí),in操作符會(huì)在對(duì)象能夠訪問(wèn)給定屬性時(shí)返回true
//無(wú)論該屬性時(shí)來(lái)自原型還是實(shí)例
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
alert("name" in person1);//true 來(lái)自原型
alert("name" in person2);//true 來(lái)自原型
alert("height" in person1);//false
//這樣就可以封裝一個(gè)函數(shù)(給定屬性是否是來(lái)給定對(duì)象的原型)
function hasPrototypeProperty(object,name){
return !object.hasOwnProperty(name) && (name in object);
}
alert("----------------------------------");
alert(hasPrototypeProperty(person1,"name"));//true
person1.name="張三";
alert(hasPrototypeProperty(person1,"name"));//false
//使用for-in 返回的是所有能夠通過(guò)對(duì)象訪問(wèn)、可枚舉的屬性,其中既包含原型屬性也包含實(shí)例屬性。
//屏蔽了原型中不可枚舉屬性(將Enumerable標(biāo)記為false的屬性)的實(shí)例屬性也會(huì)在for-in中返回
//ie早期版本總中有一個(gè)bug:屏蔽了原型中不可枚舉屬性的實(shí)例屬性也不會(huì)在for-in中返回
//eg:
var o={
toString:function(){
return "my object";
}
};
for(var prop in o){
if(prop=="toString"){
alert("找到了");//在ie早期版本中不會(huì)顯示
}
}
//要取得對(duì)象上所有可枚舉的屬性,可以使用ECMAScript5的Object.keys()方法。接受一個(gè)對(duì)象作為參數(shù),
//包含所有可枚舉屬性的字符串?dāng)?shù)組
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
var keys=Object.keys(Person.prototype);
alert(keys)
person1.name="amber.Xu";
person1.age=23;
var keys=Object.keys(person1);
alert(keys)
alert("-----------------------------------------")
//如果想要得到所有的實(shí)例屬性不管他是否可以枚舉,都可以使用
alert(Object.getOwnPropertyNames(person1));
alert(Object.getOwnPropertyNames(Person.prototype));
alert("更簡(jiǎn)單的原型語(yǔ)法-----------------------------------------")
//3、更簡(jiǎn)單的原型語(yǔ)法
function Person() {
}
Person.prototype={
name:"AMBER",
age:23,
job:"software",
sayName:function(){
alert(this.name)
}
}
//這樣寫(xiě)之后constructor屬性不再指向Person函數(shù),而是指向Object構(gòu)造函數(shù)。
//盡管通過(guò)instanceof操作符還能返回正確的結(jié)果,但是通過(guò)constructor已經(jīng)無(wú)法確定對(duì)象的類(lèi)型了,eg:
var friend=new Person();
alert(friend instanceof Person)//true
alert(friend instanceof Object)//true
alert(friend.constructor==Person);//false
alert(friend.constructor==Object);//true
//如果constructor對(duì)你真的很重要,可以向下面一樣設(shè)置成適當(dāng)?shù)闹?
function Person() {
}
Person.prototype={
constructor:Person,
name:"AMBER",
age:23,
job:"software",
sayName:function(){
alert(this.name)
}
}
var friend=new Person();
alert("手動(dòng)設(shè)置constructor-----------------------------------------")
alert(friend.constructor==Person);//true
//這種手動(dòng)的添加了constructor會(huì)使constructor變成可枚舉的元(原生的constructor屬性時(shí)不可枚舉的)。
//這種情況下就可以使用
Object.defineProperty(Person.prototype,"constructor",{
enumerable:false,
value:Person
});
//原型的動(dòng)態(tài)性
var friend=new Person();
Person.prototype.sayHi=function(){
alert("Hi");
}
friend.sayHi();//Hi (正常執(zhí)行)
//因?yàn)閷?shí)例和原型之間是松散的連接關(guān)系,實(shí)例與原型之間的連接只不過(guò)是一個(gè)指針,而非副本
//當(dāng)我們調(diào)用sayHi()方法時(shí),首先會(huì)在實(shí)例中搜索名為sayHi的方法,在沒(méi)找到的情況下會(huì)搜索原型。
//但是,如果是重寫(xiě)整個(gè)原型對(duì)象,那么情況就不一樣了。
//我們知道,調(diào)用構(gòu)造函數(shù)時(shí)會(huì)為實(shí)例添加一個(gè)指向最初原型的Prototype指針,而把原型修改為另一個(gè)對(duì)象就等于切斷了構(gòu)造函數(shù)與最初原型之間的聯(lián)系。
//請(qǐng)記?。簩?shí)例中的指針僅指向原型,而不指向構(gòu)造函數(shù)。eg:
function A(){}
var a1=new A();
A.prototype={
constructor:A,
name:"AMBER",
age:23,
job:"software",
sayName:function(){
alert(this.name)
}
}
alert("ERROR-------------------------------------");
alert(a1.sayName());
//我們創(chuàng)建了一個(gè)A的實(shí)例,然后又重寫(xiě)了其原型對(duì)象,然后在調(diào)用a1.sayName()發(fā)生了錯(cuò)誤,因?yàn)閍指向的原型中不包含以該名字命名的屬性/方法
//原生對(duì)象的原型
//原型模式的重要性不僅體現(xiàn)在創(chuàng)建自定義類(lèi)型方面。就連所有的原生的引用類(lèi)型,都是采用這種模式創(chuàng)建的。所有的原生引用類(lèi)型
//都在其構(gòu)造函數(shù)的原型上定義的方法 eg:
alert(typeof Array.prototype.sort);//function
alert(typeof String.prototype.substring);//function
//不僅可以在原生對(duì)象的原型取得雖有默認(rèn)方法的引用,而且可以定義新的方法
//為String類(lèi)型添加一個(gè)startsWith()的方法
String.prototype.startsWith=function(text){
return this.indexOf(text) == 0;
};
var msg="Hello";
alert(msg.startsWith("H"));
//我們并不建議這樣做。
alert("原型對(duì)象的問(wèn)題");
//6、原型對(duì)象的問(wèn)題 實(shí)例
function Ques() {
}
Ques.prototype={
constructor:Ques,
name:"amber",
age:23,
job:"IT",
friends:["張三","李四"],//引用類(lèi)型
sayName:function(){
alert(this.name)
}
};
var q1=new Ques();
var q2=new Ques();
q1.friends.push("王五");
alert(q1.friends);//
alert(q2.friends);//
alert(q1.friends===q2.friends);
//相信大家已經(jīng)看到了問(wèn)題,當(dāng)我創(chuàng)建了兩個(gè)實(shí)例q1、q2,當(dāng)我為q1的“朋友”添加了“王五”之后,q2的”朋友“也有了三個(gè)張三、李四、王五
//那是因?yàn)閿?shù)組存在于Ques.prototype上,而非q1上。所以出現(xiàn)了如上結(jié)果。
//而正是這個(gè)問(wèn)題,我們很少看到有人單獨(dú)使用原型模式的原因所在。
</script>
本文就先到這里了,后續(xù)我們?cè)倮^續(xù)討論javascript面向?qū)ο蟪绦蛟O(shè)計(jì),希望大家能夠喜歡。
相關(guān)文章
理解JavaScript設(shè)計(jì)模式中的單例模式
這篇文章主要介紹了理解JavaScript設(shè)計(jì)模式中的單例模式,單例模式即Singleton?Pattern是最簡(jiǎn)單的設(shè)計(jì)模式之一,下文更多相關(guān)介紹感興趣的小伙伴可以參考一下2022-04-04
List the Codec Files on a Computer
List the Codec Files on a Computer...2007-06-06
Js之軟鍵盤(pán)實(shí)現(xiàn)(js源碼)
Js之軟鍵盤(pán)實(shí)現(xiàn)(js源碼)...2007-01-01
javascript上下方向鍵控制表格行選中并高亮顯示的方法
這篇文章主要介紹了javascript上下方向鍵控制表格行選中并高亮顯示的方法,涉及javascript針對(duì)鍵盤(pán)按鍵操作相應(yīng)的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
Three.js后期處理效果(發(fā)光描邊OutlinePass)
這篇文章主要給大家介紹了關(guān)于Three.js后期處理效果(發(fā)光描邊OutlinePass)的相關(guān)資料,Three js 開(kāi)發(fā)的一些知識(shí)整理,方便后期遇到類(lèi)似的問(wèn)題,能夠及時(shí)查閱使用,需要的朋友可以參考下2024-01-01
javascript 10進(jìn)制和62進(jìn)制的相互轉(zhuǎn)換
本節(jié)主要介紹了javascript 10進(jìn)制和62進(jìn)制的相互轉(zhuǎn)換,需要的朋友可以參考下2014-07-07
Bootstrap 折疊(Collapse)插件用法實(shí)例詳解
這篇文章主要介紹了Bootstrap 折疊(Collapse)插件用法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-06-06
javascript for循環(huán)設(shè)法提高性能
讓你的for循環(huán)提升性能的寫(xiě)法,需要的朋友可以參考下。2010-02-02

