对象属性类型:数据属性和访问器属性
数据属性(EC5)
[[Configurable]]:能否把属性修改为访问器属性。默认值为true。[[Enumerable]]:能否通过for-in遍历到。默认值为true。[[Writable]]:能否修改属性值。默认值为true。[[Value]]:值。默认值为undefined。
var personA = {
name : 'Karyn'
};
var personB = {};
Object.defineProperty(personB, "name", {
configurable : false,
enumerable : false,
writable : false,
value : "Karyn"
});
// 一看两种声明都是一样的,可对应这我们上面的数据属性验证一下。
console.log(personA) // {name: "Karyn"}
console.log(personB) // {name: "Karyn"}
// 修改configurable 和 enumerable 会报错
Object.defineProperty(personB, "name", {
configurable : true
});
// 通过 for-in 不能遍历出来
for(var x in personB){
console.log(x); // undefined
}
// 值无法改变
personB.name = "song";
console.log(personB.name) // karyn
访问器属性
[[Configurable]]:能否把属性修改为访问器属性。默认值为true。[[Enumerable]]:能否通过for-in遍历到。默认值为true。[[Get]]:在读取该属性值时调用的函数。默认值为undefined。[[Set]]:在写入属性时调用的函数。默认值为undefined。
var person = {
_name : "karyn", // 通常我们用下划线开头来表示私有变量
edition : 1
}
Object.defineProperty(person, "name", {
get: function(){
return this._name;
},
set: function(newValue){
this._name = newValue;
this.edition++;
}
});
// person = {_name : "karyn", edition : 1, name : "karyn"}
// 我们看到_表示私有,但这里是特定的语法,我们看看换成其他符号呢
var person = {
$name : "karyn", // 通常我们用下划线开头来表示私有变量
edition : 1
}
Object.defineProperty(person, "name", {
get: function(){
console.log("get",this.$name,this.name);
},
set: function(newValue){
console.log("set",newValue);
}
});
// person = {_name : "karyn", edition : 1, name : [Exception: RangeError: Maximum call stack size exceeded]}
var person = {
name : "karyn", // 通常我们用下划线开头来表示私有变量
edition : 1
}
Object.defineProperty(person, "name", {
get: function(){
console.log("get",this.name);
},
set: function(newValue){
console.log("set",newValue);
}
});
// person = {edition : 1, name : [Exception: RangeError: Maximum call stack size exceeded]}
person.name = "song"
console.log(person.name) // song
console.log(person.edition) // 2
// 新的写法
var person = {
$name : "karyn",
edition : 1,
get name(){
console.log("get",this.$name);
},
set name(value){
this.$name = value;
this.edition++;
console.log("set",this.$name)
}
}
// 以上写法在更早之前可以写成以下方法
Object.__defineGetter__("name", function(){
return this._name;
});
Object.__defineSetter__("name", function(newValue){
this._name = newValue;
this.edition++;
});
读取属性的特性
// 通过 getOwnPropertyDescriptor 来读取私有字段
var descriptor = Object.getOwnPropertyDescriptor(person, "_name");
工厂模式与构造函数模式
检验方式可以通过constructor和instanceof来实现。但是还是有区别的。
function Person(){}
var person = new Person();
console.log(person.constructor === Person) // true
console.log(person.constructor === Object) // false
console.log(person instanceof Object) // true
console.log(person instanceof Object) // true
原型对象
var Person = function(){
this.name = "karyn";
}
Person.prototype = {
name: "song",
age: 11,
sayName: function(){
console.log(this.name)
}
}
var person = new Person();
// 在设计之初是不允许直接访问原型链的
// 可以用 isPrototypeOf 来测试 person 的原型链
console.log(Person.prototyoe.isPrototypeOf(person))
// EC5 增加了方法可以直接获取 Person.prototype
console.log(Object.getPrototypeOf(person))
// 也可以通过 __proto__ 访问
person.__proto__ === Person.prototype
// 这里有三个角色
构造函数:Person
构造函数的原型:简称 PerPro
实例:person
// 关系
Person.prototype = PerPro;
person.__proto__ = PerPro;
PerPro.constructor = Person;
// 基于上面这种关系 person 在想要调用 name 的属性先要访问 Person ,Person 有该属性则返回,且这个时候 PerPro 上的 name 是没有被覆盖的,如果要访问 age,则需要先访问 Person,发现 Person 没有,则去访问 PerPro,发现有则返回。
// in 方法能检验出属性是来自于构造器还是原型链
// 所以使用 for-in 来遍历会遍历出原型链的方法
// EC5 的 key 和 getOwnPropertyNames 可以达到同样的效果
var keys = Object.getOwnPropertyNames(Person.prototype); // ['name', 'age', 'sayName']
// 检验取出来的值是来自于对象实例还是原型可以通过 hasOwnProperty 来检验