物件是Js核心概念之一,也是最常用的資料型別,即參考型資料,物件可以包含多個屬性,屬性以名值對的形式存在,它是一種復合值,
它將很多值(原始值或者其他物件)聚合在一起,可通過名字訪問這些值,構成一個無序集合,除了字串、數字、true、false、null
和undefined之外, Js中其他的值都是物件,
1.1創建物件
創建物件有三種方法,具體如下:
1.1.1使用建構式創建物件
使用new運算子呼叫函式,可以構造一個實體物件,
用法如下:
1 var objectName=new functionName(args);
簡單說明如下:
|
objectName |
表 示 構 造 的 實 例 對 象 |
|
functionName |
是一個建構式 , 一般情況下,它不需要回傳值 , 建構式體內可以使用this指代objectName實體物件 |
|
args |
表 示 參 數 列 表 |
用法1:使用建構式創建物件
1 var o=new Object(); 2 var o=new Array(); 3 var o=new MyClass();
如length屬性可以獲得該陣列的元素個數,而push()方法將會為該陣列物件添加新元素,
1 var o = new Array(); 2 document.write(o.length + '<br>'); 3 var l = o.push(1, 2, 3); 4 document.write(l);
使用new運算子可以呼叫它們,并初始化為一個個物件實體,
在Js中建構式具有如下特性:
-
使用new運算子進行呼叫,也可以使用小括號呼叫,但回傳值不同,
-
建構式內部通過this關鍵字指代實體化物件,或者指向呼叫物件,
-
在建構式內可以通過點運算子生命本地成員,當然建構式結構體內也可以包含私有變數或函式,以及任意執行陳述句,
用法2:使用建構式定義一個Book類,定義兩個引數,
1.1.2new關鍵字
javascript中的new是一個語法糖,對于學過別的語言等的人來說,以為js里面是有類和物件的區別的,實作上js并沒有類,一切皆物件,
new的程序實際上是創建一個新物件,把新物件的原型設定為構造器函式的原型,在使用new的程序中,一共有3個物件參與了協作,
構造器函式是第一個物件,
原型物件是二個,新生成了一個空物件是第三個物件,最侄訓傳的是一個空物件,但這個空物件不是真空的,而是已經含有原型的
參考(__proto__),

