【JS】Day21

学习内容

  • 对象的方法
  • proxy
  • hasOwnProperty
  • 浅拷贝与深拷贝

对象的方法

/*
对象详解
Object.defineProperty(目标对象,属性,属性描述符)

1. Object.defineProperty(obj, prop, descriptor)
  给目标对象设置或添加属性,并返回此对象
  obj: 要定义属性的对象。
  prop: 要定义或修改的属性的名称。
  descriptor: 要定义或修改的属性描述符。

2. 属性描述符
  数据描述符: 一个具有值的属性,该值可以是可写的,也可以是不可写的。
  存取描述符: 由 getter 函数和 setter 函数所描述的属性

3. 数据描述符
  configurable: 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false。
  enumerable: 表示能否通过for in循环访问属性,默认值为false。
  writable: 表示能否修改属性的值。默认值为false。
  value: 包含这个属性的数据值。默认值为undefined。

4. 存取描述符
  get: getter在读取属性时调用的函数,默认值是undefined。
  set: setter在写入属性的时候调用的函数,默认值是undefined。
  注: setter 不能和 writable、value 一起使用。

5. 定义多个属性
*/

//声明一个对象
let obj = {
    name: '张三'
};
//设置obj对象中的name属性的描述
Object.defineProperty(obj,'name',{
    configurable: false, //默认为false,禁止删除指定属性的描述符
    enumerable: false, //默认false,禁止通过for in 遍历当前对象
    writable: false, //默认false,禁止修改当前对象的指定属性
})

//删除对象中的属性
//delete : 删除对象中指定的属性
// delete obj.name;
// console.log(obj);

//遍历对象
// for(let key in obj){
//     //         属性   属性值
//     console.log(key,obj[key]);
// }

//修改obj对象中的name属性
// obj.name = '李四';
// console.log(obj);

//给obj对象添加一个新的属性
Object.defineProperty(obj,'age',{
    value: 18
})
console.log(obj);

// let obj = {};
// obj.name = '张三'; //实际上是调用了方法中的setter方法
// console.log(obj.name); //实际是调用了方法中的getter方法

//数据劫持
//从原对象中劫持一份数据出来
let obj = {  //原始对象
    name: '张三',
    age: 18,
    sex: '男'
}

let object = {}; //新对象
Object.defineProperties(object,{
    name: {
        get(){  //读取
            return obj.name;
        }
    },
    age: {
        // writable: false, //禁止修改
        // value : 30,
        get(){  //获取属性权限
            return obj.age;
        },
        set(v){  //设置属性的权限
            obj.age = v;
        }
    },
    sex: {
        get(){
            return obj.sex;
        }
    }
})
//获取原始对象的数据
console.log(obj,object);
//设置原始对象中的age属性
object.age = 20;
console.log(obj,object);

proxy

/*
1. 概念:
Proxy: ES6提供的数据代理,表示由它来“代理”某些操作,可以称为“代理器"

2. 语法:
new Proxy(代理原始对象,{配置项}): 返回的实例对象,就是代理结果数据
  new Proxy()表示生成一个Proxy实例
  代理原始对象: 要被代理的对象,可以是一个object或者function。
  配置项: 也是一个对象,对该代理对象的各种操作行为处理。
  Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
*/

//声明一个对象(原始对象-明星)
let obj = {
    name: '张三',
    age : 18,
    sex: '男'
}
// 找一个代理方(经济人)
let object = new Proxy(obj,{
    //获取原始对象中的数据
    get(target,property){
        //target : 代理的目标对象-obj
        //property: 代理的目标对象-obj的属性
        return target[property];  //自动遍历出目标对象中的所有的属性
    },
    //设置原始对象中的数据
    set(target,property,value){
        //target: 代理的目标对象-obj
        //property: 代理的目标对象的属性
        //value: 代理的目标对象的属性值
        target[property] = value;
        //注意:如果是简单修改,必须添加一个返回值为true
        return true;
    }
})
console.log(object);
object.age = 20;
console.log(obj,object);

hasOwnProperty

//hasOwnProperty: 表示是否有自己的属性。这个方法会查找一个对象是否有某个属性,但是不会去查找它的原型链。

//声明一个对象
let obj = {
    a : 1,
    b : {
        c: 2
    },
    e : function(){}
}
//检测 a b c e 这些属性是否属于obj这个对象
console.log(obj.hasOwnProperty('a')); //true
console.log(obj.hasOwnProperty('b')); //true
console.log(obj.hasOwnProperty('c'));  //false
console.log(obj.hasOwnProperty('e'));  //true
console.log(obj.b.hasOwnProperty('c')); //true

