js 对象 详解

一、对象的创建和应用

1、之前学过的创建方法
1、字面量创建法:
var obj={a:1,b:2};
console.log(obj);

2、构造函数创建法:
var obj=new Object();
obj.a=1;   //增加属性
obj.b=2;
2、Object.create()方法创建
1、根据空对象创建:
var obj1=Object.create({});
2、根据已有对象创建:
var obj1=Object.create(obj);
console.log(obj2,obj1);
3、获取,会先查找该对象下有没有该属性,如果没有就去原型链中查找:
console.log("obj1.b:"+obj1.b);

打印查看结果:根据obj创建的obj1,继承于obj的属性被放在了__protp__原型链属性中。
在这里插入图片描述
4、_ _ proto _ _:原型链属性
被放在原型链下的属性,叫原型属性;
直接放在对象下的属性,叫对象属性;

如果想要修改原型链属性,只需要修改最顶端的对象的属性即可;比如obj.b = -10;obj1与obj2原型链中的b都会变成-10 。

如果该对象有对象属性,就可以直接获取对象属性;如果没有对象属性就会获取距离该对象最近的原型链属性。
设置属性时,只会设置对象属性,不能设置原型链属性。
obj1.b = 10;
console.log(obj1);
console.log("obj1.b="+obj1.b);  //obj1.b=10

var obj2=Object.create(obj1);
console.log(obj2);

在这里插入图片描述

原型、原型链其实是一个东西,只是针对的东西不一样。原型针对类,原型链针对对象,但他们的引用完全相等。

原型是指类中用来描述该类实际特征、属性、方法的;
如果直接在类上写属性 、方法,是静态方法;而如果用原型,上面所描述的属性、方法,实例化后,就可以通过实例来调用该方法。

原型链是实例化类以后的对象,会自动拥有类自身的原型。

有篇文章,介绍原型、原型链的,我觉得挺好:js原型和原型链,以及__proto__、prototype属性

5、禁止使用这种方式进行修改:

obj2.__proto__.__proto__.b=-100;  //绝对不允许
console.log(obj);
console.log(obj1);
console.log(obj2);

6、原型链中的属性不能被直接删除:

var obj = { a: 1, b: 5 };
var obj1 = Object.create(obj);
delete obj1.b; 
console.log(obj1);

在这里插入图片描述
7、对象属性可以直接删除;原型链中的属性可以获取到:

var obj = { a: 1, b: 5 };
var obj1 = Object.create(obj);

var bn = document.querySelector("button");
bn.addEventListener("click", clickHandler);

function clickHandler(e) {
    obj1.b++;
    // if(obj1.b>=10) obj1.b=obj1.__proto__.b;  //可以获取原型链里的属性,重新赋值
    if (obj1.b >= 10) delete obj1.b;  //删除对象属性,下次还是会去原型链中查找最近的
    this.textContent = obj1.b;
}

结果:按钮从无到有,从5到9,在5~9之间来回变换
在这里插入图片描述在这里插入图片描述在这里插入图片描述
8、对象属性的删除

var obj={};
var obj1={b:2};
obj.a=obj1; // obj1作为obj.a一个对象属性
delete obj.a;  //删除对象属性,但没有删除引用关系
obj1=null; //这样才彻底删除引用关系

但有种情况是没法使用上面的方法删除的:
var obj={a:{b:2}};
// 这个时候用delete直接删掉obj.a的话,obj.a是会变成孤儿对象,造成内存引用泄漏;
// 但下面的就可以了:先删除引用关系,再把这个对象属性删掉
obj.a=null;
delete obj.a;
3、Object.assign()方法创建

Object.assign(目标对象,源对象1,源对象2,… ); 返回目标对象;
Object.create()通过原型创建对象,把另一个对象作为原型放入新对象的原型链中,可以创建对象;
Object.assign()是不能创建对象的,必须拥有目标对象才能创建;

<1> obj1不存在,也可以被直接创建
var obj={a:1};
var obj1=Object.create(obj);

<2> obj1必须先创建存在
var obj1={}; 
obj1=Object.assign(obj1,obj);
// 或者使用下面的写法,先创建了一个空对象,然后将obj复制到这个空对象上:
var obj1=Object.assign({},obj); // 这个空对象和obj1引用相同

1、所以Object.assign只能复制对象属性,不能复制对象的原型链属性
2、只能复制可枚举类型
3、引用关系也会一同被复制,只能浅复制
4、多个源对象复制时,如果有相同的属性,则后面的将会覆盖前面的属性

var obj={a:1,b:2};
var obj1={b:3,c:10};
var obj2 = Object.assign({}, obj, obj1);
console.log(obj2); //{a: 1, b: 3, c: 10}