通過new創建物件經歷4個步驟:
創建一個新物件:
[var o = {};]
-
將建構式的作用域賦給新物件(因此this指向了這個新物件);[Person.apply(o)] [Person原來的this指向的是[window]
-
執行建構式中的代碼(為這個新物件添加屬性);
-
回傳新物件,
1.1.3使用物件直接量創建物件
物件直接量提供了另一種創建新物件的方式,物件直接量允許將物件描述文字嵌入到JavaScript代碼中,就比如將文本資料嵌入在
JavaScript代碼中,也就像將文本資料嵌入在JavaScript代碼中作為參考的字串一樣,物件直接量是由屬性說明串列構成的,
這個串列包含在大括號之中,屬性與屬性之間通過逗號進行分隔,最后一個屬性末尾不需要逗號,
物件直接量中的每個屬性說明串列都由:
-
一個屬性名可以是Js的識別符號
-
及跟在其后的冒號和屬性值構成
-
或任意形式的字串
-
屬性值可以是任意型別的資料,
使用物件直接量創建物件的一般格式如下:
var objectName = {屬性名1:屬性值1,屬性2:屬性值,...,屬性名n:屬性值n}
具體例子如下:
var WangLiang={
name:王亮,
age:24
}
從上面的定義中可以看出,這種定義方式實際上是宣告一種型別的變數,并同時進行了賦值,因此,宣告后的物件直接量可以在代碼中直接使用,而不必使用
new關鍵字來創建物件,
1.1.4使用create()方法創建物件
Object.create()方法是ECMAScript 5中新增的方法,直接呼叫該方法可以快速創建一個新物件,它能夠創建一個具有指定原型且可選擇地包
含指定屬性的物件,
具體用法如下:
Object.create(prototype,descriptors)
引數說明如下:
|
prototype |
必須引數,要用作原型的物件,可以為null, |
|
descriptors |
可選引數,包含一個或多個屬性描述符的Js物件, |
提示:
在descriptors中,資料屬性描述符包含value特性、enumerable(是否可列舉屬性)和configurable(是否可修改特性和洗掉屬性)特性,如果未指定最后3個特性,則它們的值默認為false,
下面用法:
var firstLine = { x: undefined, y: undefined };
var secondLine = Object.create(Object.create(Object.prototype, {
x: {
value: undefined,
writable: true,
configurable: true,
enumerable: true
},
y: {
value: undefined,
writable: true,
configurable: true,
enumerable: true
}
}))
document.write('firstline prototype =' + Object.getPrototypeOf(firstLine));
document.write('<br>')
document.write('second line prototype =' + Object.getPrototypeOf(secondLine));
2.1操作物件
物件除了包含屬性之外,每個物件還擁有了3個相關的物件特性:
|
物件的原型(prototype) |
指向另外一個物件,本物件的屬性繼承自它的原型物件 |
|
物件的類(class) |
是一個標識物件型別的字串 |
|
物件的擴展標記(extensible flag) |
指明了是否可以向該物件添加新屬性 |
2.1.1參考物件
在創建物件之后,可以把物件的地址賦值給變數,實作變數對物件的參考,當把變數賦值給其他變數時,則實作多個變數
參考同一個物件,
下面用法:
WangLiang= {
name: '王亮',
age: 24
}
wangliang= wangliang;
document.write(delete wangliang);
document.write(wangliang.x);
2.1.2復制物件
復制物件的設計思路是:利用for/in陳述句遍歷物件成員,然后逐一復制給另一物件,
用法1:
function F(x, y) {
this.x = x;
this.y = y;
this.add = function () {
return this.x + this.y;
}
this.min = function () {
return this.x - this.y;
}
}
F.prototype.mul = function () {
return this.x * this.y;
}
F.prototype.except = function () {
return this.x / this.y;
}
var f = new F(24, 12);
var o = {};
for (var i in f) {
o[i] = f[i];
}
document.write(o.x + '<br>');
document.write(o.y + '<br>');
document.write(o.add() + '<br>');
document.write(f.min() + '<br>');
document.write(f.mul() + '<br>');
document.write(o.except() + '<br>');
對于該復制法,還可以進行封裝,具有靈活性:
Function.prototype.extend=function(o){
for(var i in o){
this.constructor.prototype[i]=o[i];
}
}
-
上面的封裝函式通過原型為函式function型別物件擴展一個方法,該方法能把指定的引數物件完全復制給當前物件的建構式的原型物件,
-
this關鍵字指向是當前實體物件,而不是建構式本身,所以要為其擴展原型成員,就必須使用constructor屬性來指向他的構造器,
-
然后,先新建一個空的建構式,并為其呼叫extend()方法把傳遞進來的F類的實體物件完全復制為原型物件成員,
-
extend()方法只能為構造函式結構復制物件,
2.1.3銷毀物件
Js提供了一套垃圾回識訓制,當物件沒有被任何變數參考時,Js會自動偵測,并運行垃圾回收程式把這些物件注銷,以釋放記憶體,
每當函式物件被執行完畢,垃圾回收程式就會自動被運行,
比如下面該用法:
var o = {
x: 1,
y: 24
}
o = null;//洗掉
document.write(o.x);
在前端職場設計中,對于不用的物件,應該把其所有參考變數都設定為null,將物件廢除,就好比如把手機里的不必要的垃圾和快取清除干凈,釋放記憶體空間,
這是一種好的習慣,既節省系統開支,又可以預防錯誤,
3.1操作屬性
屬性包括名和值,屬性名可以是包含空字串在內的任意字串,但物件中不能存在兩個同名的屬性,值可以是任意的Js值,每個屬性還
有一些相關的值,
名稱為屬性中的特性:
|
可寫(writable attribute) |
表明是否可以設定該屬性的值, |
|
可列舉(enumerable attribute) |
表明是否可以洗掉或修改該屬性, |
|
可配置(configurable attribute) |
表名是否可以洗掉或修改該屬性, |
3.1.1定義屬性
在ECMAScript5中則可以對這些特性加以配置,
使用冒號可以為物件定義屬性,冒號左側是屬性名,右側是屬性值,屬性和屬性之間通過逗號運算子進行分隔,
下列用法:
var o = function () {
this.x = 1;
this.y = {
x: 1,
y: true
}
}
在宣告變數時使用var陳述句,但是在宣告物件屬性時不能使用var陳述句,
Js5增加了靜態函式,用來為指定物件定義屬性,下面進行說明:
Object.defineProperty()
Object.defineProperty()方法可以將屬性添加到物件,或者修改現有屬性的特性,并回傳這個物件,
語法:
Object.defineProperty(obj, prop, descriptor)
引數:
|
obj |
要在其上定義屬性的物件 |
|
prop |
要定義或修改的屬性的名稱 |
|
descriptor |
將被定義或修改的屬性描述符 |
回傳值:
被傳遞給函式的物件,
該方法允許精確添加或修改物件的屬性,通過賦值操作添加的普通屬性是可列舉的,能夠在屬性列舉期間呈現出來(for...in 或 Object.keys 方法),這些屬性的值可以被改變,也可以被洗掉,這個方法允許修改默認的額外選項(或配置),默認情況下,使用 Object.defineProperty() 添加的屬性值是不可修改的,
創建屬性:
如果物件中不存在指定的屬性,Object.defineProperty()就創建這個屬性,當描述符中省略某些欄位時,這些欄位將使用它們的
默認值,擁有布林值的欄位的默認值都是false,value,get和set欄位的默認值為undefined,
下面用法:
var obj = {};
Object.defineProperty(obj, 'newDataProperty', {
value: 101,
writable: true,
enumerable: true,
configurable: true
});
obj.newDataProperty = 102;
document.write(obj.newDataProperty);
3.1.2訪問屬性
通過點運算子可以訪問物件屬性,點運算子左側是物件參考的變數,右側是屬性名,屬性名必須是一個識別符號,而不是一個字串,
用法1:
alert(o['y']['y']['y'])
以陣列形式讀取物件屬性值時,應以字串形式指定屬性名,而不能使用識別符號,
用法2:可以使用for/in陳述句來遍歷物件屬性
o = {
x: 2,
y: 3,
z: 4
}
for (var i in o) {
document.write(o[i]);
}
使用for/in陳述句遍歷物件屬性時,也只能列舉自定義屬性,
3.1.3洗掉屬性
使用delete運算子可以洗掉物件屬性,這與變數操作相同,
用法:
var o = { x: 1 }
delete o.x;
document.write(o.x);
3.1.4使用方法
在Js中,方法就是物件屬性的一種特殊形式,即值為函式的屬性,從功能角度分析,方法是物件執行特定行為的邏輯塊,是與外界現行為互動的
動作,
用法1:
var o = {};
o.x = function () {
document.write('method');
}
o.x()
3.2使用方法
在Js中,Object物件默認定義了多個原型方法,由于繼承關系,所有物件都將擁有這些方法,
3.2.1使用toString()
toString()方法能夠回傳一個物件的字串表示,它回傳的字串比較靈活,可能是一個具體的值,也可能是一個物件的型別標識,
用法1:
function F(x, y) {
this.x = x;
this.y = y;
}
var f = new F(1, 2);
document.write(f.toString());
當把資料轉換為字串時,Js一般都會呼叫toString()方法來實作,由于不同的型別的物件在呼叫該方法時,所以開發人員常用它來判斷物件的型別,
彌補typeof運算子和constructor屬性在檢測物件資料型別的不足,
用法2:
function Me() { }
Me.prototype.toString = function () {
return '[Object//大類 Me//小類]';
}
var me = new Me();
document.write(me.toString());
document.write(Object.prototype.toString.apply(me));
Js在部分子型別中重寫了toString()和toLocaleString()方法,
比如:在Array中重寫toString(),讓其回傳陣列元素值的字串組合;在Data中重寫了toString(),讓其回傳當前日期字串表示,
3.2.2使用valueOf()
valueOf()方法能回傳物件的值,Object物件默認valueOf方法回傳值與toString()方法回傳值相同,但是部分型別物件重寫了valueOf()方法,
下面用法:Date物件的valueOf()方法回傳值是當前日期物件的毫秒數,
var o = new Date(); document.write(o.toString() + '<br>'); document.write(o.valueOf() + '<br>'); document.write(Object.prototype.valueOf.apply(o));
3.2.3檢測私有屬性
物件屬性可以分為兩類:
|
私 有 屬 性 |
|
繼 承 屬 性 |
用法1:
function F() {
this.name = '私有屬性';
}
F.prototype.name = '繼承屬性';
凡是建構式的原型屬性(原型物件包含的屬性),都是繼承屬性,
3.2.4檢測列舉屬性
在大多數情況下,in運算子是探測物件中屬性是否存在的最好途徑,
用法1:for/in陳述句可用來遍歷一個物件中的所有屬性名,
for (var name in person) {
if (typeof person[name] != 'function') {
document.write(name + ':' + person[name] + '<br>')
}
}
該列舉程序將會列出所有的屬性,
3.3使用原型
在Js中,建構式擁有原型,實體物件通過prototype關鍵字可以訪問原型,實作Js原型繼承機制,
3.3.1定義原型
原型事件上就是一個資料集合,即普通物件,繼承Object類,由Js自動創建并依附于每個建構式,
使用點語法,用戶可以通過function.prototype方式定義原型,所有實體物件可以共享屬性和原型方法(所有物件共享),
下面用法:
function p(x) {
this.x = x;
}
p.prototype.x = 1
var p1 = new p(10);
p.prototype.x = p1.x
document.write(p.prototype.x);
3.3.2比較原型屬性和本地屬性
建構式定義了與原型屬性同名的本地屬性,則本地屬性會覆寫原型屬性值,如果使用delete運算子洗掉本地屬性,則原型屬性會被訪問,
用法1:本地屬性可以在實體物件中被修改,但是不同實體物件之間不會相互干擾,
function f() {
this.a = 1;
}
var e = new f();
var g = new f();
document.write(e.a);
document.write(g.a);
e.a = 2;
document.write(e.a);
document.write(g.a);
如果希望統一修改實體物件中包含的本地屬性值,就需要一個個修改了,作業量會很大,
用法2:原型屬性將會影響所有實體物件,修改任何原型屬性值,則該建構式的所有實體都會看到這種變化,這樣就避免了本地屬性修改的麻煩,
function f() {
f.prototype.a = 1;
}
var e = new f();
var g = new f();
document.write(e.a);
document.write(g.a);
f.prototype.a= 2;
document.write(e.a);
document.write(g.a);
prototype屬性屬于建構式,所以必須使用建構式通過點語法來呼叫prototype屬性,再通過prototype屬性來訪問原型物件,
用法3:
function p(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
p.prototype.del = function () {
for (const i in this) {
delete this[i];
}
}
p.prototype//原型物件 = new p(1, 2, 3);
var p1 = new p(10, 20, 30);
document.write(p1.x);
document.write(p1.y);
document.write(p1.z);
p1.del();
document.write(p1.x);
document.write(p1.y);
document.write(p1.z);
3.3.3應用原型
下面通過幾個實體介紹原型在代碼中的應用技巧,
用法1:利用原型間接實作本地資料備份,
function p(x) {
this.x = x;
}
p.prototype.backup = function () {
for (const i in this) {
p.prototype[i] = this[i]
}
}
var p1 = new p(1);
p1.backup();
p1.x = 10;
document.write(p1.x);
p1 = p.prototype;
document.write(p1.x);
用法2:利用院校還可以為物件屬性設定‘只讀’特性,
function p(x, y) {
if (x) this.x = x;
if (y) this.y = y;
p.prototype.x = 0;
p.prototype.y = 0;
}
function l(a, b) {
var a = a;
var b = b;
var w = function () {
return Math.abs(a.x - b.x);
}
var h = function () {
return Math.abs(a.y - b.y);
}
this.length = function () {
return Math.sqrt(w() * w() + h() * h());
}
this.b = function () {
return a;
}
this.e = function () {
return b;
}
}
var p1 = new p(1, 2);
var p2 = new p(10, 20);
var l1 = new l(p1, p2);
document.write(l1.length() + '<br>');
l1.b().x = 50;
document.write(l1.length());
3.3.4原型繼承
原型繼承是一種簡化的繼承機制,原型繼承不再需要使用類來定義物件的結構,其中參考物件被稱為原型物件,
下面用法:
function A(x) {
this.x1 = x;
this.get1 = function () {
return this.x1;
}
}
function B(x) {
this.x2 = x;
this.get2 = function () {
return this.x2 + this.x2;
};
}
B.prototype = new A(1);
function C(x) {
this.x3 = x;
this.get3 = function () {
return this.x2 * this.x2;
}
}
C.prototype = new B(2);
var b = new B(2);
var c = new C(3);
document.write(b.x1);
document.write(c.x1);
document.write(c.get3());
document.write(c.get2());
prototype的最大特點就是能允許物件實體共享原型物件的成員,不需要宣告靜態類,而是通過復制已經存在的原型物件來實作繼承關系的,
原型繼承顯得非常簡單,其優點也是結構簡練,不需要每次構造都呼叫父類的建構式,且不需要通過復制屬性的方式就能快速實作繼承,
但是也存在一下幾個缺點:
-
每個型別只有一個原型,所以它不直接支持多重繼承,
-
它不能很好地支持多引數或者動態引數的父類,也許在原型繼承階段,用戶還不能決定以什么引數來實體化建構式,
-
使用不夠靈活,用戶需要在原型宣告階段實體化父類物件,并把它作為當前型別的原型,
-
這限制了父類實體化的靈活性,很多時候無法確定父類物件實體化的時機和場所,
-
prototype屬性固有的副作用,
3.3.4擴展原型方法
Js允許為基本資料型別定義方法,通過為Object.prototype添加原型方法,可以使得該方法對所有的物件可用,
用法1:通過給Function.prototype增加方法,是該方法對所有函式可以,
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
為Function.protype增加一個method方法后,不必在使用prototype這個屬性了,然后呼叫method方法就可以直接為各種基本型別添加方法,
用法2:Js并沒有單獨的整數型別,下面通過為Number.prototype添加一個integer方法來改善它,
Number.method('integer', function () {
return Math[this < 0 ? 'ceil' : 'floor'](this);
});
document.write((-10 / 3).integer());
3.4實戰案例
Js是基于(不是面向)物件的語言,它是以物件為基礎,以函式為模型,以原型為繼承機制的開發模式,通過多個示例介紹js物件的靈活運用,
3.4.1設計工廠模式
工廠模式是一種創建型別的模式,目的是為了簡化創建物件的流程,它把物件實體化簡單封裝在一個函式中,然后通過函式呼叫,實作快速、批量生產物件,
下面用法:
function createBook(title, price) {
var oTempBook = new Object;
oTempBook.title = title;
oTempBook.price = price;
oTempBook.showTitle = function () {
document.write(this.title);
};
oTempBook.showPrice = function () {
document.write(this.price);
};
return oTempBook;
}
var oBook1 = createBook('JavaScript從入門到精通(標準版)', ' ' + 89.80 + '元');
var oBook2 = createBook('<br>' + ' ' + '人人學音標', ' ' + 29.80 + '元');
oBook1.showTitle() + oBook1.showPrice() + oBook2.showTitle() + oBook2.showPrice();
3.4.2設計類繼承
JS中其實是沒有類的概念的,所謂的類也是模擬出來的,特別是當我們是用new關鍵字的時候,在Js中實作類的繼承,而類式繼承是在函式物件內呼叫父類的
建構式,
下面用法:
function extend(Sub, Sup) {
var F = function () { };
F.prototype = Sup.prototype;
Sup.prototype = new F();
Sup.prototype.constructor = Sub;
Sub.sup = Sup.prototype;
if (Sup.prototype.constructor == Object.prototype.constructor) {
Sup.prototype.constructor = Sup;
}
}
function A(x) {
this.x = x;
this.get = function () {
return this.x;
}
}
A.prototype.add = function () {
return this.x + this.x;
}
A.prototype.mins = function () {
return Math.sqrt(this.x - this.x);
}
A.prototype.mul = function () {
returnthis.x * this.x;
}
A.prototype.division = function () {
return Math.floor(this.x / this.x);
}
A.prototype.delivery = function () {
return Math.floor(this.x % this.x);
}
function B(x) {
A.call(this, x);
}
extend(B, A);
var f = new B(20);
document.write(f.get())
document.write(f.add())
document.write(f.mins()) + document.write(f.mul()) + document.write(f.division()) + document.write(f.delivery());
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/259665.html
標籤:其他
上一篇:JavaScript函式
下一篇:JavaScript事件處理
