创建对象
var a1 = new Object();
a1.name = "a1";
a1.age = 20;
a1.job = 'IT';
a1.sayName = function(){
console.log(this.name);
};
var a2 = {
name:'a2',
age:20,
job:'IT',
sayName:function(){
console.log(this.name);
}
};
数据属性
数据属性包含一个数据值的位置,在这个位置可以读取和写入值,数据属性有四个描述其行为的特性。
- Configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,像上面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
- Enumerable:表示能否通过for-in循环 返回属性,像上面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
- Writable:表示能否修改属性的值,像上面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
- Value:包含这个属性的数据值,读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置,这个特性的默认值为undefined。
在上面的例子中,都含有一个名为age的属性,并为它指定的值是20,也就是说[[Value]]特性被设置为20,而对这个值的任何修改都将反映在这个位置,要修改属性默认的特性,必须使用Object。defineProperty()方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符(descriptor)对象。其中,描述符对象的属性必须是:configurable,enumerable,writable和value。设置其中的一个或多个值,可以修改对应的特性值。
var b = {};
Object.defineProperty(b,'name',{
writable:false,
value:'Nicholas'
});
console.log(b.name); //Nicholas
b.name = "Greg";
console.log(b.name); //Nicholas
上面的例子中创建了一个name属性,他的属性值“Nicholas”是只读的,这个属性的值是不可修改的,如果尝试修改,在非严格模式下,赋值操作将被忽略,在严格模式下,赋值操作会导致抛出错误。类似的规则也适用于不可配置的属性。
var c = {};
Object.defineProperty(c,'name',{
configurable:false,
value:'Nicholas'
});
console.log(c.name); //Nicholas
delete c.name;
console.log(c.name); //Nicholas
把configurable设置为false,表示不能从对象中删除该属性,如果这个属性调用delete,在非严格模式下什么也不会发生,而在严格模式下会导致错误。而且,一旦把属性定义为不可配置的,就不能再把它变回可配置了。此时,再调用Object.defineProperty()方法修改除writable之外的特性,都会导致错误。
var d = {};
Object.defineProperty(d,'name',{
configurable:false,
value:'Nicholas'
});
Object.defineProperty(d,'name',{ //Uncaught TypeError: Cannot redefine property: name
configurable:true,
value:'Nicholas'
});
也就是说,可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false之后就会有限制了。
在调用Object.defineProperty()方法时,如果不指定,configurable,enumerable和writable特性的默认值都是false。
访问器属性
访问器属性不包含数据值,由一对getter和setter函数(均非必须)构成,在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下4个特性:
- configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性,对于直接在对象上定义的属性,这个特性的默认值为true。
- enumerable:表示能否通过for-in循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为true。
- get:在读取属性时调用的函数,默认值为undefined。
- set:在写入属性时调用的函数,默认值为undefined。
访问器属性不能直接定义,必须使用Object.defineProperty()来定义。
var e = {
_year:2016,
edition:1
};
Object.defineProperty(e,"year",{
get:function(){
return this._year;
},
set:function(newValue){
if(newValue > 2016){
this._year = newValue;
this.edition += newValue - 2016;
}
}
});
c.year = 2018;
console.log(c.edition); //3
上面的例子中创建了一个对象,并给它定义了两个默认的属性:_year和edition。_year前面的下划线是一个记号,用于表示只能通过对象方法访问的属性,而访问器属性year则包含一个getter函数和一个setter函数。getter函数返回_year的值,setter函数通过计算来确定正确的版本,因此把year属性修改为2018会导致_year变成2018,而edition变为3,这是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。
不一定非要同时指定getter和setter,只指定getter以为着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入只指定了getter函数的属性会抛出错误。类似低,没有指定setter函数的属性也不能读,否则在非严格模式下会返回undefined,而在严格模式下会抛出错误。
toString
toString()
表示的含义是把这个对象表示成字符串形式, 并且返回这个字符串形式. 首先,在Object.prototype
中它对toString()方法的默认实现是"[object Object]"
当我们在自己的对象或者原型上对toString()进行重写覆盖后,在访问这个对象的toString()方法时,就会沿着原型链上查找,刚好在自身对象上就找到了toString(),这是就不用再去找原型链上的顶端Object.prototype的默认的toString()了。
继续看方法重写:
首先是第一个打印,输出的是标准时间,也就是说,Date这个构造函数的原型其实是有toString()方法的,也就是js引擎已经在Date原型对象中重写了toString()方法,这样,就不会再继续到Object.prototype里面去寻找了。第二个打印中就能看到构造函数的原型中的toString()方法。
从第三个和第四个打印中可以知道,js引擎在Number对象上重写了toString()方法,用于将数字转为字符串。
valueOf()
valueOf()
返回这个对象表示的基本类型的值!在
Object.prototype.valueOf
中找到, 默认返回的是this。当需要在对象上重写
valueOf()
时,应该是返回一个基本数据类型的值。 先看一个默认返回的值的情况。(也就是说它是去这个对象的原型链的顶端
Object.prototype.valueOf
找的
valueOf
方法 )
![](https://i-blog.csdnimg.cn/blog_migrate/c81370c833d7131a9f243d5c8770f9c8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/92c48f688ad408f9fe9d0b184b34ddac.png)
在上面例子中,p1.valueOf
是在Object.prototype.valueOf
找到的,返回值默认this。此时this就是p1的这个对象。故结果返回true。
valueOf()也能进行重写
前面三个都是重写了valueOf()的,而第四个的打印就说明这个时候正则对象上没有valueOf,是在Object.prototype.valueOf找的,返回this,this指的就是regExp正则对象。