一、什么是对象?
面 向对象(Object-Oriented,OO)的语言有一个标志,那就是都有类的概念,例如C++、Java等;但是ECMAScript没有类的概 念。ECMAScript-262把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。通俗一点的理解就是,ECMAScript中的对 象就是一组数据和功能的集合,通过new操作符后跟要创建的对象类型的名称来创建。每个对象都基于一个引用类型创建。引用可以是原生类型(相关介绍:引用类型),或者开发人员自定义的类型。
二、Object对象
跟其他OO语言一样,Object对象类型是所有它的实例的基础。Object对象类型所具有的任何属性和方法同样也存在于更具体的对象中。
//创建object对象var o = new Object();//若没有参数传递,可以省略圆括号,但不推荐使用var o = new Object;
Object的每个实例都具有共同的基本属性和方法
属性或者方法 | 说明 |
constructor | 指向创建当前对象的构造函数 |
hasOwnPRoperty(name) | 检测给定属性name在实例对象(不是原型对象)中是否存在。name以字符串形式指定 |
isPropertyOf(object) | 检测传入的对象object是否该方法调用者的原型对象。一般格式:Class.prototype.isPropertyOf(object) |
propertyIsEnumerable(pr) | 检测属性pr能否用for-in循环枚举。属性pro用字符串形式指定 |
toLocaleString() | 返回对象的字符串表示。与地区和环境对应 |
toString() | 返回对象的字符串表示 |
valueOf() | 返回对象的字符串、数值或布尔值表示 |
三、对象的属性类型
在ECMAScript 5中,定义了用于描述属性的各种特征的内部特性,为实现Javascript引擎服务,所以这些特性在JavaScript中不能直接访问。属性类型有两种:数据属性和访问器属性。
1、数据属性
数据属性包含一个数据值的位置,在这个位置对数据进行读取和写入。ECMAScript定义了4个特性来描述数据属性的行为:
特性 | 说明 |
[[Configurable]] | 表示能否通过delete删除属性从而重新定义属性、能否修改属性的特性、能否把属性修改为访问器属性。默认值是true |
[[Enumerable]] | 表示能都通过for-in循环返回属性。默认值是true |
[[Writable]] | 表示能否修改属性。默认值是true |
[[Value]] | 表述属性的数据值。默认值是undefined |
2、访问器属性
访问器属性不包含数据值,不能直接定义。读取访问器属性时,调用getter函数,该函数负责返回有效值;写入访问器属性时,调用setter函数并传入新值。访问器也有4个属性:
特性 | 说明 |
[[Configurable]] | 表示能否通过delete删除属性从而重新定义属性、能否修改属性的特性、能否把属性修改为访问器属性。默认值是true |
[[Enumerable]] | 表示能都通过for-in循环返回属性。默认值是true |
[[Get]] | 读取属性时调用的函数,默认是undefined |
[[Set]] | 写入属性时调用的函数,默认是undefined |
怎么获取对象属性的默认特性呢?
var person = { name:"dwqs", age:20, interesting:"coding", blog:"www.ido321.com"};var desc = Object.getOwnPropertyDescriptor(person,"age");alert(desc.value); //20alert(desc.configurable); //truealert(desc.enumerable); //truealert(desc.writable); //true
使用ECMAScript 5的Object.getOwnPropertyDescriptor(object,prop)获取给定属性的描述符:object 是属性所在的对象,prop是给定属性的字符串形式,返回一个对象。若prop是访问器属性,返回的对象包含configurable、 enumerable、set、get;若prop是数据属性,返回的对象包含configurable、enumerable、writable、 value。
属性的特性都不能直接定义,ECMAScript提供了Object.defineProperty(obj,prop,desc):obj是属性所在的对象,prop是给定属性的字符串形式,desc包含特性集合的对象。
var person = { name:“dwqs”, age:20, interesting:“coding”, blog:“www.ido321.com” }; //定义sex属性,writable是false,所以不能修改 Object.defineProperty(person,“sex”,{ writable:false, value:“male” }); alert(person.sex); //male
//在严格模式下出错,非严格模式赋值被忽略 person.sex=“female”; //writable是false,所以不能修改 alert(person.sex); //male
可以多次调用Object.defineProperty()修改特性,但是,若将configurable定义为false,则不能再调用Object.defineProperty()方法将其修改为true。此外,调用Object.defineProperty()时若不指定特性的值,则configurable、enumerable和writable的默认值是false。
var person = { name:"dwqs", age:20, interesting:"coding", blog:"www.ido321.com"};Object.defineProperty(person,"sex",{ configurable:false, value:"male"});alert(person.sex); //maledelete person.sex; //configurable是false,严格模式下出错,非严格模式下忽略此操作alert(person.sex); //male//抛出Cannot redefine property: sex错误Object.defineProperty(person,"sex",{ configurable:true, value:"male"});alert(person.sex); //不能弹框delete person.sex;alert(person.sex);//不能弹框
也可以用Object.defineProperties(obj,props)同时定义多个属性:obj是属性所在的对象,props是一个包含多个属性定义的对象
var book={}; Object.defineProperties(book,{ _year:{ value:2014 }, edition:{ value:1 }, year:{ get:function() { return this._year; }, set:function(newValue) { if(newValue > 2014) { this._year = newValue; this.edition += newValue – 2014 } } } }); var descs = Object.getOwnPropertyDescriptor(book,“_year”); alert(descs.value); //2014
//调用Object.defineProperty()时若不指定特性的值,则configurable、enumerable和writable的默认值是false。 alert(descs.configurable); //false alert(typeof descs.get); //undefined
get和set可以不指定,也可以值指定二者之一。只有get表示属性是只读的,只有set表示属性只能写入不能读取。
3、枚举属性 ECMAScript 5定义了两个常用的方法用于枚举属性: Object.keys(obj):列举出obj能够枚举的所有属性,即对应的属性特性[[Enumerable]]是true的属性。 Object.getOwnPropertyNames(obj):列举出obj能够枚举的和不能枚举所有属性,即不管对应的属性特性[[Enumerable]]是true还是false。var person = { name:"dwqs", age:20, interesting:"coding", blog:"www.ido321.com"};Object.defineProperty(person,"sex",{ configurable:false, value:"male"});alert(Object.keys(person)); //name,age,interesting,blogalert(Object.getOwnPropertyNames(person)); //name,age,interesting,blog,sex
因为sex属性是用defineProperty()方法定义,而对于未指定的enumerable的值默认是false。所以第一次弹框没有返回sex属性,而第二次返回了。
四、创建对象的方式
1、工厂模式
function Person(name,age,blog){ var o = new Object(); o.name = name; o.age = age; o.blog = blog; o.interest = function() { alert("I like coding and writing blog!!!"); } return o;}var per1 = Person("dwqs",20,"www.ido321.com");alert(per1.name); //dwqs
优点:节省代码量,防止冗余。
缺点:不能识别对象,即创建的每个实例都有相同的属性,不能反应对象的类型。
2、构造函数模式
function Person(name,age,blog){ this.name = name; this.age = age; this.blog = blog; this.interest = function() { alert("I like coding and writing blog!!!"); }}var per1 = new Person("dwqs",20,"www.ido321.com");alert(per1.name);
优点:创建的每个实例都不同,可以识别不同对象。
缺点:创建一个实例,实例共有的方法都会重新创建。对应的解决方案可以把方法定义到全局上去,或者定义在原型对象上。
function Person(name,age,blog){ this.name = name; this.age = age; this.blog = blog; this.interest = my;} function my(){ alert("I like coding and writing blog!!!");}
这样,Person的所有实例均共享了my()方法。
3、原型模式
function Person(){ }Person.prototype.name = "dwqs";Person.prototype.age = 20;Person.prototype.blog = "www.ido321.com";Person.prototype.interest = function(){ alert("I like coding and writing blog!!!");}var per1 = new Person();alert(per1.name); //dwqsvar per2 = new Person();alert(per1.interest == per2.interest); //true
per1和per2共享了所有原型上定义的属性和方法,显然,不能保持每个实例的独立性了,不是我们想要的。具体关于原型,后续笔记在解释。
4、原型模式+构造函数模式(推荐使用)
function Person(name,age,blog){ this.name = name; this.age = age; this.blog = blog;}Person.prototype.interest = function(){ alert("I like
新闻热点
疑难解答