javascript的對象問題及總結
一 js中的對象是什麽?
-- js的對象是一種無序的數據集合,由若幹鍵值對組成(key-value)組成,裏面包含著數據(屬性)和方法(動作),它可以代表js中的所有事物。
- 例如將動物抽象成一類對象,此類對象有著動物中特有的屬性和動作,不同於植物,而動物中又分有豬,狗,雞不同類型的事物對象,這些類型事物對像既有著動物類型的屬性和動作,又有著自身獨特類型的屬性和動作,可以這樣一直細分下去,直到每一種動物的個例,也就是對象的實例了,它不僅具備上層事物共有的屬性和方法,也有著自己獨特個性,是一個獨特的個體。
1-1 js的對象如何創建?
-- 對象可通過對象字面量({}),構造函數(如new Object(),或自定義),Object.create等方式創建。
1-1-1 對象字面量,與new Object()創建對象方式的異同?
相同點:創建的對象在使用上是一致的,var a = {} // 是var a= new Object()的語法糖
不同點:初始化的過程有些區別,new Object()是通過構造函數實例化對象,{ }是直接創建JSON對象,且在初始化時可以直接賦值,相比{ }比較高效
1-1-2 訪問及修改對象的屬性
-- 對象是由鍵值對組成,對象的鍵名又稱屬性(property),都是字符串類型,鍵名符合標識名條件或是數字可省略" ",系統會默認自動轉為對應的字符串,鍵值可以是任意類型,若鍵值是函數,則該屬性又可被稱為方法,像函數般調用。
- 使用 . 或 [ ] 訪問或修改增添對象的屬性
- delete刪除屬性
- in檢查是否屬於自身的屬性
- Object.keys(obj)查看所有自身可枚舉屬性,Object.getOwnPropertyNames(obj)包括自身不可枚舉的屬性如數組中的"length",都返回屬性名數組
- for...in 循環遍歷對象本身屬性
- Object.observe(obj,function(changes))觀察對象屬性變化
1-1-2eg1:對象字面量式創建
<script> //對象字面量式創建 var obj = { name: ‘fermin‘, run:function () { alert(‘run‘); } }; obj.age = 18; //添加屬性 console.log(obj.age); //18 delete obj.age; //刪除屬性,註意:不能刪除繼承的屬性,會返回false,刪除不存在的屬性不會報錯,且返回true alert(obj.age); // undefined,訪問不存在的屬性返回undefined alert("age" in obj); //false, 註意:in對對象擁有的屬性都返回ture,無論是否是繼承的,無法識別繼承屬性 console.log(Object.keys(obj)); //["name","run"] //Object.keys()返回所有本身屬性名 for (let i in obj) { console.log(i); //name run //for..in 遍歷可enumerable的自身和繼承的屬性,可加obj.hasOwnProperty(i),過濾為自身屬性 } obj.run(); //run //用點號訪問屬性和方法 obj[‘run‘](); //run //用[]訪問屬性和方法 alert("toString" in obj); //true
</script>
構造函數:構造函數創建對象是借用Object.create(原型) 來實現。
1-1-2eg2:new Object() 創建 (訪問和修改對象屬性與上述相同)
<script> //new Object()創建 var obj = new Object(); //new可以省略 obj.name = ‘fermin‘; obj.age = 18; //添加屬性 obj.run = function () { alert(‘run‘); }; //添加屬性 delete obj.age; //刪除屬性 //delete只能刪除對象的屬性如:var a=1; delete a //false alert(obj.age); // undefined,訪問不存在的屬性返回undefined alert("age" in obj);//false console.log(Object.keys(obj)); //["name","run"] for (let i in obj) { console.log(i); //name run } obj.run(); //用點號訪問屬性和方法 obj[‘run‘](); //用[]訪問屬性和方法 alert("toString" in obj); //true
</script>
1-1-2eg3:自定義構造函數
<script> //自定義構造函數 function Person(name) { this.name = name; } var obj = new Person("fermin"); obj.age = 18; obj.run = function () { alert("run"); }; //添加屬性 alert(Object.keys(obj)); //name,age,run for (let i in obj) { console.log(i); //name age run } obj.run(); // run obj[‘run‘](); // run alert("toString" in obj); //true </script>
1-1-2eg4:Object.create(原型) // Object.create(Object.prototype) <==> new Object()
<script> //Object.create(原型); var obj = Object.create(null); //原型為null,不能繼承Object.prototype中的屬性 obj.name = ‘fermin‘; obj.age = 18; //添加屬性 obj.run = function () { alert(‘run‘); }; //添加屬性 delete obj.age; //刪除屬性 alert(obj.age); // undefined,訪問不存在的屬性返回undefined alert("age" in obj);//false console.log(Object.keys(obj)); //["name","run"] for (let i in obj) { console.log(i); //name run } obj.run(); //用點號訪問屬性和方法 obj[‘run‘](); //用[]訪問屬性和方法 alert("toString" in obj); //false //沒有繼承Object.prototype中的屬性 </script>
1-1-3 new一個對象的過程
var obj = new Function();
- 創建一個空對象 // var obj = {};
- 將實例的__proto__屬性指向構造函數的prototype原型 // obj__proto__ = Function.prototype
- 將構造函數的指針指向實例 // Function.call(obj)
1-1-3eg1:模擬new過程
<script>
function Person(name) { this.name = name; } var obj = Person("fermin"); //不用new obj = {}; obj.__proto__ = Person.prototype; Person.call(obj); obj.age = 18; obj.run = function () { alert("run"); }; //添加屬性 alert(Object.keys(obj)); //name,age,run for (let i in obj) { console.log(i); //name age run } obj.run(); // run obj[‘run‘](); // run alert("toString" in obj); //true </script>
1-1-4 函數中this的指向問題
-- this的指向在函數執行時才能確定,總是指向調用該函數的對象
- 由new調用,指向新建的對象 //在構造函數執行
- 由call,apply,bind調用,指向綁定的對象 //在強制綁定對象執行
- 由上下文調用,指向所屬的上下文對象 //在對象屬性執行
- 沒有所屬對象時,嚴格模式指向undefined或指向全局對象(window或global) //在普通函數執行
1-1-4-eg1:
<script> var obj1= { a:3, b:{ a:10, fn:function(){ console.log(this.a); //undefined console.log(this); //window } } }; var j = obj1.b.fn; j(); //將fn賦值給變量j時,obj調用fn沒有執行,所以它最終指向的是window,而不是obj var obj2 = { a : ‘A‘, fn: function () { console.log(this.a); } }; obj2.fn(); //"A" // this ===obj2 obj2.fn.call({a: ‘AA‘}); //"AA" // this === {name: ‘AA‘} var fn1 = obj2.fn; fn1(); //undefined //this === window </script>
二 object對象的方法
2-1 六個實例對象方法,繼承Object.prototype
- valueOf():返回當前對象對應的值,默認返回對象本身 // var o1 = new Object (); o1.valueOf === o1 //true
- toString():將對象轉換為字符串形式並返回 // var o2 = {a : 1}; o2.toString() // [object Object] //用Object.prototype.toString.call() 更準確的判斷類型[object,對象類型11種/ Number/ String/ Boolean/ Object/ Array/ Function/ Null/ Undefined/ RegExp/ NaN/ Infinite]
- toLocalString():將對像轉換為本地對應的字符串並返回
- hasOwnPropoty():判斷某個屬性是否是自身的非繼承屬性,是的返回true
- isPrototypeOf(): 判斷當前對象是為另一對象原型,是返回true
- propertylsEnumerable():判斷某個屬性是否可枚舉
2-2 對象屬性的特征 attributes 對象用Object.getOwnPropertyDescriptor(obj,字符串屬性名)讀取。
- value:表示該屬性的值,默認undefined
- writable:表示該屬性的值是否可改,默認true
- enumerable:表示該屬性名是否可枚舉,默認true //改為false時,for..in 及Object.keys(),JSON.stringify()不遍歷該屬性,可成私密屬性
- configurable:表述該對像是否可配置,默認true //var 聲明的變量會為false,沒聲明為false,如a=1或this.a=1 //改為false時,writable可從true改為false,當writable為true可改value值,其他值不可修改,不能再用delete刪除該屬性
- get:表屬性取值函數(getter)默認undefined //定義後,writable不能為true且定義value的值 // get,set為存取器的命令,常使用於某屬性值需依賴對象內部數據場合。 // 利用存取器可以實現數據對象與DOM對象的雙向綁定
- set:表屬性存值函數(setter)默認underfined //定義後,writable不能為true且定義value的值
2-3 定義對象屬性的attributes對象,下面兩種方法定義後,屬性中的writable,enumerable,configurable的值默認值又都會變為false
- Object.defineProperty(obj,字符串屬性名,attributesObj)
- Object.defineProperties(obj,{字符串屬性名: attributesObj,字符串屬性名: attributesObj,...})
2-3-eg1:定義單一attribules屬性
<script> var o = Object.defineProperty({}, "p", { value: 3, writable: false, enumerable: true, configurable: false }); alert(o.p); //3 o.p = 33; alert(o.p); //3 //writable為false,修改不了該屬性的值 </script>
2-3-eg2:定義多個attributes屬性
<script> var o = Object.defineProperties({}, { p1: { value: 3, enumerable: true, writable: true, //configurable值沒設定,默認為false }, p2: { get: function () { return this.p1 + 6; }, //有get,就不能直接定義其value值 enumerable: true, configurable: true } }); alert(o.p1); //3 o.p1 = 4; //writable,值為true後,可直接用.或[]修改該屬性值, alert(o.p1); //4 alert(o.p2); //10 Object.defineProperty(o, "p1",{value:33}); //若再修改p1其它屬性值會報錯,因為一開始configurable為false alert(o.p1); //33 //PS:當writable值為false,configurable值為true,只能在defineProperty()中修改 </script>
2-4 對象的拷貝
--將一對象所有屬性拷貝到另一個對象上,有重復的屬性,將被覆蓋
<script> var extend = function (to, from) { for (var property in from) { var descriptor = Object.getOwnPropertyDescriptor(from, property); if (descriptor && (!descriptor.writable || !descriptor.enumerable || !descriptor.configurable || !descriptor.get || !desciptor.set)) { Object.defineProperty(to, property, descriptor); //都拷貝 } else { to[property] = from[property]; //這個else遇存取器定義屬性只拷貝值,適用於descriptor的5個特征都具備 } } return to; }; var aa = extend({a:1, b:2}, {a:11, bb:22}); console.log(aa); //{a:11, b:2, bb:22} </script>
2-5 控制對象的狀態
- Object.preventExtensions(obj) //無法再添加新屬性,嚴格模式下添加會拋錯,可用delete刪除現有屬性
- Object.isExtensible(obj) //沒使用Object.preventExtensions(obj)返回false,使用了返回true
- Object.seal(obj) //無法添加新屬性,也無法刪除舊屬性,現有屬性的configurable會變為false
- Object.isSeal(obj) //沒使用Object.seal(obj)返回false,使用了返回true,且isExtensible返回false
- Object.isFrozen(obj) //是否被凍結,指不可擴展,所有屬性不可配置,所有數據屬性(即沒有getter或setter組件的訪問器的屬性)都是不可寫的。
2-5-eg:
<script> var o = new Object(); Object.preventExtensions(o); o.p = 1; console.log(o.p); // undefined console.log(Object.isExtensible(o)); //false </script>
javascript的對象問題及總結