JavaScript对象
属性描述符
只针对name这个属性,假如对象有其他属性的话则不受影响,如果调用Object.defineProperty()时,如果这三个参数都不指定,那么全部默认为false
let obj = {}
Object.defineProperty(obj, 'name', {
configurable: false, //是否可以配置属性描述符
writable: false, //是否可以改写属性的值
enumerable: false, //控制属性是否会出现在对象的枚举当中(遍历的到不)
value: '属性标识符' //属性的值
})
不变性
有时候需要创建一个变量是不变的,不只是对于简单值,引用值里面的值也不变。也就是说可以用属性描述符,即configurable:false和writable:false去创建一个真正的常量属性。
Object.defineProperty(person, "age", {
configurable: false,
writable: false,
value:2,
});
禁止扩展
如何禁止一个对象再添加新的属性,可以使用Object.preventExtensions(obj)
密封
假如想一个对象即不能添加新属性也不能改变既有属性的值,可以一个一个的给对象属性添加属性描述符,也可以使用Object.seal(obj)去创建一个密封对象,它会自动完成上面的功能。
冻结
Object.freeze(obj)会创建一个冻结对象,这个方法实际上会调用seal。
如果在项目进行优化的时候,有一个数组或者object,并且确信数据不会修改,可以使用冻结让性能大幅提升
JavaScript的getter和setter
【GET】
get,获取的意思,平常对于对象中数据的获取大部分是直接调用,如下
let a = {}
a.name = '9527'
console.log(a.name); //9527
但是在使用.的时侯默认调用了对象的内置get函数去获取对象的值,获取的路径是先在对象中查找是否具有同名的属性,没有的话就会去原型链上查找,如果一直没有则返回undefined
let a = {}
a.__proto__.age = 21
console.log(a.age); //21
console.log(a.name); //undefined
但是当自己在对象中声明了get函数后并且没有声明set函数,则不能再对对象的属性进行修改
let a = {
name: 'sifan',
get name() {
return this.name
},
}
console.log(a.name) //undefined
a.name = 'sifan111'
console.logo(a.name) //undefined
所以当设置了get或set函数后,js就不在关心value和writable属性,而是去监听get、set函数还有configurable与enumerable属性
【Getter】
当我们获取一个对象的属性的时候,就会调用getter函数,但首先要给对象设置getter,否则返回undefined,当给对象定义了getter和setter后,js也会忽略value和writable,而且优先级比get高
let a = {
get name() {
console.log('调用了自己的方法get');
return this._name
},
set name(val) {
console.log('调用自己的方法set');
this._name = val
}
}
Object.defineProperty(a,'name',{
get: function() {
console.log('调用getter函数');
return this._name + 'getter'
}
})
console.log(a.name) //undefinedgetter
a.name = '11
console.log(a.name) //11getter
【setter】
当需要修改一个属性的值的时候,会触发set函数,并且传入一个参数val就是想要赋予的值
【vue】
在Vue2中,Object.defineProperty是vue的响应式和双向绑定的主要实现底层,在set中监听属性的改变,并调用notify()函数去通知使用到这个函数的节点的值更新为最新的值,如下部分代码:
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
if (Dep.target) {
dep.addSub(Dep.target);
}
return val;
},
set(newValue) {
if (val === newValue) {
return;
}
// 数据发生变化 dep通知wather更新
val = newValue;
dep.notify();
},
});
undefined类型的值和找不到值返回的undefined的区别
可以判断这个属性是否存在对象或者原型链上
使用in操作符
in操作符可以检查属性是否存在于对象及其对象的原型链之中
const obj = {
a: undefined,
};
obj.__proto__.c=undefined
console.log(obj.a);//undefined
console.log(obj.b);//undefined
console.log("a" in obj);//true
console.log("b" in obj);//false
console.log("c" in obj);//true
但是in操作符不能判断一个值是否在数组中,因为in操作符检测的式容器内的某个属性名,对于数组来说包含的属性名是下标
let arr = ['a', 'b', 'c']
console.log('a' in arr); //false
console.log(1 in arr); //true
使用hasOwnProperty()
与in操作符不同的是,hasOwnProperty()是不会检测原型链,也就是只查找自己本身的属性,而且也是检测属性名
const obj = {
a: undefined,
};
obj.__proto__.c=5
console.log(obj.hasOwnProperty("a"));//true
console.log(obj.hasOwnProperty("b"));//false
console.log(obj.hasOwnProperty("c"));//false
let arr = ['a', 'b', 'c']
console.log(arr.hasOwnProperty('a')); //false
console.log(arr.hasOwnProperty(1)); //true
遍历
for...in可以遍历对象属性列表,注意:即可以遍历数组,也可以遍历对象
const array = [1, 2, 3, 4];
for (let i in array) {
console.log(i, array[i]);
}
// 0 1
// 1 2
// 2 3
// 3 4
for...of可以遍历数组值列表,注意:只能遍历数组,不能遍历对象
const array = [1, 2, 3, 4];
for (let index of array) {
console.log(index);
}
// 1
// 2
// 3
// 4
辅助迭代器
ES5中的一些数组的辅助迭代器:
forEach
const array = [1, 2, 3, 4]
array.forEach((item) => {
console.log(item); //1,2,3,4
});
some
array.some((item) => {
console.log(item); //1,2,3,4
return false
});
every
array.every((item) => {
console.log(item); //1,2,3,4
return true
});
some和every的区别:some是当返回值有一个是返回true就结束遍历,every是当返回值有一个是false的时候结束遍历
forEach没有返回值
手动遍历
使用es6的symbol类型,Symbol.iterator可以获取对象的内部属性,然后可以带有next()方法,返回的是一个{value, done},value是值,done是当前是否到了底部
const array = [1, 2, 3, 4];
const it = array[Symbol.iterator]();
console.log(it.next());// {value: 1, done: false}
console.log(it.next());// {value: 2, done: false}
console.log(it.next());// {value: 3, done: false}
console.log(it.next());// {value: 4, done: false}
console.log(it.next());// {value: undefined, done: true}
行百里者半九十