JavaScript入门 js高级Object对象hasOwnProperty/defineProperty/Proxy代理/深拷贝与浅拷贝 Day20

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)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值