// 其他用法
Object.assign(div.style,{
	// 我们之前不是经常这么写样式嘛
})

二、对象的属性定义 & 获取

1、之前我们用的对象属性定义方法
obj.a=3;
obj["b"]=5;
仅仅定义了值,没有定义引用,复杂的就不行了。
2、Object.defineProperty()
  • 1、功能:定义属性。
    原型链属性是不可以被修改描述对象的。
var obj = {_b:1};
	     三个参数:  对象 对象属性 描述对象
Object.defineProperty(obj, "a", {
    // 是否可删除属性并且是否可以重定义该属性的属性描述对象,默认值是false:
    configurable: false,
    // 是否可以遍历,是否可枚举(该对象在使用for in遍历时,不可枚举属性是不能被遍历,也不能被Object.assign()复制 ):
    enumerable: false,
    // 是否可写,是否能够修改值:
    writable: false,
    // 是值,还可以是function方法:
    value: 10,
});

后面再来讲解getsetgetset不能够和writable和value同时定义,所以分开展示了:

Object.defineProperty(obj, "b", {
    configurable: false,
    enumerable: false,
    // get和set不能够和writable和value同时定义
    get: function () {
        return this._b;
    },
    set: function (value) {
         this._b=value;
    }
})
  • 2、定义一个obj,里面有函数abc,用for in遍历的话,会遍历函数abc;所以如果想要只遍历属性,就不能用这种方法。
var obj={
    a:1,
    b:2,
    abc:function(){
        console.log("abc")
    }
}
for(var prop in obj){
    console.log(prop);
}
  • 3、如果把该属性函数的描述对象里设置成 enumerable:false,就不会遍历:
var obj0 = {
    a: 1,
    b: 2
}
Object.defineProperty(obj0, "abc", {
    // 其实下面这三句可以不写,不写,默认false
    // enumerable:false,
    // configurable:false,
    // writable:false,
    value: function () {
        console.log("abc")
    }
});
console.log(obj0);

// 只遍历属性了,不会遍历函数abc(不可枚举)
for (var prop in obj0) {
    console.log(prop);
}

// 然后此时再用Object.assign()就不会复制方法
var obj1 = Object.assign({}, obj0);
console.log(obj1);

在这里插入图片描述

  • 4、定义多个属性 & 将属性返回 & 获取描述对象
Object.defineProperties(obj,{
    "c":{
        // 描述对象
        value:function(){
        }
    },
    d:{
        // 描述对象
        value:10,
        writable:true
    },
    e:{
        value:20,
        writable:true,
        configurable:true
    },
    f:{
        value:30,
        enumerable:true
    }
});
console.log(obj);1)不过除了enumerable:true的,以上那些属性都没法遍历;

(2)不过可以通过获取obj的所有属性(不包括原型链属性__proto__),把所有的属性名放在一个数组中返回:
var arr = Object.getOwnPropertyNames(ob
j);
console.log(arr);3)获取某个属性的描述对象:
var desc = Object.getOwnPropertyDescriptor(obj, "f");
console.log(desc);

在这里插入图片描述

三、对象浅复制&深复制

浅复制:有相同的引用,比如说,新对象改变了其中一个对象属性后,源对象里该对象属性也改变了。

深复制:源对象的属性如果有对象,该对象属性修改后,不会引起复制后的对象各属性的改变,源对象的任何属性及子属性,与新对象的没有任何引用关系。

目前学的浅复制的方法:

1for in 看不到不可枚举属性,不遍历空属性
for(var prop in obj){
    // 浅复制
}

2、Object.assign();//浅复制

3var obj1={...obj};//浅复制,obj作为一个对象属性;如果原obj1就存在,还会改变原obj1的引用地址

4JSON字符串,表面上看是深复制,但其实,复制的不完全;所以既不是深复制,也不是浅复制。
var obj1=JSON.parse(JSON.stringify(obj));//不能达到真正的复制
console.l(obj1,obj);//可以自己看一下,有很多不同

目前学的深复制的方法:之前讲过很多例子,自己去翻翻以前的笔记。

下面要展示一个特别全活的深复制例子,这个很重要:js 对象深复制

四、对象的其他方法集合

Object.freeze()
  • 冻结的对象不能增加属性,不能重新设置属性,不能删除,也不能重新设置属性的描述对象。
  • 对象自身是可以删除的,只是对象所对应的属性,都是被冻结的。
