JavaScript第六章学习

JavaScript第六章——面向对象

一、理解对象

1.创建对象

使用new操作符和使用对象字面量两种方法

2.属性类型

特性是内部值,把它放在两对方括号“[[Enumerable]]”

数据属性

数据属性包含一个数据值的位置。在这个位置可以读取和写入值。

JavaScript第六章学习_第1张图片

定义了属性(赋值后确定属性)之后只能通过Object.defineProperty()方法修改属性默认得特性

该方法接受三个参数:属性所在的对象、属性的名字和一个描述符对象

描述符(descriptor)对象的属性一定是configurable、enumerable、writable 和 value(可修改多个特性值)

JavaScript第六章学习_第2张图片

特性值如图进行设定

该特性在严格模式下进行修改属性的值会抛出错误

IE8是第一个实现 Object.defineProperty()方法的浏览器版本。然而,这个版本的实现存在诸多限制:只能在 DOM对象上使用这个方法,而且只能创建访问器 属性。由于实现不彻底,建议读者不要在 IE8 中使用 Object.defineProperty() 方法。

访问器属性

访问器不含数据值,包含一堆getter和setter函数

getter返回有效值,setter传入新值

JavaScript第六章学习_第3张图片

不能直接定义,必须使用Object.defineProperty来定义

严格模式下只指定setter函数或getter函数会抛出错误

在之前创建访问器属性的方法:用两个非标准的方法: *defineGetter()和*defineSetter__()

3.定义多个属性

Object.definePro- perties()方法

通过描述符可一次性定义多个属性

4.读取属性的特性

Object.getOwnPropertyDescriptor()方法

可以取得给定属性的描述符

接收参数::属性所在的对象和要读取其描述符的属性名称

返回值:对象

可读取(对象的类型)

访问器属性: 对象的属性有 configurable、enumerable、get 和 set

数值:对象的属性有 configurable、enumerable、writable 和 value

在JavaScript中,可以针对任何对象——包括 DOM和BOM对象,使用 Object.getOwnProperty- Descriptor()方法

二、创建对象

1.工厂模式

ECMAScript无法创建类

createPerson()函数能够替代类用函数封装以特性接口创建对象的细节

可无数次调用该函数

返回值:包含三个属性一个方法的对象

缺点:没有解决对象识别的问题(即怎样知道一个对象的类型)

2.构造函数模式

Person()函数

与createPerson()函数的不同之处

JavaScript第六章学习_第4张图片

按照惯例,构造函数始终都应该以一个 大写字母开头,而非构造函数则应该以一个小写字母开头

创建对象新例要使用new操作符

经历的步骤:

JavaScript第六章学习_第5张图片

任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数,否则则为普通函数

缺点:每个方法都要在每个实例重新创建

3.原型模式

每个函数都有prototype(原型)属性

该属性是一个指针,指向一个对象

用途:包含可以由特定类型的所有实例共享的属性和方法

不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中

1.理解原型

只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象

所有实现中都无法访问到[[Prototype]],但可以通过 isPrototypeOf()方法来确定对象之 间是否存在这种关系

Object.getPrototypeOf()函数

返回[[Prototype]]的值

调用 person1.sayName()的时候,会先后执行两次搜索(先实例,再原型)

原型最初只包含 constructor 属性,而该属性也是共享的,因此可以通过对象实例访问

可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值

设置同名的属性,在实例中创建,而原型中的属性将屏蔽

使用 delete 操作符则可以完全删 除实例属性,从而让我们能够重新访问原型中的属性

hasOwnProperty()方法可以检测一个属性是存在于实例中,还是存在于原型中

Object.getOwnPropertyDescriptor()方法只能用于实例属 性,要取得原型属性的描述符,必须直接在原型对象上调用 Object.getOwnProperty- Descriptor()方法

2.原型与 in 操作符

单独使用:in 操作符会在通 过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原型中

在 for-in 循环中使用:在使用 for-in 循环时,返回的是所有能够通过对象访问的、可枚举的(enumerated)属性

