js高级程序设计第3版(6章:面向对象的程序设计)
1.理解对象
2.属性类型
- 数据属性:[Configurable]是否删除,编辑的特性。[Enumerable]表示能否通过for-in循环返回该属性。[Wirtable]表示能否修改属性的值 [value]包含这个属性的数据值
修改这些属性的值时,Object.defineProperty() 不传参时,默认三个属性是false
- 访问器属性:[Configurable]是否删除,编辑的特性。[Enumerable]表示能否通过for-in循环返回该属性。[Get]在读取属性时调用的函数,默认undefined 。[Set]在写入属性调用的函数,默认为undfined
- 读取属性的特性 Object.getOwnPropertyDescriptor()
3.创建对象
- 工厂模式:优点:解决创建多个相似对象的问题, 缺点:没有解决对象识别的问题
function person(){ var o=new Object(); o.name=name; o.job=job; return o; } var person1=person("122"); var person2=person("232")
- 构造函数模式: 优点:创造的自定义的构造函数可以作为实例标识 instanceof 缺点:每次创建一个实例,则重新定义方法,容易造成乱用。放在全局也容易混淆。
function Createperson(name,age){ this.name=name; this.age=age; this.sayName=function(){ alert(this.name) } } var person1=new Createperson('12',1); var person2=new Createperson('1222',33);
- 原型模式:优点:所有的属性和函数都可以共享 缺点: 引用类型共享,造成所有的实例的对象属性都一样,没有差异性
Object.getPrototypeOf()获取原型对象
Object.hasOwnProperty()可以检测一个属性是存在于实例中,还是原型中 来自实例则返回true。实例和原型 中同时存在相同的变量,则优先使用实例中,delete 实例中则会访问到原型中的
in操作符:无论在实例和原型中都会返回true。
- 组合构造函数和原型模式:共享的属性采用构造函数,共同的方法采用原型方法(默认方式)
- 动态原型模式:
function Person (name,age,job){ this.name=name; this.age=age; this.job=job; if(typeof this.sayName!='function'){ Person.prototype.sayName=function(){ alert(this.name) } }
- 寄生构造函数模式:在构造函数中,创建对象,封装对象的属性,方法等,然后返回对象
缺点:返回的对象与构造函数和构造函数的原型都没有关系,采用instanceof确定类型。
- 稳妥构造函数模式:在一些安全环境中,禁止使用this和new使用。访问函数中的变量,只能使用函数中的方法。
4.继承:实现继承(依靠原型链实现)接口继承(因没有函数签名,没有此种方法)
- 原型链继承:注意:通过此方法继承时,不能使用对象字面量创建原型方法,因为会重写原型链。
缺点:1.引用类型的原型共用,会影响所有的实例。2.构建实例时,不能向里边传入参数。不能与构造函数一样。
- 借用构造函数继承:
function Person(name){ this.name=name; } function Second(){ //即传入参数,又定义自己的属性 Person.call(this,'qwqw') this.age=12; } let s=new Second(); console.log('s.name',s.name); console.log('s.age',s.age);
缺点:方法都在构造函数中定义,函数不能复用。
- 组合继承:原型链实现对原型属性和方法的继承,构造函数实现对实例属性的继承。(组合)
function Person(name) { this.name = name; this.colors = ['red', 'green'] } Person.prototype.sayName = function () { alert(this.name); } function Second(name, age) { Person.call(this, name) this.age = age; } Second.prototype = new Person(); Second.prototype.sayAge = function () { alert(this.age); } let s = new Second(); let create1 = new Second('111', 1); create1.colors.push('black'); console.log('1,colors', create1.colors); create1.sayName() create1.sayAge() let create2 = new Second('211', 2); console.log('2,colors', create2.colors); create2.sayName() create2.sayAge()
- 原型式继承
// 传入的参数作为构造函数的原型,本质是浅复制 function object(o){ function F(){}; F.prototype=o; return new F(); } var person={ name:'ssss', friends:['k','l','o'] } var another=object(person); another.name="another"; console.log('anotjer',another.name); // 'another' another.friends.push('sss'); // another和person 同指一个地方 console.log('as',another.friends); //["k", "l", "o", "sss"] console.log('anotjeranotjer',person.friends);//["k", "l", "o", "sss"]
Object.create()接收两个参数:第一个参数:用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。
function object(o){ function F(){}; F.prototype=o; return new F(); } var person={ name:'ssss', friends:['k','l','o'] } var another=Object.create(person,{ name:{ value:"SSS" } }); alert(another.name) //SSS
- 寄生式继承
// 传入的参数作为构造函数的原型,本质是浅复制 function object(o){ function F(){}; F.prototype=o; return new F(); } // 类似寄生构造函数和工厂模式类似 function Another(per){ var clone=object(per); //通过调用函数创建一个新对象 clone.sayhi=function(){//为新对象添加函数 alert('hi') } return clone; }
- 寄生组合式继承
组合式继承有个缺点:原型上的属性和实例上的属性会被分别创建一次,实例上的属性如果和原型上的属性同名,则会屏蔽原型中的属性名。
其继承的特点:借用构造函数实现属性的继承,通过原型链继承方法。
// 传入的参数作为构造函数的原型,本质是浅复制 function object(o){ function F(){}; F.prototype=o; return new F(); } function inherit(subType,superType){ // 第一个为子类型构造函数,第二个为超类型构造函数 var prototype=object(superType.prototype); //创建超文本构造函数的一个副本 prototype.constructor=subType; //增强对象 subType.prototype=prototype; //将对象赋值给子类型的构造函数 } function SuperType(name){ this.name=name; this.colors=['ee','e','eee'] } SuperType.prototype.sayName=function(){ alert(this.name) } function SubType(name,age){ SuperType.call(this,name); this.age=age; } inherit(SubType,SuperType); SubType.prototype.sayAge=function(){ alert(this.age); } let s=new SubType('ss',12); console.log('s',s); //包含name,age,colors console.log('super',new SuperType('super')); //包含colors,name