javaScript 基础知识汇总 (十二)
1、属性的标志和描述符
属性的标志
对象属性除value外还有三个特殊属性,即标志
writable ----如果为true,则可以修改,否则它只是只读的。
enumerable ----如果为true,则可在循环中列出,否则不列出。
configurable -----如果为true,则此属性可以被删除,相应的特性也可以被修改,否则不可以
得到这些标志的语法:
let descriptor = Object.getOwnPropertyDescriptor(obj,propertyName);
obj 需要获取信息的对象
propertyName 属性的名称
let user = {
name : "Jhon"
};
let descriptor = Object.getOwnPropertyDescriptor(user,'name');
alert(JSON.stringify(descriptor,null,2));
/* property descriptor:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
标志修改语法:Object.defineProperty(obj,propertyName,descriptor)
1 let user = {}; 2 3 Object.defineProperty(user, "name", { 4 value: "John" 5 }); 6 7 let descriptor = Object.getOwnPropertyDescriptor(user, 'name'); 8 9 alert( JSON.stringify(descriptor, null, 2 ) ); 10 /* 11 { 12 "value": "John", 13 "writable": false, 14 "enumerable": false, 15 "configurable": false 16 } 17 */
设置属性只读
let user = {
name : "Jhon"
};
Object.defineProperty(user,"name",{
writable:false
});
user.name = "XiaoMing";//错误,不能设置只读属性‘name’;
不可枚举
通过设置 enumerable 标志可以设置属性是否可以枚举
1 let user = { 2 name: "John", 3 toString() { 4 return this.name; 5 } 6 }; 7 8 // 默认情况下,我们的两个属性都会列出: 9 for (let key in user) alert(key); // name, toString 10 11 12 Object.defineProperty(user, "toString", { 13 enumerable: false 14 }); 15 16 // 现在 toString 消失了: 17 for (let key in user) alert(key); // name
不可配置
通过设置configurable 标志,来控制属性是否可以修改
1 let user = { }; 2 3 Object.defineProperty(user, "name", { 4 value: "John", 5 writable: false, 6 configurable: false 7 }); 8 9 // 不能修改 user.name 或 它的标志 10 // 下面的所有操作都不起作用: 11 // user.name = "Pete" 12 // delete user.name 13 // defineProperty(user, "name", ...) 14 Object.defineProperty(user, "name", {writable: true}); // 错误
Object.defineProperties
一次定义多个属性,语法和示例如下:
1 Object.defineProperties(obj, { 2 prop1: descriptor1, 3 prop2: descriptor2 4 // ... 5 }); 6 Object.defineProperties(user, { 7 name: { value: "John", writable: false }, 8 surname: { value: "Smith", writable: false }, 9 // ... 10 });
Object.getOwnPropertyDescriptors(obj)
一次获取所有属性描述
语法:let
clone =
Object.
defineProperties
(
{
}
,
Object.
getOwnPropertyDescriptors
(
obj)
)
;
2、属性的getter 和 setter
getter 和 setter
1 2 let obj = { 3 get propName() { 4 // getter, the code executed on getting obj.propName 5 }, 6 7 set propName(value) { 8 // setter, the code executed on setting obj.propName = value 9 } 10 };
访问器描述符
get
—— 一个没有参数的函数,在读取属性时工作,set
—— 带有一个参数的函数,当属性被设置时调用,enumerable
—— 与数据属性相同,configurable
—— 与数据属性相同。
兼容性
1 function User(name, birthday) { 2 this.name = name; 3 this.birthday = birthday; 4 5 // age 是由当前日期和生日计算出来的 6 Object.defineProperty(this, "age", { 7 get() { 8 let todayYear = new Date().getFullYear(); 9 return todayYear - this.birthday.getFullYear(); 10 } 11 }); 12 } 13 14 let john = new User("John", new Date(1992, 6, 1)); 15 16 alert( john.birthday ); // birthday 是可访问的 17 alert( john.age ); // ...age 也是可访问的
这个例子主要解决了,当存储表示一个可以互相转换的值。
3、原型继承
Prototype
Prototype 是内部隐藏的,但是可以通过_proto_设置
let animal = {
eats:true
};
let rabbit = {
jumps:true
};
rabbit._proto_=animal;
alert(rabbit.eats);
alert(rabbit.jumps);
4、函数原型
F.prototype
属性与[[Prototype]]
不同。F.prototype
唯一的作用是:当new F()
被调用时,它设置新对象的[[Prototype]]
。F.prototype
的值应该是一个对象或 null:其他值将不起作用。"prototype"
属性在设置为构造函数时仅具有这种特殊效果,并且用new
调用。1 let animal = { 2 eats: true 3 }; 4 5 function Rabbit(name) { 6 this.name = name; 7 } 8 9 Rabbit.prototype = animal; 10 11 let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal 12 13 alert( rabbit.eats ); // true
5、原生的原型
- 所有的内置对象都遵循一样的模式:
- 方法都存储在原型对象上(
Array.prototype
、Object.prototype
、Date.prototype
等)。 - 对象本身只存储数据(数组元素、对象属性、日期)。
- 方法都存储在原型对象上(
- 基本数据类型同样在包装对象的原型上存储方法:
Number.prototype
、String.prototype
和Boolean.prototype
。只有undefined
和null
没有包装对象。 - 内置对象的原型可以被修改或者被新的方法填充。但是这样做是不被推荐的。只有当添加一个还没有被 JavaScript 引擎支持的新方法的时候才可能允许这样做。
6、原型方法
- Object.create(proto[, descriptors]) —— 利用给定的
proto
作为[[Prototype]]
来创建一个空对象。 - Object.getPrototypeOf(obj) —— 返回
obj
的[[Prototype]]
(和__proto__
getter 相同)。 - Object.setPrototypeOf(obj, proto) —— 将
obj
的[[Prototype]]
设置为proto
(和__proto__
setter 相同)。 - Object.keys(obj) / Object.values(obj) / Object.entries(obj) —— 返回包含自身属性的名称/值/键值对的数组。
- Object.getOwnPropertySymbols(obj) —— 返回包含所有自身 symbol 属性名称的数组。
- Object.getOwnPropertyNames(obj) —— 返回包含所有自身字符串属性名称的数组。
- Reflect.ownKeys(obj) —— 返回包含所有自身属性名称的数组。
- obj.hasOwnProperty(key):如果
obj
拥有名为key
的自身属性(非继承得来),返回true
。
同时我们还明确了 __proto__
是 [[Prototype]]
的 getter/setter,位置在 Object.prototype
,和其他方法相同。
我们可以不借助 prototype 创建一个对象,那就是 Object.create(null)
。这些对象被用作是「纯字典」,对于它们而言 "__proto__"
作为键没有问题。
所有返回对象属性的方法(如 Object.keys
以及其他)—— 都返回「自身」属性。如果我们想继承它们,我们可以使用 for...in
。