//继承过来的属性
// toString()  
console.log([].hasOwnProperty('toString')); //false
console.log(new Object().hasOwnProperty('toString')); //false (toString是Object原型对象的方法,不是实例方法)
console.log('toString' in Object);  //true (in: 无论这个属性是实例属性还是原型属性,它都属于这个对象的属性,所以返回true);
console.log(new Object().__proto__.hasOwnProperty('toString'));

/*
    hasOwnProperty :
    1. 如果是普通对象,则只检测当前对象中的实例属性是否存在
    2. 如果是原型对象,则只检测当前原型对象中原型属性是否存在
    in:
    无论属性是实例属性还是原型属性,只要是当前对象的属性,都返回true
*/

let object = {
    a : 1,
    b : {
        c : 2,
        d : {
            e : 3
        }
    }
}
//添加原型属性
object.__proto__.x = 4;
object.__proto__.y = 5;
//检测object对象中有哪些属性
//遍历当前对象
for(let key in object){
    //key : 就代表当前对象中的属性名
    //检测当前属性是否属于object对象
    if(object.hasOwnProperty(key)){
        console.log(key,object[key]); //输出属性名与属性值
    }
    alert(key);
}

浅拷贝与深拷贝

//深浅拷贝: 针对引用类型而言,浅拷贝指的是复制对象的引用,即直接给引用类型赋值,如果拷贝后的对象发生变化,原对象也会发生变化。而深拷贝是真正地对对象进行拷贝,修改拷贝后的新对象并不会对原对象产生任何影响。

//数据类型
//基本数据类型: Number/String/Boolean/null/undefined/Symbol。
//复合数据类型: Object。

//值传递: 基本数据类型的值属于值传递,传递的是栈空间中的值。
//引用传递: 复合数据类型属于引用传递,传递的是栈空间中的地址(堆地址)。

//复合数据类型才涉及到浅拷贝与深拷贝的问题。

//声明一个变量
//let a = 3;
//再声明一个变量
//let b = a;
//修改a中的值
//a = 4;
//console.log(a,b); //4  3

//声明一个对象
//let obj = {
//    a : 1,
//    b : {
//        c : 2,
//        d : {
//            e : 3
//        }
//    }
//}

//拷贝对象
//浅拷贝
//let object = obj; //将obj对象的引用地址拷贝给了object,所以这个是浅拷贝
//浅拷贝的特点:
//1. 拷贝的是对象的引用地址
//2. 当我修改一个对象中的属性时,两个对象中的属性会同时改变。
//obj.a = 10;
//console.log(obj,object);

//浅拷贝
//创建一个新对象
//let newObj = {... obj};
//修改obj对象中的a属性
//obj.a = 100;
//修改obj对象中的b对象中c属性的值
//obj.b.c = 200;
//console.log(obj,newObj);

//浅拷贝
//创建一个新对象
//let newObject = {}; //空对象
//遍历obj对象中的所有属性,取出来赋值给新对象

//for(let key in obj){
//    newObject[key] = obj[key];
//    newObject.a = obj.a
// }

//修改obj对象中b对象中c属性的值
//obj.b.c = 200;
//console.log(obj,newObject);

//思考: 怎样才能实现深拷贝?
//1 当前对象中有多少个对象,我们就应该遍历多少次?(循环)
//声明一个对象
let obj = {
    a : 1,
    b : {
        c : 2,
        d : {
            e : 3
        }
    }
}
function deepCopy(obj){ //obj: 对象
    //创建一个空对象
    let object = {};
    //遍历当前对象
    for(let key in obj){
        //检测
        //1. 它是否为对象
        //2. 这个对象不能是null
        //{}  []  null
        //if(typeof obj[key] === 'object' && obj[key] !== null){
        if(obj[key] instanceof Object){
            //console.log(key,obj[key]);
            //再调用当前函数,进行检测
            object[key] = deepCopy(obj[key]);
            //object[b] = {}
            //object['b']['c'] = 2
            //object['b']['d'] = {}
            //object['b']['d']['e'] = 3
        }else{
            //console.log(key,obj[key]);
            object[key] = obj[key];
            //object['a'] = 1
            //object['c'] = 2
            //object['e'] = 3
        }
    }
    
    return object;
    /*
        {
            a: 1,
            b : {
                c: 2
                d: {
                    e : 3
                }
            }
        }
    */
}

//创建一个新对象
let newObj = deepCopy(obj);
//修改obj.b.c
obj.b.c = 200;
obj.b.d.e = 300;
console.log(obj,newObj);

//console.log(typeof [],typeof {},typeof null);
//console.log([] instanceof Object,{} instanceof Object,null instanceof Object);

function deepClone(obj){
    let object = {};
    for(let key in obj){
        if(obj[key] instanceof Object){
            object[key] =  deepClone(obj[key]);
        }else{
            object[key] = obj[key];
        }
    }
    return object;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值