学习内容
- 对象的方法
- 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;
}