Object.keys()方法

目的:取得对象上所有可枚举的实例属性

接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组

Object.getOwnPropertyNames() 方法

得到所有实例属性,无论它是否可枚举

强制改动constructor属性将导致[[Enumerable]]特性被设置为 true

Object.defineProperty():重设构造函数功能

3.原型的动态性

在原型中查找值的过程是一次搜索,对原型对象所做的任何修改都能够立即从实例上反映出来

实例与原型之间的松散连接关系

实例中的指针仅指向原型,而不指向构造函数,一旦设立构造函数,将切断与实例之间的关系

JavaScript第六章学习_第6张图片
4.原生对象的原型

所有原生引用类型(Object、Array、String,等等)都在其构造函数的原型上定义了方法

通过原生对象的原型,不仅可以取得所有默认方法的引用,而且也可以定义新方法

如果因某个实现中缺少某个方法,就在原生对象的原型中添加这个方法,那么当在另一个支 持该方法的实现中运行代码时,就可能会导致命名冲突,也会意外重写原生方法

5.原生对象的问题

原型中所有属性是被很多实例共享的,这种共享对于函数非常合适

4.组合使用构造函数模式和原型模式

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

5.动态原型模式

使用动态原型模式时,不能使用对象字面量重写原型

6.寄生构造函数模式

基本思想:创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象

返回的对象与构造函数或者与构造函数的原型属 性之间没有关系

7.稳妥构造函数模式

没有公共属性,而且其方法也不引用 this 的对象

与寄生构造函数类似的模式的不同点

新创建对象的 实例方法不引用 this

不使用 new 操作符调用构造函数

与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间也 没有什么关系,因此 instanceof 操作符对这种对象也没有意义。

三、继承

1.原型链

利用原型让一个引用类型继承另一个引用类型的属性和方法

JavaScript第六章学习_第7张图片

别忘记默认的原型

默认原型都会包含一个内部指针,指向 Object.prototype

因此所有自定义类型都会继承 toString()、 valueOf()等默认方法

确定原型和实例的关系

通过两种方式来确定原型和实例之间的关系:

1.使用 instanceof 操作符,只要用 这个操作符来测试实例与原型链中出现过的构造函数,结果就会返回 true

2.使用 isPrototypeOf()方法。同样,只要是原型链中出现过的原型,都可以说是该 原型链所派生的实例的原型,因此 isPrototypeOf()方法也会返回 true

谨慎地定义方法

给原型添加方法的代码一定要放在替换原型的语句之后,否则将无效

通过原型链实现继承时,不能使用对象字面量创建原型方法,否则将重写原型链

原型链的问题

包含引用类型值的原型,会被所有实例共享

通过原型来实现继承时,原型实际上会变成另一个类型的实例,原先的实例属性也就顺理成章地变成了现在的原型属性了

2.借用构造函数

在子类型构造函数的内部调用超类型构造函数

通过使用 apply()和 call()方法也可以在(将来)新创建的对象上执行构造函数

传递参数:可以在子类型构造函数中向超类型构造函数传递参数

借用构造函数的问题

3.组合继承(combination inheritance)

也叫做伪经典继承

将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式

思路:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承

4.原型式继承

借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型

前提:必须有一个对象可以作为另一个对象的基础

Object.create()方法

接收两个参数:一 个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象(会覆盖掉原型对象上同名属性)

5.寄生式继承

创建一个仅用于封装继承过程的函数,该 函数在内部以某种方式来增强对象,后再像真地是它做了所有工作一样返回对象

使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一 点与构造函数模式类似

6.寄生组合式继承

组合继承大的问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部

导致的问题:子类型终会包含超类型对象的全部实例属性,但我们不得不在调用子 类型构造函数时重写这些属性

寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法

思路:使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型

YUI的 YAHOO.lang.extend()方法采用了寄生组合继承,从而让这种模式首次 出现在了一个应用非常广泛的 JavaScript库中

四、小结

JavaScript第六章学习_第8张图片

你可能感兴趣的:(JavaScript第六章学习)