本文目录:
- JS中的所有内置对象
- 创建对象的方法
- 深拷贝和浅拷贝(通用方法参考之前的文章,特列方法重新总结下)
- 属性描述符
- 不变性
- Getter和Setter
- 存在性
- 遍历
正文
JS中的所有内置对象(内置构造函数)
- String
- Number
- Array
- Object
- Function
- Date
- Boolean
- Error
- RegeXp
创建对象的方法
创建对象的方法我们这里只谈那些实践中可以用的,有缺陷的其实就是下面方法的不完整版
- 字面量的形式:
let obj = {
name: 'obj'
}
- 构造函数的形式
function Class1() {
this.name = 'Class1'
}
let obj = new Class1();
无论像网上其他教程说的那样比如通过new Object或者什么原型模式都是基于构造函数的补充,其本质还是基于构造函数的形式。
function Class1() {
this.name = 'Class1'
}
let obj = new Class1();
- 通过Object.create()
let obj = {
name: 'obj'
}
let obj2 = Object.create(obj, {
age: {
value: 12,
writable: true,
configurable: true,
enumerable: true
}
})
console.log(obj)
console.log(obj2, obj2.name)
// Object.create()方法创建一个新对象,使用现有的对象(第一个参数)来提供新创建的对象的__proto__。
// Object.create的第二个参数就相当于Object.defineProperty的后面2个参数的集合
- 二种方式的联系
var obj = {}
Object.create(Object.prototype)
/*--------------分割线---------------*/
function Class1() {
}
var obj = new Class1();
Object.create(Class1.prototype)
//以上2种方式两两等价
深拷贝和浅拷贝
属性描述符
从ES5开始所有属性都具有了属性描述符,可以通过Object.getOwnPropertyDescriptors获取,通过Object.defineProperty设置
let obj = {
name: 'obj'
}
Object.defineProperty(obj, 'age', {
value: 123,
writable: true,
configurable: false,
enumerable: true
})
console.log(Object.getOwnPropertyDescriptor(obj, 'name'))//获取单个属性的属性描述符用这个方法
/*
{
value: 123,//属性的值
writable: true,//该属性是否可写,
configurable: false,.//该属性的属性描述符是否可配置,只影响configurable和enumerable
enumerable: true//该属性是否可枚举,可以参考下面的可枚举性
}
*/
console.log(Object.getOwnPropertyDescriptors(obj))
/*
{
age: {
value: 123,
writable: true,
configurable: false,
enumerable: true
}
name: {
value: 123,
writable: true,
configurable: false,
enumerable: true
}
}
*/
不变性
如果想声明一个对象常量可以通过将writable和configurable置为false即可。
- 禁止扩展
let obj = {
}
Object.defineProperty(obj, 'age', {
value: 123,
writable: true,
configurable: false,
enumerable: true
})
Object.preventExtensions(obj)//阻止对象添加新的属性,在严格模式下会报错
obj.b = 321
console.log(obj)//{ age: 123 }
-
密封
无法添加属性,所有属性无法删除,所有属性无法配置,所有属性可以修改值
let obj = {
name: 'obj'
}
Object.defineProperty(obj, 'age', {
value: 123,
writable: true,
configurable: false,
enumerable: true
})
Object.seal(obj)
obj.c = 321//无法添加属性
delete obj.name//无法删除属性
Object.defineProperty(obj, 'age', {
enumerable: false
})//无法配置属性,直接报错
console.log(obj)//{ age: 123 }
console.log(Object.getOwnPropertyDescriptors(obj))
-
冻结
在密封的基础上增加不可修改值
let obj = {
name: 'obj'
}
Object.defineProperty(obj, 'age', {
value: 123,
writable: true,
configurable: false,
enumerable: true
})
Object.freeze(obj)
obj.c = 321//无法添加属性
delete obj.name//无法删除属性
// Object.defineProperty(obj, 'age', {
// enumerable: false
// })//无法配置属性,直接报错
obj.name = 666;//无法修改值
console.log(obj)//{ age: 123 }
console.log(Object.getOwnPropertyDescriptors(obj))
- 深度冻结
很少用到,可以递归遍历然后通过Objecrt.freeze来是实现。
Getter和Setter
读取一个对象的是实现了JS默认的[[Get]]操作(也就是ES5的Getter)而设置一个对象的属性是实现了默认的[[Put]](也就是ES5的Setter)操作。当然,在ES5之后你可以重写JS内置的Getter和Setter方法。
默认的[[Get]]操作会进行如下操作:
- 首先会查找是否具有相同的名称的属性,如果找到的话则返回值。
- 如果找不到的话则往原型链上找,如果找到的话则返回值。
- 如果无论如何都找不到的话则返回undefined(注意区分和变量的区别,在词法作用域中如果不存在某变量,则会报错)。
默认的[[Put]]操作:
该对象自身属性存在的情况:
- 会先判断该属性是否是访问描述符(访问器属性),如果是则判断是否有Setter,如果有则调用Setter,没有则调用默认的setter。
- 如果不是访问描述符,则判断该属性的writeable是否为true,是则赋值,否则在严格模式下啥都不做,在严格模式下报错。
该对象自身属性不存在的情况:
- 简单的说只要原型链上的数据能“改”(包括setter和writable为true的情况),那么就会在自身添加属性,并且会发生属性屏蔽;否则,则啥都不做,严格模式下回报错。
存在性
- 检查自身某个属性是否存在用
Object.hasOwnProperty - 检查自身及其原型链上的某个属性是否存在用
in
例子:
let objx = {}
let objy = {a: 12}
objx.__proto__ = objy;
console.log(Object.prototype.hasOwnProperty.call(objx, a))//false
console.log('a' in objx)//true
- 检查可枚举属性的方法:
1. Object.keys(obj); //返回obj自身所有可以枚举的属性名组成的数组。
2. propertyIsEnumerable; //检查某个具体属性是否可枚举
- 检查所有属性的方法:
1. for.. in
2. getOwnPropertyNames//返回索引名组成的数组
3. every
4. some
5. for ... of //直接返回值
遍历
一个对象可以遍历的的原理是该对象中存在一个【Symbol.iterator】属性,该对象是一个函数,该函数返回一个对象,该对象里面有个名为next的函数,next函数返回一个对象,包含2个属性,一个是value,一个是done.下面是自己实现一个对象的迭代器的例子。
var obj = {
a: 11,
b: 22,
'3': 33
}
Object.defineProperties(obj, {
[Symbol.iterator]: {
writable: false,
enumerable: false,
configurable: true,
value: function() {
let o = this;
let index = 0;
let indexArr = Object.keys(o)
return {
next: function() {
return{
value: o[indexArr[index++]],
done: (index > indexArr.length)
}
}
}
}
}
})
for (let i of obj) {
console.log(i)
}//本来for in 不能作用于普通对象,但是添加了迭代器了就可以了
网友评论