hasOwnProperty
语法
Object.prototype.hasOwnProperty() ->所有实例对象都可以访问
作用
判断属性或方法是不是对象本身自带的,沿原型链上查找的方法不是它自身的
let obj = {
name: 'jack',
age: 18,
}
Object.prototype.score = 100 //原型链上的
// 判断属性age是否是对象obj的
// let isOk = obj.hasOwnProperty('name')
console.log('obj.score ',obj.score)
let isOk = obj.hasOwnProperty('score')
console.log('isOk ', isOk) //false
let arr = []
console.dir(arr)
console.dir(Array.prototype);
console.log(arr.hasOwnProperty('length') ) //true
console.log(arr.hasOwnProperty('find') ) //false
defineProperty
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
语法
Object.defineProperty(obj, prop, descriptor)
Object.defineProperty(obj,属性,{})
参数
- obj : 要定义属性的对象。
- prop:要定义或修改的属性的名称或 Symbol 。
- descriptor:要定义或修改的属性描述符对象。
descriptor 属性描述符对象
数据属性
- value:包含这个属性的数据值。默认值为undefined。
- configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false。
- enumerable:表示能否通过for in循环访问属性,默认值为false
- writable:表示能否修改属性的值。默认值为false。
let obj = {}
Object.defineProperty(obj, 'name', {
value: 'jack',
configurable: true, // 允许删除属性
writable: true, //允许修改属性值
enumerable: true, // 遍历对象for-in
})
// obj = {name:'jack'}
console.log(obj.name) //jack
// delete obj.name // 删除对象属性
// obj.name = 'rose' // 修改对象属性值
console.log(obj.name)
访问器属性
- get:在读取属性时调用的函数,默认值是undefined
- set:在写入属性的时候调用的函数,默认值是undefined
let obj = {}
Object.defineProperty(obj,'age',{
// 访问对象age属性时自动调用 obj.age
get:function(){
console.log('get >>>> ')
return 20 // get >>>> 20
},
// 赋值给对象属性age时自动调用并赋值
set(newValue){
// 等同于this.age = newValue
console.log('set >>>> ')
}
})
console.log('111',obj.age) //111,20
obj.age = 18 // set >>>>
console.log('222',obj.age) //222,18
作用
给对象动态添加属性
将对象属性绑定到另一个对象上
let obj = {
name: 'jack',
age: 18,
}
let vm = {}
// 将obj对象的所有属性动态添加到vm对象上
//1. 遍历obj对象
for (const key in obj) {
// 2. 动态给vm添加属性
Object.defineProperty(vm, key, {
// vm.name
get() {
return obj[key]
},
// vm.name = 'rose'
set(newValue) {
// 原值与新值相同直接返回
if (obj[key] == newValue) {
return
}
obj[key] = newValue // 设置属性新值
},
})
}
数据劫持-监听对象数据变化, 实现数据变化自动更新界面 (vue2.x实现原理应用)
<div>
<p class="title">jack</p>
</div>
<script>
let obj = {
name: 'jack',
age: 18,
}
let vm = {}
// 将obj对象的所有属性动态添加到vm对象上
//1. 遍历obj对象
for (const key in obj) {
// 2. 动态给vm添加属性
Object.defineProperty(vm, key, {
// vm.name
get() {
console.log('get >>>> ')
return obj[key]
},
// vm.name = 'rose'
set(newValue) {
// 原值与新值相同直接返回
if (obj[key] == newValue) {
return
}
obj[key] = newValue // 设置属性新值
console.log('set >>>> ')
// 监听对象数据变化后执行其它操作
// 更新界面
const titleEle = document.querySelector('.title')
titleEle.innerHTML = obj.name
},
})
}
Proxy代理
代理是目标对象的抽象。目标对象既可以直接被操作,也可以通过代理来操作。通过代理对象操作目标对象和直接操作目标对象是一样的效果。
let proxy = new Proxy(obj, handler) 目标对象和处理程序对象
// 目标对象
let obj = {
name: 'jack',
age: 18,
}
// 处理程序
let handler = {}
// 代理对象
let proxyObj = new Proxy(obj, handler)
// 通过代理对象操作目标对象和直接操作目标对象是一样的效果,
console.log('obj.name ', obj.name)
console.log('proxyObj.name ', proxyObj.name)
proxyObj.name = 'rose' // 通过代理对象更改目标对象属性值
console.log('obj.name ', obj.name)
通过代理对象操作目标对象时,可以对目标对象做一些拦截操作
// 通过代理对象操作目标对象时,可以对目标对象做一些拦截操作, 在处理程序handler中设置
// 目标对象
let obj = {
name: 'jack',
age: 18,
}
// 处理程序
let handler = {
// 通过代理对象获取目标对象属性值时触发
// get(){
// return '这是代理给的新值'
// }
// get参数
get(target,propery,receiver){ //目标对象,属性,代理对象
console.log('target ',target)
console.log('propery ',propery)
console.log('receiver ',receiver)
return target[propery]
},
// 通过代理对象给属性设置值触发
set(target,propery,value,receiver){ //目标对象,属性,新值,代理对象
console.log('set >>>');
console.log('target ',target)
console.log('propery ',propery)
console.log('value ',value)
console.log('receiver ',receiver)
target[propery] = value
}
}
// 代理对象
let proxyObj = new Proxy(obj, handler)
// console.log( proxyObj.age )
proxyObj.age = 20
代理Proxy应用
通过Proxy代理目标对象obj,实现数据劫持-通过代理对象proxy改变目标对象属性值时,
在get,set捕获器方法中做一些处理, 比如更新界面
<div></div>
<script>
let obj = {
message:''
}
let proxyObj = new Proxy(obj,{
get(target,propery){
return target[propery]
},
set(target,propery,value){
target[propery] = value // 通过代理对象改变目标对象属性值
// 更新界面操作-更改div内容
document.querySelector('div').innerHTML = value
}
})
proxyObj.message = 'hello'
</script>
代理Proxy与Object.definePropery区别
Object.definePropery 处理数组要特殊处理,而代理Proxy直接处理
<div></div>
<script>
let obj = {
name:'jack',
age:18,
score:98,
fun:{
num:10,
},
arr:[10,20,30]
}
// let proxyObj = {}
// for(const key in obj){
// Object.defineProperty(proxyObj,key,{
// get(){
// return obj[key]
// },
// set(value){
// obj[key] = value
// document.querySelector('div').innerHTML = value
// }
// })
// }
// =============================
let proxyObj = new Proxy(obj,{
get(target,propery){
return target[propery]
},
set(target,propery,value){
target[propery] = value
document.querySelector('div').innerHTML = value
}
})
</script>
todolist用代理对象实现
<div class="container">
<input type="text" placeholder="请输入内容" /><button>确定</button>
<ul></ul>
</div>
<script>
// 目标对象
var arr = ['html', 'css'] // 数据
// 代理对象
let proxyArr = new Proxy(arr,{
get(target,propery){
return target[propery]
},
set(target,propery,value){
target[propery] = value
// 代理对象数组数据变化,自动刷新界面
showList()
return true
}
})
/*
数据操作-实现显示列表
遍历数组,拼接字符串,将字符串作用内容设置给显示元素
点击确定按钮,获取输入框内容,添加数组
*/
function showList() {
var liArr = proxyArr.map(function (item, index) {
return `<li data-index="${index}">${item}</li>`
})
var liStr = liArr.join('')
var ulEle = document.querySelector('ul')
ulEle.innerHTML = liStr
}
// 删除元素
function onDelete() {
// 删除事件操作委托给ul上级元素处理
var ulEle = document.querySelector('ul')
ulEle.addEventListener('click', function (e) {
e = e || window.event
var target = e.target || e.srcElement // 事件目标对象
var index = target.dataset.index
proxyArr.splice(index, 1)
})
}
//添加元素
function bindAdd() {
var btn = document.querySelector('button')
btn.onclick = function () {
var inputEle = document.querySelector('input')
var inputValue = inputEle.value
proxyArr.push(inputValue)
inputEle.value = '' // 清空输入框
}
}
showList() // 初始化执行
onDelete() // 初始化执行
bindAdd() // 初始化绑定添加事件
</script>
深拷贝与浅拷贝
浅拷贝: 只复制一层对象,如果对象属性值是对象则不能复制
深拷贝: 复制得到完全不一样的对象
实现方式
Object.assign(obj)或展开运算符{…obj}[浅拷贝]
只能拷贝一层,如果属性值是对象,无法拷贝
let obj = {
name: 'jack',
age: 18,
fun: {
swiming: '游泳',
},
}
// {...obj} [...arr]
// let newObj = { ...obj } // 浅拷贝,如果属性值是对象不能拷贝
let newObj = Object.assign(obj)
newObj.name = 'rose'
newObj.fun.swiming = '打游戏'
console.log('newObj :',newObj.name, ' oldObj :',obj.name); //rose jack
console.log('newObj fun :',newObj.fun.swiming,'oldObj fun:',obj.fun.swiming); //打游戏 打游戏 fun对象没有被拷贝出来,是同一个地址
console.dir(newObj);
console.dir(obj);
JSON.parse(JSON.stringify(obj)) [深拷贝]
数据类型是Function或数据值为undefined无法拷贝,解决方法:递归
JSON对象 JSON.stringify(obj)[深拷贝]
obj -> 字符串
注: 只能是Object形式对象不是Math,Date...
'{name:"jack",age:18,fun:{swiming:"游泳"}}' <- JSON字符串
JSON对象 JSON.parse(str)[深拷贝]
字符串 -> obj
注: 字符串必须 是 json格式
/*
JSON对象
*/
function test1() {
let objStr = JSON.stringify(obj)
console.log(obj)
console.log(objStr, typeof objStr)
let str = '{"num":1001,"score":98}'
let obj1 = JSON.parse(str)
console.log(obj1)
console.log(obj1.num)
}
let obj = {
name: 'jack',
age: 18,
fun: {
swiming: '游泳',
},
say:function(){
console.log('说话');
},
score:undefined
}
// 利用JSON实现深拷贝
// let str = JSON.stringify(obj) //obj->str
// let newObj = JSON.parse(str) // str->obj
let newObj = JSON.parse(JSON.stringify(obj))
newObj.name = 'rose'
newObj.age = 20
newObj.fun.swiming = '玩游戏'
console.dir(newObj) // rose 20 玩游戏
console.dir(obj) //jack 18 游泳 深拷贝不影响之前的
递归 cloneDeep()
function cloneObj(obj){
let newObj = Array.isArray(obj)? []:{} // 存储拷贝的原对象属性方法
for(const key in obj){
if(obj[key] && typeof obj[key] === 'object'){
newObj[key] = cloneObj(obj[key])
}else{
newObj[key] = obj[key]
}
}
return newObj
}
let obj = {
name: 'jack',
age: 18,
fun: {
swiming: '游泳',
},
say: function () {
console.log('说话')
},
score: undefined,
}
let newObj = cloneObj(obj)
newObj.name = 'rose'
newObj.age = 20
newObj.score = 98
newObj.fun.swiming = '玩游戏'
console.dir(newObj)
console.dir(obj)