JavaScript高级程序设计(第三版) 6/25
第六章
面向对象的程序设计
1.定义只有在内部才用的特性(attribute)时,描述了属性(property)的各种特征。这些特性是为了实现JavaScript引擎用的,因此在JavaScript中不能直接访问它们。为了表示特性是内部值,该规范把它们放在了两对方括号中,例如[[Enumerable]]。
2.数据属性
[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,默认为true,一旦改为false不能再把它变回可配置了。
[[Enumerable]]:表示能否通过for-in循环返回属性,默认为true。
[[Writable]]:表示能否修改属性的值,默认为true。
[[Value]]:包含这个属性的数据值,默认为undefined,只可读。
3.要修改属性默认的特性,必须使用ES5的Object.definePropert()方法。这个方法接受三个参数:属性所在的对象,属性的名字和一个描述符对象。
4.访问器属性
[[Configurable]]
[[Enumerable]]
[[Get]]:在读取属性时调用的函数。默认undefined
[[Set]]:在写入属性时调用的函数。默认undefind
访问器属性不能直接调用,必须使用Object.defineProperty()
_year,起那么加下划线是一种常用的标记,用于表示只能通过对象方法访问的属性。
5.工厂模式
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 person = createPerson("Grey",27,"Doctor");
6.构造函数模式
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("Nicholas",29,"Software Engineer");
跟工厂模式的区别:1.没有显示地创建对象 2.直接将属性和方法赋给了this对象 3.没有return语句
7.创建一个实例经过的步骤
1.创建一个新对象
2.将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
3.执行构造函数中的代码(为这个新对象添加属性)
4.返回新对象
8.person1根person2保存着不同的实例,但是两个对象都有一个constructor(构造函数)属性,指向Person
person1 instanceof Person == true
创建自定义构造函数意味着将来可以将它的实例标识为一种特定的类型,而这正是构造函数模式胜于工厂模式的地方
9.创建的每一个函数都有一个prototype(原型)属性。
使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必再构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。
10.代码读取属性时候,如果在实例中找到了具有给定名字的属性,则返回该属性的值,如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。
11.
function Person(){ } var friend = new Person(); Person.prototype = { constructor:Person, name: "Nicholas", age : 29, job : "Student" sayName : function(){ alert(this.name); } }; friend.sayName();
重写原型对象切断了现有原型与任何之前已经存在的对象之间的联系;它们的引用任然是最初的原型。
搞错 不应该报这个错误,原因是我在上面的job的后面少了个,所以导致出现这个错误,是语法错误的意思
改完后
12.不建议修改原生对象的原型,因为不同分支如果都重写,可能造成命名冲突。
13.原型对象的最大问题是其共享的本性所导致。
14.组合使用构造函数模式和原型模式,每一个实例都会有自己的一份实例属性的副本,但同时又共享着对方的引用了,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数。
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("zs", 12, "student"); var person2 = new Person("ls", 11, "doc"); person1.friends.push("van"); alert(person1.friends);//shelby,count,van alert(person2.friends);//shelby,count alert(person1.friends === person2.friends);//false alert(person1.sayName === person2.sayName);//true
15.and 寄生构造函数模式,稳妥构造函数模式。instanceof操作符对这种对象都没意义。
16.javascript的继承主要依靠原型链来实现,
比如,1,先搜索实例 2,往上层原型搜索 3,往更上层原型搜索
17.原型链的问题也是原型属性实例共享。解决这个问题用借用构造函数。(这两种技术都很少单独使用)
18.组合继承
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.constructor = SubType; 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("Grey",27); alert(instance2.colors); // "red,blue,green,black" instance2.sayName(); // "Grey" instance2.sayAge(); // 27
组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为js中最常用的继承模式。而且instanceof 和isPrototypeof()也能够用于识别基于组合继承创建的对象。