[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