[toc]javascript
內容概要java
用對象字面量建立自定義對象數組
Object.defineProperty()
方法修改默認屬性的特性var person = {}; Object.defineProperty(person, "name", { writable: false, value: "Nicholas" }); alert(person.name); person.name = "Michael"; alert(person.name);
Object.defineProperty()
方法來定義var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, "year", { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } }); book.year = 2005; alert(book.edition); //2
Object.defineProperties()
方法 經過描述符一次定義多個屬性 兩個對象參數:要添加和修改屬性的對象;對象屬性與要添加和修改的屬性app
var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); book.year = 2005; alert(book.edition); //2
Object.getOwnPropertyDescriptor()
方法:取得給定屬性的描述符 兩個參數:屬性所在對象和要讀取其描述符的屬性名稱函數
var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); var descriptor = Object.getOwnPropertyDescriptor(book, "_year"); alert(descriptor.value); //2004 alert(descriptor.configurable); //false alert(typeof descriptor.get); //"undefined" var descriptor = Object.getOwnPropertyDescriptor(book, "year"); alert(descriptor.value); //undefined alert(descriptor.enumerable); //false alert(typeof descriptor.get); //"function"
使用構造函數和對象字面量建立單個對象,有個缺點:使用同一個接口建立對象,產生大量代碼重複,使用工廠模式的變體解決這個問題this
抽象建立具體對象的過程,用函數來封裝以特定接口建立對象的細節prototype
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson("Nicholas", 29, "Software Engineer"); var person2 = createPerson("Greg", 27, "Doctor"); person1.sayName(); //"Nicholas" person2.sayName(); //"Greg"
沒有解決對象識別問題code
建立自定義的構造函數,從而定義自定義對象類型的屬性和方法對象
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
與工廠模式creatPerson()的不一樣之處繼承
var person = new Person("Nicholas", 29, "Software Engineer"); person.sayName(); //"Nicholas" Person("Greg", 27, "Doctor"); //adds to window window.sayName(); //"Greg" var o = new Object(); Person.call(o, "Kristen", 25, "Nurse"); o.sayName(); //"Kristen"
屬性和方法添加給window對象 2. 構造函數的問題 每一個方法都要在每一個實例上建立一遍 不一樣實例名是不相等的 咱們能夠把函數轉移到構造函數外部
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
在全局做用域中定義的函數實際上只能被某個對象調用,這讓全局做用域有點名存實亡。更難以接受的是:若是對象須要定義不少方法,那麼就定義多個全局函數。這個自定義的引用類型就無封裝性可言了。咱們能夠經過原型函數解決這個問題
prototype就是經過調用構造函數而建立的那個對象實例的原型對象 讓全部對象實例共享它包含的屬性和方法
function Person(){ } Person.prototype.name = "yohann"; Person.prototype.age = "22"; Person.prototype.job = "Software Engineer"; Person.sayname = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); alert(person1.sayName = person2.sayName); //true
1. 理解原型對象 Person構造函數、Person原型屬性和實例的關係 isPrototypeOf()方法:肯定對象是否具備原型屬性 Object.getPrototypeOf()方法:返回prototype的值 實例屬性屏蔽原型屬性
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //"Greg" – from instance alert(person2.name); //"Nicholas" – from prototype
delete操做符刪除實例屬性解除屏蔽 hasOwnProperty()
方法:檢測屬性是存在實例中仍是原型中,對象實例返回true 2. 原型與in操做符 in操做符會在經過對象能訪問給定屬性時返回true hasOwnProperty()
方法和in操做符組合使用:肯定該屬性是存在對象中仍是存在原型中
function hasPrototypeProperty(object, name){ return !object.hasOwnProperty() && (name in object); }
使用for-in循環時,返回的是可以經過對象訪問的、可枚舉的屬性,既包括實例中的屬性也包括原型中的屬性 Object.key()
方法:接收一個對象做爲參數,返回一個包含全部可枚舉屬性的字符串數組
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var keys = Object.keys(Person.prototype); alert(keys); //"name,age,job,sayName"
Object.getOwnPropertyNames()
方法:返回全部實例屬性,不管是否枚舉 3. 更簡單的原型語法 前面例子中每添加一個原型屬性就要敲一遍Person.protptype。更常見是用一個包含全部屬性和方法的對象字面量來重寫整個原型對象
function Person(){ } Person.prototype = { name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } }; var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //false alert(friend.constructor == Object); //true
可是constructor屬性值會改變,要設置其爲適當的值,會致使Enumerable特性被設置爲true 4. 原型的動態性 先建立實例,再修改原型。仍然能夠訪問該方法 重寫原型對象就不同了 下面例子是先建立一個對象實例,而後重寫原型對象
function Person(){ } var friend = new Person(); Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", sayName : function () { alert(this.name); } }; friend.sayName(); //error
重寫原型對象切斷了現有原型與任何以前已經存在的實例的聯繫 4. 原生對象的原型 修改原生對象的原型,隨時添加方法 例如:給基本包裝類String添加一個startWith()方法
String.prototype.startsWith = function (text) { return this.indexOf(text) == 0; }; var msg = "Hello world!"; alert(msg.startsWith("Hello")); //true
不建議在產品化的程序中修改原生對象的原型 5. 原型對象的問題 在原型中有一個數組,在實例中push,會改變原型中數組的值。另外一個實例訪問的是改變後的值
function Person(){ } Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", friends : ["Shelby", "Court"], sayName : function () { alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court,Van" alert(person1.friends === person2.friends); //true
構造模式:定義實例屬性 原型模式:定義方法和共享的屬性
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby", "Court"]; } Person.prototype = { constructor: Person, sayName : function () { alert(this.name); } }; var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court" alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName); //true
檢查某個應該存在的方法是否有效,來決定是否初始化原型
function Person(name, age, job){ //properties this.name = name; this.age = age; this.job = job; //methods if (typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); }; } } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName();
建立一個構造函數,做用僅僅是來封裝建立對象的代碼,而後返回新建立的對象
function SpecialArray(){ //create the array var values = new Array(); //add the values values.push.apply(values, arguments); //assign the method values.toPipedString = function(){ return this.join("|"); }; //return it return values; } var colors = new SpecialArray("red", "blue", "green"); alert(colors.toPipedString()); //"red|blue|green" alert(colors instanceof SpecialArray);
返回的對象與構造函數或者構造函數的原型屬性之間沒有關係。缺點:不能依賴instanceof操做符肯定對象類型
**穩妥對象:**沒有公共屬性,其餘方法也不引用this的對象 與寄生構造模式的不一樣:新建立對象的實例方法不引用this;不使用new操做符調用構造函數
function Person(name, age,job){ var o = new Object(); //能夠在這裏定義私有變量和函數 //添加方法 o.sayName = function(){ alert(name); }; return o; }
除本身添加方法,無其餘方式訪問內部數據
OO語言支持兩種繼承模式:接口繼承和實現繼承 ECMAScript值支持實現繼承
利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法 SubType繼承SuperType。繼承經過建立SuperType實例,並將該實例賦給SubType.prototype實現的
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //inherit from SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true alert(Object.prototype.isPrototypeOf(instance)); //true alert(SuperType.prototype.isPrototypeOf(instance)); //true alert(SubType.prototype.isPrototypeOf(instance)); //true
1. 別忘記默認的原型 SubType繼承了SuperType,調用instance.toSteing(),實際是調用保存在Object.prototype中的方法 2. 肯定原型與實例的關係 instance操做符和isPrototype()
方法 3. 謹慎地定義方法 給原型添加方法放在替換原型語句後 原型鏈繼承不能使用對象字面量建立原型方法 4. 原型鏈的問題 包含引用類型值的原型,修改原型中的數據 建立子類型實例時,不能向超類型的構造函數中傳遞參數
在子類型構造函數內部調用超類型構造函數 使用apply()和call()方法在新建立的對象上執行構造函數
function SubType(){ //inherit from SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green"
借用構造函數的問題 方法都是在構造函數中定義的,函數複用無從談起 超類型原型中定義的方法對子類型不可見
將原型鏈和借用構造函數技術組合一塊兒 使用原型鏈實現對原型屬性的方法的繼承,經過借用構造函數實現對實例屬性的繼承
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } SubType.prototype = new SuperType(); SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27
藉助原型能夠基於已有對象建立新對象,沒必要新詞建立自定義類型
function object (o){ functin F() {} F.prototype = o; return new F(); }
Object.creat()
方法
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = Object.create(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = Object.create(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
第二個參數
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = Object.create(person, { name: { value: "Greg" } }); alert(anotherPerson.name); //"Greg"
建立一個僅用於封裝繼承的函數,在函數在內部以某種方式加強對象
functin creatAnother(original){ var clone = object(original); clone.sayHi = function(){ alert("hi"); }; return clone; } var person = { name: "yohann"; friends: ["hehe", "haha", "heng"] }; var anotherPerson = creatAnother(person); anotherPerson.sayHi(); //hi
經過借用構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法
function object(o){ function F(){} F.prototype = o; return new F(); } function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); //create object prototype.constructor = subType; //augment object subType.prototype = prototype; //assign object } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27