您的位置:首页 > Web前端 > JavaScript

《JS高级程序设计-第3版》的读书笔记关于对象

2019-07-27 16:07 232 查看
原文链接:http://www.cnblogs.com/ant-xu/p/11255498.html

ECMAScript与其他OO语言对象的区别:js中没有类的概念,但是有对象的概念,ECMA-262把对象定义为,无序属性的集合,其属性可以包含基本值、对象或者函数。这里我将其当成java中的HashMap<Key, Object>,一个HashMap对应一个对象。应为没有类的概念所以对象的创建也有一些不同。在js里每个对象都是基于一个引用类型创建的(或者说是'对象定义')。可以是js原生类型(例如:Object、Array、Date)也可以是自定义的引用类型。

对象的创建:对象的创建的统一方式是new操作符后跟构造函数。例如:var person = new Object()。但是对于不同的类型还可能存在着不同的字面量表示法。例如Object和Array类型:

Object类型,使用字面量表示法创建对象
var person = {
"name" : "abc",    //属性名也可以是字符串
age : 18,
5 : true        //最后一个属性后没有逗号,不同版本浏览器可能会出错,数值5转化为字符串
};    //这有个分号,js中表达式上下文指的是能够返回一个值(表达式),这里的{}及其内部构成表达式

var person ={}; //与new Object()相同,现在版本这句话不会调用Object构造函数,以前的可能。
person.name = "abc";
person.age = 18;

Array类型,使用字面量表示法创建对象
var colors = ["red", "blue", "green"]; //创建一个包含3个字符串的数组
var names = [];                      //创建一个空数组
var values = [1,2,];                  // 不要这样!这样会创建一个包含2或者3项的数组
var options = [,,,,,];                  // 不要这样!这样会创建一个包含5或者6项的数组

在js中可以用person.name来访问属性,也可以用person["name"]这种方括号语法,方括号语法可以访问一些特别的属性名,类如person["first name"],或者访问属性名是关键字或保留字的属性。

对象的属性:js中有两种属性,数据属性和访问器属性。不同的属性有不同的特性,这些特性描述了属性的各种特征。(类比为,属性为成员变量,特性为public、static、final这些修饰符),特性是给js引擎用的,不能直接访问。

数据属性:数据属性包含一个数据值的位置,在这个位置可以读写。即可以通过person.name这样访问和赋值的属性。该属性有四个特性:

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把苏醒修改为访问器属性 。对于直接在对象上定义的属性,如上例该值默认为true。

[[Enumerable]]:表示能否通过for-in循环返回属性。对于直接在对象上定义的属性,如上例该值默认为true。

[[Writable]]:表示能够修改属性的值。对于直接在对象上定义的属性,如上例该值默认为true。

[[Value]]:包含这个属性的数据值。读写都是在这个位置。默认为undefined。

 属性的特性可以修改,但是要使用ECMAScript5的Object.defineProperty()方法。这个方法就收三个参数:属性所在对象、属性的名字和一个描述符对象。其中描述符对象必须为上面的特性的一个或多个(注意首字母小写,js是区别大小写的)。

var person = {};
Object.defineProperty(person, "name", {
writable: false,     //即便删除这一行,下面输出部分的结果也是一样的。
value: "Nicholas"
});

alert(person.name);  //"Nicholas"
person.name = "Greg";
alert(person.name);  //"Nicholas"

在非严格模式会忽略,在严格模式会报错。这里值得注意的地方有两个。其一、如果这里修改的特性如果为configurable,即将configurable修改为false,那么你就没有办法修改回来了。其二、这里了传入的特性虽然只有一个,但是默认为传入四个值,并且默认值都是false(value默认为undefined)。这也就意味着一旦defineProperty运行,只有传入的特性可以操控,其余的都是false。即上面的方法调用后,其实即便删除writable: false。其结果也是一样的。

访问器属性:访问器属性不包含数据值。它们包含一堆getter和setter函数(不过,这两个函数都不是必需的)。这两句话我的理解是,这个属性因为它包含两个函数,为了方便使用这两函数,用一个标识符来代替这两个函数,以达到用"对象名.访问器属性"这种方式就能访问这两个函数的程度。这个标识符就是访问器属性。该属性有四个特性如下。

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,(访问器也可以直接定义?)默认为true。

[[Enumerable]]:表示能否通过for-in循环返回属性。对于直接在对象上定义的属性,(访问器也可以直接定义?)默认为true。

[[Get]]:在读取属性时调用的函数。默认为undefined。

[[Set]]:在写入属性时调用的函数。默认为undefined。

访问器属性不能直接定义,必须用Object.defineProperty()来定义,例子如下:

var book = {
_year: 2004, //_year前面的下划线是一种常用的记号,用于表达只能通过对象方法访问的属性。
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);  //2

上面例子就是访问器属性的常见用法,即设置一个属性的值导致其他属性发生变化。其在调用defineProperty()方法后同样存在不操作的属性设置为false。(get和set属性设置为undefined的情况,get和set还不知道怎么验证所以括起来,有可能get和set为指向getter和setter的指针,也有可能为null)。但是只对访问器属性有效果,例如上例,enumerable和configurable变成了false,但是只对year这个属性起作用,在for-in中不返回year属性,delete book.year; 无效果。

两个遗留的方法创建访问器属性:

var book = {
_year: 2004,
edition: 1
};

book.__defineGetter__("year", function(){  //遗留的__defineGetter__()方法
return this._year;
});

book.__defineSetter__("year", function(newValue){ //一流的__defineSetter__()方法
if (newValue > 2004) {         this._year = newValue;
this.edition += newValue - 2004;
}
});

book.year = 2005; alert(book.edition);  //2

ECMAScript 5 中有个Object.defineProperties()的方法,用于复制属性和属性的特性。第一个参数时要添加和修改的对象,第二个是模板,第二个对象的属性和第一个对象的某个属性相同时应该就是修改了。

var book = {
x:100
};

var fee = {
_year: {         //由下面for-in的输出结果可以看出,这种属性后加{}来定义属性的方式
value: 2004    //会使其余特性会变成false,因为不是在对象上直接定义
},
edition: {
value:  1
},
say: {
value: function(){
alert("123");
}
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
}

Object.defineProperties(book, fee); //fee可以用fee等号右边的整个来代替
for(var y in book){
console.log(y);        //只输出了属性x,因为其余属性的enumerable都为false
}
book.say();
console.log(book.year);
console.log(book.x);    //原本的book.x并没有发生改变

ECMAScript 5 中的Object.getOwnPropertyDescriptor()用于读取属性的特性,属性不同对应不同的特性,第一个参数为对象,第二个参数为属性名称。返回一个以特性为属性的对象,属性值为原本的特性值。如下

var book = {};

Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});

var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value);         //2004
alert(descriptor.configurable); //false
alert(typeof descriptor.get);    //"undefined"
var descriptor = Object.getOwnPropertyDescriptor(book, "year");
alert(descriptor.value);        //undefined
alert(descriptor.enumerable);   //false
alert(typeof descriptor.get);   //"function"

 

转载于:https://www.cnblogs.com/ant-xu/p/11255498.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: