DOM笔记(十一):JavaScript对象的基本认识和创建

一、什么是对象?

面向对象(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);   //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表示属性只能写入不能读取。

  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,blog
alert(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);  //dwqs
var 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 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

构造函数定义每个实例的不同属性,原型共享共同的方法和属性,最大限度的节省内存。

5、动态原型模式

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!!!

将所有信息均封装在构造函数中,在需要的时候,初始化原型。

6、寄生构造函数模式

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操作符来确定对象类型。

7、稳妥构造函数模式

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操作符调用构造函数。

原文首发:http://www.ido321.com/1365.html

时间: 2024-08-08 17:54:45

DOM笔记(十一):JavaScript对象的基本认识和创建的相关文章

学习Javascript笔记1 Javascript对象1

以前学过一段时间Js,现在再看,感觉又像是新知识,说明自己对Js掌握的还不是很好(是很不好,从来就没好过,嘿嘿),在这里,在温习一下 如果各位大哥大姐不幸看到了,,额 额这只是自己的笔记. 在Js里面 面向对象的思想是绝对很重要的,大家如果看过大神的代码,就会知道在Js里面面向对象的思想有多么重要了 JavaScript 中的所有事物都是对象:字符串(String).数字(Number).数组(Array).日期(Date),等等. 在 JavaScript 中,对象是拥有属性和方法的数据. 属

DOM笔记(十三):JavaScript的继承方式

在Java.C++.C#等OO语言中,都支持两种继承方式:接口继承和实现继承.接口继承制继承方法签名,实现继承则继承实际的方法和属性.在SCMAScript中,由于函数没有签名,所以无法实现接口继承,只支持实现继承. 实现继承主要依靠原型链来实现. 一.原型链 原型链是利用原型让一个引用类型继承另一个引用类型的方法,在DOM笔记(十二):又谈原型对象中,描述了构造函数.实例和原型之间的关系: 每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而每个实例都包含一个指向原型对象的内部

JavaScript进阶系列03,通过硬编码、工厂模式、构造函数创建JavaScript对象

本篇体验通过硬编码.工厂模式.构造函数来创建JavaScript对象. □ 通过硬编码创建JavaScript对象 当需要创建一个JavaScript对象时,我们可能这样写: var person = { firstName: "Darren", lastName: "Ji", getFullName: function() { return this.firstName + " " + this.lastName; } }; 如果需要创建2个结

DOM笔记(十二):又谈原型对象

因为之前谢过一篇关于原型对象的笔记:浅谈JavaScript中的原型模式.现在我又重新看到这个话题,对原型有了进一步的理解,所以,又要谈谈原型对象. 一.理解原型对象 创建的每一个函数都有一个prototype属性,它指向这个函数的原型对象.利用原型模式创建的方法和属性是被所有实例所共享的. function Person(){} Person.prototype.name="dwqs"; Person.prototype.age=20; Person.prototype.sayNam

DOM笔记(十):JavaScript正則表達式

一.RegExp ECMAScript通过RegExp类型类支持正則表達式,语法和Perl类似: var exp = /pattern/flags; patternb部分是不论什么简单的或复杂的正則表達式:flags是每一个正則表達式所带的一个或者多个标志. 正則表達式的模式匹配支持三个标志: g:全局模式,即模式应用于整个字符串.而非在发现第一个匹配项时马上停止 i:不区分大写和小写模式 m:多行模式,即到达一行文本末尾是还会继续茶查找下一行中是否存在与模式匹配的项. 1.创建正則表達式 Ja

DOM笔记(十):JavaScript正则表达式

一.RegExp ECMAScript通过RegExp类型类支持正则表达式,语法和Perl类似: var exp = /pattern/flags; patternb部分是任何简单的或复杂的正则表达式:flags是每个正则表达式所带的一个或者多个标志. 正则表达式的模式匹配支持三个标志: g:全局模式,即模式应用于整个字符串,而非在发现第一个匹配项时立即停止 i:不区分大小写模式 m:多行模式,即到达一行文本末尾是还会继续茶查找下一行中是否存在与模式匹配的项. 1.创建正则表达式 JavaScr

DOM笔记(八):JavaScript执行环境和垃圾收集

一.执行环境 在有关于JavaScript对象或者this的指向问题时,脱离不了的另外一个概念就是执行环境,即上下文环境.执行环境在JavaScript是一个很重要的概念,因为它定义了变量或函数有权访问的其它数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象,在该环境中定义的所有变量和函数都保存在这个对象中. 全局环境时最外围的一个执行环境.在Web浏览器中,全局环境被认为是Window对象(后续笔记中会讨论),因此所有的全局变量和函数都是作为window对象的属性或者方法创建的

DOM笔记(五):JavaScript的常见事件和Ajax小结

一.常见事件类型 1.鼠标事件 事件名称 说明 onclick 鼠标单击时触发 ondbclick 鼠标双击时触发 onmousedown 鼠标左键按下时触发 onmouseup 鼠标释放时触发 onmouseover 鼠标的光标移动到某对象上时触发 onmousemove 鼠标移动时触发 onmouseout 鼠标光标离开某对象时触发 ps:当单击一次鼠标左键的时候,将同时触发onclick.onmousedown.onmouseup三个事件,事件处理程序执行的先后顺序为:onmousedow

【JQuery】jquery对象和javascript对象即DOM对象相互转换

jQuery 对象是通过 jQuery 包装DOM 对象后产生的对象.jQuery 对象是 jQuery 独有的,其可以使用 jQuery 里的方法,但是不能使用 DOM 的方法:例如: $("#img").attr("src","test.jpg"); 这里的 $("#img")就是 jQuery 对象. DOM对象就是Javascript 固有的一些对象操作.DOM 对象能使用Javascript 固有的方法,但是不能使用