js 对象 详解
发布日期:2022-02-08 04:21:00 浏览次数:3 分类:技术文章

本文共 8033 字,大约阅读时间需要 26 分钟。

一、对象的创建和应用

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=10var obj2=Object.create(obj1);console.log(obj2);

在这里插入图片描述

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

原型是指类中用来描述该类实际特征、属性、方法的;

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

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

有篇文章,介绍原型、原型链的,我觉得挺好:

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,});后面再来讲解get和set,get和set不能够和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(obj);console.log(arr);(3)获取某个属性的描述对象:var desc = Object.getOwnPropertyDescriptor(obj, "f");console.log(desc);

在这里插入图片描述

三、对象浅复制&深复制

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

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

目前学的浅复制的方法:

1、for in 看不到不可枚举属性,不遍历空属性for(var prop in obj){
// 浅复制}2、Object.assign();//浅复制3、var obj1={
...obj};//浅复制,obj作为一个对象属性;如果原obj1就存在,还会改变原obj1的引用地址4、JSON字符串,表面上看是深复制,但其实,复制的不完全;所以既不是深复制,也不是浅复制。var obj1=JSON.parse(JSON.stringify(obj));//不能达到真正的复制console.l(obj1,obj);//可以自己看一下,有很多不同

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

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

四、对象的其他方法集合

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));//trueconsole.log(NaN === NaN);//false

hasOwnProperty() 与 in

  • hasOwnProperty()判断对象实例是否具有某个对象属性。
  • hasOwnProperty()方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。
  • 如果该属性或方法是该对象自身定义的而不是原型链中定义的,则返回true;否则返回false。
  • in判断的是对象的所有属性,包括对象实例及其原型的属性。
var obj = {
a: 1};console.log(obj.hasOwnProperty("a"));//trueconsole.log(obj.hasOwnProperty("b"));//falsevar 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、Ballconsole.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

在这里插入图片描述

转载地址:https://blog.csdn.net/weixin_43297321/article/details/104368934 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:jQuery 表格选中颜色变化
下一篇:js 对象深复制

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月09日 07时17分11秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章