此文是《Javascript Elightment》的讀書筆記,希望和有意向從jS庫的使用者轉變成js的開發人員的童鞋們一起分享。
第一篇
javascript 對象建立對象
Js中,所有事物都是對象或者可以表現得像對象。
記住:對象事實上就是一個屬性(名字和對應的值)的容器。
方法其實也是對象的一個屬性,它包含了用來操作對象的function()對象。如果沒有方法,對象除了儲存靜態屬性外什麼也做不了。
建立一個對象:var myObject = new Object();
上面代碼解析: 我們用一個指向Object() 建構函式的Null 物件去建立新對象。
可以把建構函式看成生產預定義好的對象的模板。
我們也可以自己建立一個物件建構函數,用來大量“生產”我們需要的對象。
如:
var Person = function(living, age, gender) {
this.living = living;
this.age = age;
this.gender = gender;
this.getGender = function() {return this.gender;};
};
var cody = new Person(true, 33, 'male');
js 建構函式構建和返回對象執行個體
建構函式的作用是建立一批共用特定屬性和方法的對象。
建構函式在正常時候不外乎是一個函數,但是當被new調用後,這個函數就被特殊對待,因為它要設定正準備建立的對象的屬性值,然後返回一個建好的對象,這個對象就被認作這個建構函式構造出來的執行個體。
Js 原生/內建對象(Native/Built-In Object)的建構函式
Js的9個原生對象:
• Number()
• String()
• Boolean()
• Object()
• Array()
• Function()
• Date()
• RegExp()
• Error()
自訂建構函式
自訂的建構函式名字的首字母最好大寫。
在建立對象的時候可以省去new關鍵字,但是在定義建構函式的時候必須明確地返回一個對象。
如:
var myFunction = function(){return {prop: val}};
上面的做法避免了prototype的繼承。
用new執行個體化建構函式
new操作就是告訴js解譯器——我們要建一個相應的建構函式的執行個體。
Math()
Math與其它內建建構函式不一樣,它是一個靜態對象,並不是建構函式,所以不能用new來構建一個執行個體,但是你可以用它已經建好的執行個體(如 Math.PI)。事實上Math只是js用來儲存math方法的一個對象。
注意: Math 是一個靜態對象(一個包含其它方法的容器),不可以用new操作。
用建構函式建立速記/字面值(Shorthand/Literal Values)
Js提供了“字面值”的捷徑去製造大多數的內建對象值,所以我們不需要每次都用new操作。
大多數情況字面值方式和new操作做的事是一樣的,除了Number(),String()和Boolean().
如:
var myObject = new Object();
var myObjectLiteral = {};
var myNumber = new Number(23);
var myNumberLiteral = 23;
注意: 用字面值建立string, number, boolean對象,剛開始並不是建立一個真正的複雜的對象,而是單純的一個未經處理資料類型,只有當這個對象被當做對象用(調用建構函式內的方法,擷取屬性)時,js才會為這個字面值建立一個封裝對象,允許這個字面值像對象一樣操作,當建構函式內的方法調用完後,js就會拋棄這個對象,字面值又恢複成單純的資料類型。(這裡解釋了為什麼“js裡所有的事物都是對象或可以像對象一樣操作”)。
原始值(Primitive Values) null,undefined,“string”,10,true,false都不是對象
原始值不是對象,它們只是用來表示簡單的值。
原始值如何在js中儲存和複製
原始值的儲存和操作僅限於數值表面的,不可還原的。
var myString = 'foo' // create a primitive string object
var myStringCopy = myString; // copy its value into a new variable
var myString = null; // manipulate the value stored in the myString variable
/* The original value from myString was copied to myStringCopy. This is confirmed
by updating the value of myString then checking the value of myStringCopy */
console.log(myString, myStringCopy); // logs 'null foo'
原始值的對比
如果不是通過new建立的對象,那麼原始值的類型還是原始類型。如果用new建立對象,即使數值相同,但是類型已經不再是原始類型了,而變成了對象。
var price1 = 10;
var price2 = 10;
var price3 = new Number('10'); // a complex numeric object because new was used
var price4 = price3;
console.log(price1 === price2); // logs true
/* logs false because price3 contains a complex number object and price 1 is
a primitive value */
console.log(price1 === price3);
// logs true because complex values are equal by reference, not value
console.log(price4 === price3);
// what if we update the price4 variable to contain a primitive value?
price4 = 10;
console.log(price4 === price3); /* logs false: price4 is now primitive
rather than complex */
複合值(Complex Values)
內建對象 Object(),Array(),Function(),Date(),Error(),RegExp()都是複合值,因為它們包含一個或多個原始值和複合值。
複合值在js中如何儲存和複製
新建立一個對象後,這個對象會被儲存在記憶體的某個地址裡;當你調用這個對象時,你用對象的名字去獲得記憶體位址裡的值。
對象的複製並不是像原始值一樣單純在數值表面的複製,複製的是對象的引用值/地址值,並不是真的數值,這意味著對象並不是完全被複製。所以,複製的對象和來源物件其實指向同一個地址值,即它們操作的是同一個對象。
var myObject = {};
var copyOfMyObject = myObject; /* not copied by value,
just the reference is copied */
myObject.foo = 'bar'; // manipulate the value stored in myObject
/* Now if we log myObject and copyOfMyObject, they will have a foo property
because they reference the same object. */
console.log(myObject, copyOfMyObject); /* logs 'Object { foo="bar"}Object { foo="bar"}' */
注意: String(),Number(),Boolean()被new建立或偷偷被臨時轉成對象,這些值任然是以單純的數值表面儲存和複製。所以即使原始值可以做類似對象一樣的操作,它們的儲存複製方式也不會和對象一樣。
如果想完全複製一個對象,那就必須把來源物件裡的值擷取出來並注入新的對象中。
複合值的對比
只有當兩個對象指向的是同一個對象,即有相同的儲存地址時,兩個對象才是相等的。否則,即使兩個對象看上去完全一樣,它們也是不等的。
var objectFoo = {same: 'same'};
var objectBar = {same: 'same'};
/* logs false, JS does not care that they are identical
and of the same object type */
console.log(objectFoo === objectBar);
// how complex objects are measured for equality
var objectA = {foo: 'bar'};
var objectB = objectA;
console.log(objectA === objectB); /* logs true because they reference
the same object */
綜合物件的動態屬性
已經知道,一個變數指向一個現有的對象時並不是複製這個對象,僅僅是複製了對象的地址。所以一個對象可以擁有很多個引用對象,它們都指向同一個地址的來源物件。
所以,只要這些對象中任意一個的屬性改動,則其它的對象都會一起改動。
原始值和複合值的typeof 操作
值的類型要根據環境來確定。如下面,除了用new操作建立的對象外,其它快捷建立出來的值都是原始類型。
var myNull = null;
var myUndefined = undefined;
var primitiveString1 = "string";
var primitiveString2 = String('string');
console.log(typeof myNull); // logs object? WHAT? Be aware...
console.log(typeof myUndefined); // logs undefined
console.log(typeof primitiveString1, typeof primitiveString2);// logs string string
// Complex Values
var myNumber = new Number(23);
var myString = new String('male');
var myBoolean = new Boolean(false);
console.log(typeof myNumber); // logs object
console.log(typeof myString); // logs object
console.log(typeof myBoolean); // logs object
對象的可變性
因為對象擁有動態屬性的特點,導致了它是可變的,即使是js的內建對象。這意味著你可以隨時隨地改變js中的大多數對象,改變它原配置的屬性,添加屬性方法等(實際上這種做法是不推薦的)。
所有的建構函式執行個體都有指向它們的建構函式的建構函式屬性
每個執行個體都有一個建構函式屬性,這個屬性指向了構造這個執行個體的建構函式。
即使是原始值,也同樣擁有建構函式屬性,但是構造出來的並不是對象,仍是一個原始值。
var myNumber = new Number('23');
var myNumberL = 23; // literal shorthand
var myString = new String('male');
var myStringL = 'male'; // literal shorthand
console.log( // all of these return true
myNumber.constructor === Number,
myNumberL.constructor === Number,
myString.constructor === String,
myStringL.constructor === String);
如果希望自訂的對象的建構函式有確切的名字,則在定義的時候要先給它命名。如
var Person = function Person(){};
每個對象都是特定的建構函式的執行個體
instranceof() 函數可以用來判斷一個對象是否是某個建構函式的執行個體。
註:1. 每個對象都是Object()建構函式的執行個體。
2. 如果原始值不是new出來的,則在判斷建構函式執行個體時一定會返回false. (e.g., 'foo' instanceof
String // returns false).
建構函式構造的執行個體可以擁有它們獨立的屬性
Js中,對象隨時可以被擴充。但是原始值不可以進行擴充。
var myString = new String();
var myNumber = new Number();
myString.prop = 'test';
myNumber.prop = 'test';
console.log(myString.prop,myNumber.prop); // logs 'test', 'test'
// be aware: instance properties do not work with primitive/literal values
var myString = 'string';
var myNumber = 1;
myString.prop = true;
myNumber.prop = true;
// logs undefined, undefined
console.log(myString.prop, myNumber.prop);
註: 除了建構函式的屬性外,執行個體還會從prototype 鏈繼承屬性。如上所述,執行個體也可擁有自己擴充的屬性。
“Javascript Objects” 和 “Object() Objects” 語義上的區別
Javascript Objects 泛指js中的所有對象,Object() Objects特指由Object建構函式構造出來的名字為Objects的對象。
後面會繼續更新”第二篇 使用對象和屬性“。
此文為原創,轉載請附連結,謝謝。