1、什么是对象?html
面 向对象(Object-Oriented,OO)的语言有一个标志,那就是都有类的概念,例如C++、Java等;可是ECMAScript没有类的概 念。ECMAScript-262把对象定义为:无序属性的集合,其属性能够包含基本值、对象或者函数。通俗一点的理解就是,ECMAScript中的对 象就是一组数据和功能的集合,经过new操做符后跟要建立的对象类型的名称来建立。每一个对象都基于一个引用类型建立。引用能够是原生类型(相关介绍:引用类型),或者开发人员自定义的类型。web
2、Object对象app
跟其余OO语言同样,Object对象类型是全部它的实例的基础。Object对象类型所具备的任何属性和方法一样也存在于更具体的对象中。函数
//建立object对象 var o = new Object(); //若没有参数传递,能够省略圆括号,但不推荐使用 var o = new Object;
Object的每一个实例都具备共同的基本属性和方法this
属性或者方法 | 说明 |
constructor | 指向建立当前对象的构造函数 |
hasOwnProperty(name) | 检测给定属性name在实例对象(不是原型对象)中是否存在。name以字符串形式指定 |
isPropertyOf(object) | 检测传入的对象object是否该方法调用者的原型对象。通常格式:Class.prototype.isPropertyOf(object) |
propertyIsEnumerable(pr) | 检测属性pr可否用for-in循环枚举。属性pro用字符串形式指定 |
toLocaleString() | 返回对象的字符串表示。与地区和环境对应 |
toString() | 返回对象的字符串表示 |
valueOf() | 返回对象的字符串、数值或布尔值表示 |
3、对象的属性类型spa
在ECMAScript 5中,定义了用于描述属性的各类特征的内部特性,为实现JavaScript引擎服务,因此这些特性在JavaScript中不能直接访问。属性类型有两种:数据属性和访问器属性。prototype
一、数据属性rest
数据属性包含一个数据值的位置,在这个位置对数据进行读取和写入。ECMAScript定义了4个特性来描述数据属性的行为:code
特性 | 说明 |
[[Configurable]] | 表示可否经过delete删除属性从而从新定义属性、可否修改属性的特性、可否把属性修改成访问器属性。默认值是true |
[[Enumerable]] | 表示能都经过for-in循环返回属性。默认值是true |
[[Writable]] | 表示可否修改属性。默认值是true |
[[Value]] | 表述属性的数据值。默认值是undefined |
二、访问器属性htm
访问器属性不包含数据值,不能直接定义。读取访问器属性时,调用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); //20 alert(desc.configurable); //true alert(desc.enumerable); //true alert(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); //male delete 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表示属性只能写入不能读取。
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,blog alert(Object.getOwnPropertyNames(person)); //name,age,interesting,blog,sex
由于sex属性是用defineProperty()方法定义,而对于未指定的enumerable的值默认是false。因此第一次弹框没有返回sex属性,而第二次返回了。
4、建立对象的方式
一、工厂模式
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
优势:节省代码量,防止冗余。
缺点:不能识别对象,即建立的每一个实例都有相同的属性,不能反应对象的类型。
二、构造函数模式
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()方法。
三、原型模式
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); //dwqs var per2 = new Person(); alert(per1.interest == per2.interest); //true
per1和per2共享了全部原型上定义的属性和方法,显然,不能保持每一个实例的独立性了,不是咱们想要的。具体关于原型,后续笔记在解释。
四、原型模式+构造函数模式(推荐使用)
function Person(name,age,blog) { this.name = name; this.age = age; this.blog = blog; } Person.prototype.interest = function() { alert("I like coding and writing blog!!!"); } var per1 = new Person("dwqs",20,"www.ido321.com"); alert(per1.name); //dwqs var per2 = new Person("i94web",22,"www.i94web.com"); alert(per2.blog); //www.i94web.com
构造函数定义每一个实例的不一样属性,原型共享共同的方法和属性,最大限度的节省内存。
五、动态原型模式
function Person(name,age,blog) { this.name = name; this.age = age; this.blog = blog; if(typeof this.interest != "function") { Person.prototype.interest = function() { alert("I like coding and writing blog!!!"); }; } } var per1 = new Person("dwqs",20,"www.ido321.com"); per1.interest(); //I like coding and writing blog!!!
将全部信息均封装在构造函数中,在须要的时候,初始化原型。
六、寄生构造函数模式
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
形式跟工厂模式同样,但这个能够在特殊状况下用来为对象建立构造函数,而且使用new操做符建立对象,而工厂模式没有使用new,直接使用返回的对象。例如,在不能修改原生对象Array时,为其添加一个新方法
function SpecialArray() { var values = new Array(); values.push.apply(values,arguments); values.toPipedString = function() { return this.join("|"); }; return values; } var colors = new SpecialArray("red","blue","yellow"); alert(colors.toPipedString()); //red|blue|yellow
须要说明的是,寄生构造函数模式返回的对象与构造函数或者构造函数的原型对象没有关系,因此不能用instanceof操做符来肯定对象类型。
七、稳妥构造函数模式
function Person(name,age,blog) { var o = new Object(); o.sayName = function() { alert(name); } return o; } var per1 = Person("dwqs"); per1.sayName(); //dwqs
以这种方式建立的对象,除了sayName()方法以外,没有其余办法访问name的值。per1称为稳妥对象。稳妥对象指没有公共属性,其方法也不引用this的对象。
稳妥构造函数模式与寄生构造函数有两点区别:新建对象的实例方法不引用this;不使用new操做符调用构造函数。