JS代理、深拷贝浅拷贝

93 阅读1分钟

hasOwnProperty

 => Object.prototype.hasOwnProperty() ->所有实例对象都可以访问

           => 作用: 判断属性或方法是不是对象本身自带的

           => 沿原型链上查找的方法不是它自身的

Object.defineProperty

作用: 1. 给对象动态添加属性

       2. 将对象属性绑定到另一个对象上

       3. 数据劫持-监听对象数据变化, 实现数据变化自动更新界面  (vue2.x实现原理应用)

           语法:

               Object.defineProperty(obj,属性,{})

作用1

<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() {
                return obj[key]
            },
             // vm.name = 'rose'
            set(newValue) {
                // 原值与新值相同直接返回
                if (obj[key] == newValue) {
                    return}		
                obj[key] = newValue // 设置属性新值},
             })
          }
</script>

作用2

 let obj = {
            name:'jack',
            age:18
        }
        let vm={}
      // 将obj对象的所有属性动态添加到vm对象上
      //1. 遍历obj对象
        for(let key in obj){
        // 2. 动态给vm添加属性
            Object.defineProperty(vm,key,{
                get(){
                    return obj[key]
                },
                set(newValue){
                // 原值与新值相同直接返回
                    if(obj[key]==newValue){
                        return
                    }
                    obj[key] = newValue
                    // 监听对象数据变化后执行其它操作
                    
                    // 更新界面
                    const titleEle =document.querySelector('.titler')
                    titleEle.innerHTML = obj.name
                }
            })
        }
        console.log(vm.name)
        vm.name = 'rose'
        console.log(vm.age)

数据劫持

 将obj对象的属性能过Object.defineProperty方法绑定到vm对象上,

 转变成getter和setter方法.

 vm对象数据变化,自动更新界面

 vm.message = 'helloworld'

 <div>内容</div>

    <script>

        let obj = {

            message:''

        }

        let vm = {}



        for(const key in obj){

            Object.defineProperty(vm, key, {

                get(){

                    return obj[key]

                },

                set(value){

                    obj[key] = value

                    // 更新div内容

                    document.querySelector('div').innerHTML = value

                }

            })

        }

代理

<script>
        function test1() {
            // 目标对象
            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
    </script>

代理应用

 <!-- 

        通过Proxy代理目标对象obj,实现数据劫持-通过代理对象proxy改变目标对象属性值时,

        在get,set捕获器方法中做一些处理, 比如更新界面

     -->

</head>

<body>

    <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 直接处理

深拷贝和浅拷贝

 拷贝 - 复制对象

          浅拷贝: 只复制一层对象

          深拷贝: 复制得到完全不一样的对象

        实现拷贝
<script>

			function test1() {

				let obj = {

					name: 'jack',

					age: 18,

					fun: {

						swiming: '游泳',

					},

				}

				// let newObj = obj // 不是拷贝

				// newObj.name = 'rose'

				// console.log('obj.name ',obj.name);

			}

			// test1()

			function test2() {

				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);

                console.log('newObj fun :',newObj.fun.swiming,  '  oldObj  fun :',obj.fun.swiming);

                console.dir(newObj);

                console.dir(obj);

			}

            test2()

深拷贝

 JSON对象

               JSON.stringify(obj)

                 obj -> 字符串

                 注: 只能是Object形式对象不是Math,Date...

                 '{name:"jack",age:18,fun:{swiming:"游泳"}}'  <- JSON字符串



               JSON.parse(str)

                 字符串 -> obj

                 注: 字符串必须 是 json格式
<script>

            /*

              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)



            console.dir(obj)







		</script>

递归实现深拷贝

<script>

            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)





		</script>