var obj={a:1,b:2};
Object.freeze(obj);
// 对象冻结后,不能增加属性
obj.c=30;
// 不能重新设置属性
obj.a=1000;
// 也不能删除属性
delete obj.a;
console.log(obj);//虽然能够打印出来,但是obj没有任何改变
// 不能重新设置属性的描述对象
Object.defineProperty(obj,"a",{
    configurable:true,
    writable:true,
    enumerable:true,
    value:3000
})
console.log(obj);//出错了
// obj自身是可以删除的
obj=null;
console.log(obj);//null

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 对象被冻结后,使用Object.assign()与Object.create()
// obj虽被冻结,但可以用于复制,并且复制后的属性是可以删除和修改的
var obj1=Object.assign({},obj);
obj1.a=10;
console.log(obj1);

var o=Object.create(obj);//属性描述特征是被继承过去的
// 首先判断对象有没有原型属性a,如果有,还需要看原型属性a是否冻结,如果冻结则不能增加对象属性
o.a=10;//不能
o.c=10;//能增加,因为o没有被冻结
console.log(o);

在这里插入图片描述

判断对象是否冻结的两种方法 Object.isExtensible()、Object.isFrozen()
  • Object.isExtensible() 判断当前对象是否可扩展:若对象被冻结,结果为false,则为不可扩展;若为true,则可以扩展。
  • Object.isFrozen() 判断当前对象是否冻结:若对象被冻结,结果为true;否则,未被冻结。
var obj = { a: 1 };
Object.freeze(obj);
console.log(Object.isExtensible(obj));// false 不可扩展
console.log(Object.isFrozen(obj));// true obj被冻结 

所以,判断对象冻结有以上两种判断方法。

Object.is()
  • 比较数据和数据的类型,等同于" === " 的用法。
var a=3;
var b="3";
console.log(Object.is(a, b));//false 类型不等
console.log(Object.is([],[]));//false 引用不同

var a = 3;  //数值类型
var b = new Number(3);  //对象类型  创造数值型对象
console.log(Object.is(a, b)); //false 类型不等

var b=Number(3);//强制转换为数值3 数值类型
console.log(Object.is(a, b)); //true

// 很特殊的例子:(其他都跟 === 用法一样)
console.log(Object.is(NaN, NaN));//true
console.log(NaN === NaN);//false
hasOwnProperty() 与 in
  • hasOwnProperty()判断对象实例是否具有某个对象属性。
  • hasOwnProperty()方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。
  • 如果该属性或方法是该对象自身定义的而不是原型链中定义的,则返回true;否则返回false。
  • in判断的是对象的所有属性,包括对象实例及其原型的属性。
var obj = { a: 1};
console.log(obj.hasOwnProperty("a"));//true
console.log(obj.hasOwnProperty("b"));//false

var o=Object.create(obj);
console.log(o.hasOwnProperty("a"));//false 原型属性不是当前对象的对象属性
console.log("a" in o);//true in判断属性是否是对象属性时,只要是该对象的原型属性和对象属性都可以判断
isPrototypeOf()
  • isPrototypeOf() 是用来判断指定对象object1是否存在于另一个对象object2的原型链中,是则返回true,否则返回false。
  • 或者这么理解,object2._ _ proto _ _ ==== object1.prototype ? true:false 。
var obj = { a: 1};
var o=Object.create(obj);
var o1=Object.create(o);
o.a=10;
o1.a=1000;
console.log(o.isPrototypeOf(obj));//false 
console.log(obj.isPrototypeOf(o));//true obj是o对象的原型
console.log(o,o1);
console.log(obj.isPrototypeOf(o1));//true  obj是o1的原型链中的一个
console.log(o.isPrototypeOf(o1));//true  o也是o1的原型链中的一个

在这里插入图片描述

  • 类中,isPrototypeOf 可以判断某个类的父类是否是这个指定类。
  • 语法:父类.isPrototypeOf(子类)
class Box {
    a = 3;
    constructor() {

    }
}

class Ball extends Box {
    b = 10;
    constructor() {
        super();
    }
}

class Rect extends Ball {
    c = 20;
    constructor() {
        super();
    }
}
var rect=new Rect();
console.log(rect);
// 说明Rect继承于Ball,Ball继承于Box,所以Rect的父类当中有Box、Ball
console.log(Box.isPrototypeOf(Rect));//true 
console.log(Ball.isPrototypeOf(Rect));//true 

在这里插入图片描述

propertyIsEnumerable
  • propertyIsEnumerable 判断是否是可枚举属性。
var obj={a:1,b:2};
Object.defineProperty(obj,"b",{
    enumerable:true  //设置可枚举
});
Object.defineProperty(obj,"c",{
    value:3000
});

var names=Object.getOwnPropertyNames(obj);
console.log(names);
for(var i=0;i<names.length;i++){
    if(obj.propertyIsEnumerable(names[i])){
        console.log(names[i]+"是可枚举属性")
    }else{
        console.log(names[i]+"是不可枚举属性")
    }
} 

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值