一、JS对象
1.1对象定义的两种方式
- 声明形式
var obj = {
key1: value1,
key2: value2
}
- 构造形式
var obj = new Object();
obj.key1 = value1;
obj.key2 = value2;
主要区别:
声明形式的可以一次性多加键值对,构造形式的话要逐个添加
1.2类型
(1)语言类型
- string
- number
- boolean
- undefined
- object
- null
- symbol (es6新增的)
前五个属于简单基本类型,typeof null
的结果是object
(2)内置对象
- String
- Number
- Boolean
- Object
- Function
- Array
- Error
- Date
- RegExp
1.3对象内容
(1)访问属性
var obj = { a: 1 };
obj.a // 1 属性访问
obj["a"] //1 键访问
注意点:属性名永远都是字符串
var obj = {};
obj[3] = "a";
console.log(obj["3"], obj[3]); // a a
(2)数组访问
var myArray = ["foo", 42, "bar"];
myArray[3] = "aaa";
console.log(myArray.length); // 4
myArray.baz = "baz";
console.log(myArray); // ["foo", 42, "bar", "aaa", baz: "baz"]
console.log(myArray.length); // 4
当我们为一个数组根据下标-值的方式存储时候,长度加一,但是如果是通过键-值方式添加的,长度不会改变,但是我们最好是在对象{ }中添加键值,在数组[ ]中用下标-值的方式添加
(3)对象的复制
方法一:
var newObj = JSON.parse( JSON.stringify( someObj ) );
先将对象字符串化,再转为对象
方法二:
var newObj = Object.assign( {}, myObject );
使用es6的方法
(4)属性描述符
var obj = {};
Object.defineProperty( myObject, "a", {
value: 2,
writable: true,
configurable: true,
enumerable: true
} );
obj.a = 3;
obj.a // 2
- writeable
为false时,表示不可修改,如果在严格模式,则会TypeError
- configurable
为false时,下次对对象进行属性描述时就不能修改为configurable:true
一旦先前改为false就无法改回来,如果一开始writable: true
,后面还是可以改成false的。而且configurable:false
时,不能使用delete删除属性。
- enumerable
为false时,表示我不想让(for ... in)循环遍历出这个属性,但是正常的访问还是可以的
(5)不变性
- 对象常量化
var obj = {};
Object.defineProperty( myObject, "a", {
value: 1,
writable: false,
configurable: false,
enumerable: true
} );
将可修改和可配置的都设置为false,这时候a属性就不会被改变
- 禁止扩展
var obj = { a:1 };
Object.preventExtensions(obj);
obj.b = 3;
obj.b; // undefined
当我们不允许对一个对象添加新属性时,并且还要保留原来的属性,就使用此方法
- 密封
Object.seal()
会创建一个“密封”的对象,这个方法会在现有对象上调用 Object.preventExtensions()
并把所有现有属性标记为configurable:false
。 密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性,但是可以 修改属性的值
- 冻结
我们可以使用Object.freeze()
冻结一个对象,这个效果是在密封的基础上,把所有属性的writable设为false。属于最高级别的不可变性
(6)getter和setter
当我们进行属性访问的时候,比如obj.a,实际上我们在obj上实现了Get操作。回去对象中汇总啊是否有这个属性名的属性,有则返回,没有去原型链中找,再没有就返回undefined。同样地也有Put的方法。
ES5 中可以使用 getter 和 setter 部分改写默认操作,只能在单个属性上。
getter 是一个隐藏函数,会在获取属性值时调用。
setter 也是一个隐藏函数,会在设置属性值时调用。
var obj = {
get a() {
return 1;
}
};
obj.a = 3
console.log(obj.a) // 1 此处返回还是1,因为自动调用了get函数
Object.defineProperty( obj, "b", {
get: function(){
return this.a * 2
},
enumerable: true
});
console.log(obj.a) // 1
console.log(obj.b) // 2
这两种方式都会在obj对象中创建一个不包含值的属性,当我们访问这两个属性时,会自动调用get。加上了setter后:
var obj = {
get a() {
return this._a_;
},
set a(val) {
this._a_ = val * 2;
}
};
obj.a = 2;
console.log(obj.a); // 4
可以看到我们先是赋值为2, 默认会经过set操作,乘了2倍之后才是最后存储的值
(7)判断存在性
var obj = {
a: 1
}
console.log("a" in obj)
obj.hasOwnProperty("a")
①使用in来判断
4 in [2, 4] // false
for(k in [2,4]) {
console.log(k) // 0, 1
}
in会检查对象和原型链,检查某个容器中是否有某个属性名。但是对于数组而言,实际上这个数组的属性名只有0,1,即下标;
②使用hasOwnProperty
这个只会检查是否在对象中。但是有的对象没有连接到Object.prototype
就无法使用第二种。那么可以采用显示绑定的方法:
Object.prototype.hasOwnProperty.call(obj,"a")
③枚举
就像之前提到的那种,使用(for...in) 来查找,还有两种方式:
obj.propertyIsEnumerable("a") // true 仅返回可枚举的
Object.keys(obj) // 返回一个属性数组 ["a"],仅返回可枚举的
但是这些方法如果遇到属性的enumerable:false
就无法找出来了,而且后面两种只查找对象,不会去找原型链。
现在还有一种方法:
Object.getOwnPropertyNames(myObject); //返回属性数组,不管是否可枚举
1.4 遍历方法
最简单粗暴的莫属for循环遍历下标,这个就不解释了
forEach: 遍历所有值,并忽略函数的返回值
every:会一直运行,如果每一项都返回true,结果就是true,一旦有false就结束,结果为false
some: 会一直运行,直到出现返回为true的,如果都没有就返回false
使用for...of
var arr = [1,2,3]
for(var v of arr) {
console.log(v) // 1 2 3
}
- 迭代器对象
var myArray = [ 1, 2, 3 ];
var it = myArray[Symbol.iterator](); it.next(); // { value:1, done:false }
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { done:true }
当遍历完之后done的值才为true