学习�目标
- 理解对象属性
- 理解并创建对象(重要)
- 理解继承(重要)
概述
面向对象(OO)的语言都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象,js中的对象是"无序属性的集合,其属性可以包含基本值,对象或者函数"
创建自定义对象的2�种常见方式
- 创建一个Object的�实例
var person = new Object()
person.name = 'qianlongo'
person.sayName = function () {
alert(this.name)
}
- 对象字面量创建
var person = {
name: 'qianlongo',
sayName: function () {
alert(this.name)
}
}
- 数据属性
- 访问�器属性
数据属性
数据属性包含一个数据值的位置,在这个位置可以读取和写入值,数据属性有4个描述其行为的特性。
[[Configurable]] : 表示1 能否通过delete删除属性重而重新定义属性
,2. 能否修改属性的特性
,3. �能否把属性修改为访问器属性
,使用new Object或对象字面量,默认值为true
[[Enumerable]] : 表述能否通过for in循环返回属性,使用new Object或对象字面量,默认值为true
[[Writable]] : 表述能否修改属性的值,使用new Object或对象字面量,默认值为true
[[Value]] : 包含这个属性的数据值,读取属性值的时候,从这个位置读,写入属性值的时候,把新值保存到这个位置。这个特性的默认值为undefined。
经过测试,通过Object.defineProperty定义对象的属性 Configurable、Enumerable、Writable默认�值都是false,而Value没有设置则是undefined
可以多次调用Object.defineProperty()方法修改同一属性,但在把configurable特性设置为false之后就会有限制了。
访问器属性
访问器属性不包括数据值,包含一堆getter和setter�函数(这两个函数不是必须的)。在读取属性的时,会调用getter函数,这个函数负责返回有效值,在写入访问器属性时,会调用�getter函数并传入新值,这个函数负责决定如何处理�数据。分别�有以下属性
[[Configurable]] : 表示1 能否通过delete删除属性重而重新定义属性
,2. 能否修改属性的特性
,3. �能否把属性修改为访问器属性
,使用new Object或对象字面量,默认值为true
[[Enumerable]] : 表述能否通过for in循环返回属性,使用new Object或对象字面量,默认值为true
[[Get]] : 在读取属性时调用的函数,默认值为undefined
[[Set]] : 在写入属性时调用的函数,默认值为undefined
访问器属性不能直接定义,必须使用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)
不一定get和set函数都要指定,�只指定get,意味着只能读不能写,只指定set,意为着只能写不能读
同样我们可以使用__defineGetter__
和__defineSetter__
来做��一些get、set的事情
var book = {
_year: 2004,
edition: 1
}
book.__defineGetter__('year', function () {
return this._year
})
book.__defineSetter__('year', function (newValue) {
if (newValue > 2004) {
this._year = newValue
this.edition += newValue - 2004
}
})
Object.defineProperties()一次描述多个属性。
var book = {}
Object.defineProperties(book, {
_year: {
value: 2004,
writable: true // 不指定将不可写
},
edition: {
value: 1,
writable: true
},
year: {
get: function () {
return this._year
},
set: function (newValue) {
if (newValue > 2004) {
this._year = newValue
this.edition += newValue - 2004
}
}
}
})
使用Object构造函数和对象字面量的形式来创建对象有一个明显的缺点,使用同一个接口创建很多对象,会产生很多垃圾代码。
创建对象的模式有很多种,比如
工厂模式
、构造函数模式
、原型模式
、混合构造函数和原型模式
等等,这里做主要的代码示例和介绍。
工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程,用函数来封装以特定接口来创建对象的细节。
function createPerson (name, sex, age) {
let o = new Object()
o.name = name
o.sex = sex
o.age = age
o.sayName = function () {
console.log(this.name)
}
return o
}
let p1 = createPerson('qianlongo', 'boy', 100)
let p2 = createPerson('huihui', 'boy', 1000)
评论
createPerson
函数能够根据传入的参数来构建包含三个所有必要信息的Person
对象,可以无数次的调用这个函数,而它每次都会返回包含三个属性的一个方法的对象。工厂模式虽然解决了创建多个相似对象的代码冗余问题,但是却没有解决对象识别
的问题。
构造函数可以用来创建特定类型的对象,有些类似Array和Object在运行时就自动出现在执行环境中,此外,也可以自定义�构造函数。从而自定义对象类型的属性和方法。
function Person (name, sex, age) {
this.name = name
this.sex = sex
this.age = age
this.sayName = function () {
console.log(this.name)
}
}
let p1 = new Person('qianlongo', 'boy', 100)
let p2 = new Person('huihui', 'girl', 1000)
比较两个例子可以发现,有以下区别。
- 没有显示地创建对象
- 直接将属性和方法赋给了this对象
- 没有return语句
- 构造函数名字使用首字母大写
创建Person实例大概经历了以下几步
- 创建一个新的对象
- 将构造函数的作用域赋值给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新的对象
创建自定义的构造函数意味着可以将它的实例标记为一种特定的类型�,这也是其胜过工厂模式的地方