数据劫持
对象
- 我们数据类型的一种
- 以键值对的形式存储数据
- 因为 __proto__和原型链 可以访问自己没有的属性
for in 循环
- 专门遍历对象
- 遍历对象身上的所有属性
- 遍历对象身上所有的 可枚举 的属性(包括原型链上的所有 可枚举 属性)
- 一种是自定义属性
- 我们可以设置为可枚举属性
对象自己的方法
- hasOwnProperty()
查看是不是自己的属性(是自己的属性还是原型链的属性)
语法:对象.hasOwnProperty(‘你要检测的属性名’)
function Person() {
this.name = 'Jack'
this.age = 18
this.gender = '男'
}
Person.prototype.sayHi = function() {
console.log('sayHi')
}
let p1 = new Person()
for (let k in p1) {
console.log("a")
}
console.log(p1.hasOwnProperty('name')) // true
console.log(p1.hasOwnProperty('sayHi')) // false
- defineProperty()
数据劫持
一种给对象添加属性的方法
我可以给一个我设置的属性设置各种各样的行为状态(比如:可枚举、可删除)
语法:Object.defineProperty(给哪一个对象添加, ‘key’ .{ 添加的设置 })
<input type="text" id="username">
<input type="text" id="txt">
// 数据劫持
let obj = {
name: 'Jack'
}
let fg = {
o: '男',
e: '男女'
}
// 普通添加
obj.age = 18
// 数据劫持
Object.defineProperty(obj, 'username', {
// value: '男',
enumerable: true, // 默认是不可枚举,设置成true就可以枚举了
get () {
return fg.e + fg.o
},
// 当你想修改劫持的数据的时候
// 就会触发这个 set 函数
// 接收一个形参,就是你想修改的值
set(val) {
// 通过在 set 里面修改 prop 对象
// 来达到修改 username 属性
let a = val.slice(0, 2)
let b = val.slice(2)
fg.e = a
fg.o = b
console.log(val)
let ipt = document.querySelector("#username")
ipt.value = fg.o + fg.e
}
})
let ipt = document.querySelector("#txt")
ipt.addEventListener('input', () => {
obj.username = ipt.value
})
configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false。
enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
默认为 false。
数据描述符还具有以下可选键值:
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
默认为 undefined。
writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。
默认为 false。
存取描述符还具有以下可选键值:
get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
默认为 undefined。
set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
默认为 undefined。
enumerable为false时
Object.keys(obj)拿不到defineProperty()创建的值
Object.getOwnPropertyNames(obj)可以拿到
但是这两个都拿不到原型上创建的东西