浅析Javascript面向对象程序设计之对象
2018-01-15 00:50 jym94 阅读(139) 评论(0) 收藏 举报什么是对象
众所周知,Javascript是一门面向对象的编程语言。本人最近看书小有心得,特此总结一下关于javascript面向对象编程的几个知识点。
ECMA-262把对象定义为一组无序属性的集合,其属性可以包含基本值、对象或函数。
var person = new Object();
person.name = "Jym";
person.sayName = function(){
alert(this.name);
}
以上代码定义了一个最基本的对象,并添加了一个name属性和一个sayName方法。当然,我们的对象还可以使用另一种方法来定义。
var person = {
name : "Jym";
sayName : function() {
alert(this.name);
}
}
甚至,我们还可以用第三种方法来定义一个对象。
var person = { };
Object.defineProperty(person, "name", {
value : "Jym"
})

需要特别注意的是,首先Object.defineProperty是ECMAScript5中的方法,所以各位需要支持IE9以下版本浏览器的同学请自动忽略它(为你们默哀三秒)。
其次,Object.defineProperty定义的数据类型默认的configurable,enumerable,writable特性都是false。(给不知道这三种特性的同学讲一下,configurable表示属性能否被删除,能否被修改。enumerable表示属性能否通过for-in循环返回。writable表示属性的值能否修改。)
嘿嘿,你要是觉得不爽,可以手动改掉它们。
Object.defineProperty(person, "name", {
value : "Jym",
configurable : true
})
Object.defineProperty还可以用来定义对象的访问器属性。访问器属性不包含数据值,但是包含一对getter和setter函数。读取访问器属性调用getter函数,写入访问其属性调用setter函数。有一点需要注意的是,访问器属性只能通过Object.defineProperty来定义。

var book = {
_year : 2004, //下划线表示属性只能通过对象方法来访问
edition : 1
}
Object.defineProperty(book , "year" , {
get : function() {
return this._year;
},
set : function() {
if(newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
getter和setter不一定要同时指定。只指定getter意味属性是不能写的,嗯,接下来请自觉举一反三。
如果想要通过Object.defineProperty给对象定义多个属性,这也是可以的。
var book = { };
Object.defineProperty(book, {
_year: {
value: 2004,
writable:true
},
year: {
get : function() {
return this._year;
},
set : function() {
if(newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});
ECMAScript5中给了一个Object.getOwnPropertyDescriptor()方法用来取得给定属性的描述符。这个方法接收两个参数,分别是属性所在的对象以及要读取其描述符的属性名称。
var desc = Object.getOwnPropertyDescriptor(book , "year");
alert(desc.value); //undefined
alert(typeof desc.get); //"function"
创建对象的几种模式
接下来,我们具体分析一下创建对象的几种模式的优劣性。
工厂模式
function CreatePerson(name, age) {
var o = new object();
o.name = name;
o.age = age;
o.sayName = function() {
alert(this.name);
}
return o;
}
工厂模式的劣势是无法识别一个对象的类型。于是,机智的猿们想到了另一个模式。
构造函数模式
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
};
}
var preson1 = new Person("Jym",23);
在上面这个例子中,Person是一个构造函数。js中的构造函数一般以大写字母开头,非构造函数一般以小写字母开头。
在创建person1这个实例时,必须使用new操作符。同时,用这种方法调用构造函数会经历以下四个步骤。

- 创建一个新对象
- 将构造函数的作用于赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码
- 返回新对象
实例person1中有一个constructor属性,该属性指向Person。
person1.constructor == Person; //tue
嘿嘿,接下来我们可以来检测一下这个对象的类型了。
person1 instanceof Object //true
person1 instanceof Person //true
nice!
那么这种模式就是完美无缺的吗?显然是不可能的。

function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
};
}
相当于
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = new Function("alert(this.name)");
}
可以看到,以这种方法创建实例函数,每个实例函数都创建了一个完成同样任务的function,这是相当没有必要的。所以我们可以换一个方式来解决这个问题。
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = sayName;
}
function sayName() {
alert(this.name)
}
这样一来,就避免了每个实例都需要去创建sayName方法。实例中包含的是一个指向sayName函数的指针。但是问题又来了,如果对象需要定义很多个方法,那我们就得去定义很多个全局函数,这既繁琐又破坏了对象的封装性。(封装,即把属性和方法封装成抽象的类,隐藏属性和方法的实现细节,仅对外公开接口。)
为了解决这个问题,我们只能祭出传说中的终极杀招,“原型模式”!
欲知后事如何,且看下回《浅析Javascript面向对象程序设计之原型》
浙公网安备 33010602011771号