百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

对象 (基础详解)_对象的基本概念和主要特征

myzbx 2025-08-31 06:13 6 浏览

创建对象的方式

(1)Object 构造函数方式 Object 构造函数将给定的值包装为一个新对象。

  • 如果给定的值是 null 或 undefined, 它会创建并返回一个空对象。
  • 否则, 它将返回一个和给定的值相对应的类型的对象。
  • 如果给定值是一个已经存在的对象, 则会返回这个已经存在的值( 相同地址)
let o = new Object()
  o.foo = 42
  console.log(o)

(2)对象字面量方式

var obj1 = { foo: 'bar', x: 42 };

(3)Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。

如果该参数被指定且不为 undefined,则该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。这些属性对应于 Object.defineProperties() 的第二个参数。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create

const person = {
       isHuman: false,
       printIntroduction: function() {
           console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
       }
   };

   const me = Object.create(person);
   console.log(me)
   me.name = 'Matthew'; // "name" is a property set on "me", but not on "person"
   me.isHuman = true; // inherited properties can be overwritten

   me.printIntroduction();
   // expected output: "My name is Matthew. Am I human? true"

对象的静态方法

Object.assign() 通过复制一个或多个对象来创建一个新的对象。

Object.create() 使用指定的原型对象和属性创建一个新对象。

Object.defineProperty() 给对象添加一个属性并指定该属性的配置。

Object.defineProperties() 给对象添加多个属性并分别指定它们的配置。

Object.entries() 返回给定对象自身可枚举属性的 [key, value] 数组。

Object.freeze() 冻结对象:其他代码不能删除或更改任何属性。


Object.getOwnPropertyDescriptor() 返回对象指定的属性配置。


Object.getOwnPropertyNames() 返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名。


Object.getOwnPropertySymbols() 返回一个数组,它包含了指定对象自身所有的符号属性。 Object.getPrototypeOf() 返回指定对象的原型对象。

Object.is() 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。

Object.isExtensible() 判断对象是否可扩展。

Object.isFrozen() 判断对象是否已经冻结。

Object.isSealed() 判断对象是否已经密封。

Object.keys() 返回一个包含所有给定对象自身可枚举属性名称的数组。

Object.preventExtensions() 防止对象的任何扩展。

Object.seal() 防止其他代码删除对象的属性。

Object.setPrototypeOf() 设置对象的原型(即内部 [[Prototype]] 属性)。

Object.values() 返回给定对象自身可枚举值的数组。

对象的实例实例属性

  • Object.prototype.constructor
  • 一个引用值,指向 Object 构造函数
  • Object.prototype.__proto__
  • 指向一个对象,当一个 object 实例化时,使用该对象作为实例化对象的原型

方法定义

对象属性也可以是一个函数、getter、setter方法。

var o = {
 property: function ([parameters]) {},//or   property([parameters]) {}


 get property() {},
 set property(value) {},
};

属性

对象拥有两种属性:数据属性和访问器属性

数据属性

数据属性是键值对,并且每个数据属性拥有下列特性:

configurable :当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认值为false

Value: 包含这个属性的数据值。

Writable:如果该值为 false,则该属性的Value 特性不能被修改。

Enumerable : 如果该值为 true,则该属性可以用 for...in 循环来枚举。

let obj = {
        foo: 123
    };
    console.log(Object.getOwnPropertyDescriptor(obj, 'foo'))

访问器属性

访问器属性有一个或两个访问器函数(getset)来存取数值。 自定义 Setters和getter

function Archiver() {
 var temperature = null;
 var archive = [];

 Object.defineProperty(this, 'temperature', {
   get: function() {
     console.log('get!');
     return temperature;
   },
   set: function(value) {
     temperature = value;
     archive.push({ val: temperature });
   }
 });

 this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]

可枚举性

对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。
Object.getOwnPropertyDescriptor
方法可以获取该属性的描述对象

可枚举属性是指那些内部 “可枚举” 标志设置为 true 的属性,对于通过直接的赋值和属性初始化的属性,该标识值默认为即为 true,对于通过 Object.defineProperty 等定义的属性,该标识值默认为 false

    var o = {};
   Object.defineProperty(o, "a", {
       value: 1,
       enumerable: true
   });
   Object.defineProperty(o, "b", {
       value: 2,
       enumerable: false
   });
   Object.defineProperty(o, "c", {
       value: 3
   }); // enumerable 默认为 false
   console.log(o)

   for (var i in o) {
       console.log(i)
   }
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
//    value: 123,
//    writable: true,
//    enumerable: true,
//    configurable: true
//  }

for ...in

for...in语句以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。

  const user = {};
   Object.prototype.authenticated = true;
   for (var i in user) {
       console.log(i)
   }

示例2

 var obj = {};
    obj.name = 'xkx';
    obj.age = 18;
    obj.run = function() { //创建一个 run()方法并返回值
        return this.name + this.age + '运行中...';
    };

    // 给原型添加属性和方法
    Object.prototype.gaga = function() {
        console.log('gaga')
    }
    Object.prototype.names = 'names'
        // 给原型添加一个可枚举的属性
    Object.defineProperty(Object.prototype, "ages", {
        enumerable: false,
        configurable: false,
        writable: false,
        value: 20
    });
    var descriptor = Object.create(null); // 没有继承的属性
    // descriptor.value = 'static';
    // // 默认没有 enumerable,没有 configurable,没有 writable
    // Object.defineProperty(obj, 'key', descriptor);
    // console.log(Object.getOwnPropertyDescriptor(obj, 'key'))


    //显式

    Object.defineProperty(obj, "key", {
        enumerable: false,
        configurable: false,
        writable: false,
        value: "static"
    });
    console.log(Object.getOwnPropertyDescriptor(obj, 'key'))
    console.log(obj)
    console.log(Object.getPrototypeOf(obj))

    for (var i in obj) {
        console.log(i)
    }

原型上添加的不可枚举的ages属性,没有被枚举

如果将enumerable 改为true,原型上添加的ages 可枚举属性被遍历

Object.defineProperty(Object.prototype, "ages", {
        enumerable: true,
        configurable: false,
        writable: false,
        value: 20
    });

创建属性

如果对象中不存在指定的属性,Object.defineProperty() 会创建这个属性。当描述符中省略某些字段时,这些字段将使用它们的默认值。

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

var o = {}; // 创建一个新对象

// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o, "a", {
  value : 37,
  writable : true,
  enumerable : true,
  configurable : true
});

getPrototypeOf方法

getPrototypeOf()是JavaScript中的内置函数,用于检查用户创建的对象的原型。大多数时候,它用于检查两个对象是否具有相同的原型。这里的原型是指用户在JavaScript代码中定义的对象的内部定义

  const person = {
        isHuman: false,
        printIntroduction: function() {
            console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
        }
    };

    const me = Object.create(person);
    console.log(me)
    me.name = 'Matthew'; // "name" is a property set on "me", but not on "person"
    me.isHuman = true; // inherited properties can be overwritten

    me.printIntroduction();
    // expected output: "My name is Matthew. Am I human? true"

    console.log(Object.getPrototypeOf(me))

应用场景: (1)完整克隆一个对象,还拷贝对象原型的属性,可以采用下面的写法。

// 写法一
const clone1 = {
  __proto__: Object.getPrototypeOf(obj),
  ...obj
};

// 写法二
const clone2 = Object.assign(
  Object.create(Object.getPrototypeOf(obj)),
  obj
);

// 写法三
const clone3 = Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
)

getOwnPropertyDescriptor 方法


Object.getOwnPropertyDescriptor
方法可以获取该属性的描述对象。

let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
//    value: 123,
//    writable: true,
//    enumerable: true,
//    configurable: true
//  }
 console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable)
 console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'ages').enumerable)

defineProperty方法

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

Object.keys(obj)

Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

 var obj = {};
    obj.name = 'xkx';
    obj.age = 18;
    obj.run = function() { //创建一个 run()方法并返回值
        return this.name + this.age + '运行中...';
    };

    // 给原型添加属性和方法
    Object.prototype.gaga = function() {
        console.log('gaga')
    }
    Object.prototype.names = 'names'
        // 给原型添加一个可枚举的属性
    Object.defineProperty(Object.prototype, "ages", {
        enumerable: true,
        configurable: false,
        writable: false,
        value: 20
    });
    var descriptor = Object.create(null); // 没有继承的属性
    // descriptor.value = 'static';
    // // 默认没有 enumerable,没有 configurable,没有 writable
    // Object.defineProperty(obj, 'key', descriptor);
    // console.log(Object.getOwnPropertyDescriptor(obj, 'key'))


    //显式

    Object.defineProperty(obj, "key", {
        enumerable: true,
        configurable: false,
        writable: false,
        value: "static"
    });
    // console.log(Object.getOwnPropertyDescriptor(obj, 'key'))
    // console.log(obj)
    // console.log(Object.getPrototypeOf(obj))


    // console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable)
    // console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'ages').enumerable)



    // 查看对象原型上toString
    console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'toString'))
        // 修改前
    console.log(obj.toString())

    // 原型链方式修改
    Object.prototype.toString = function() {
            return '修改了toString方法'
        }
        // defineProperty方式修改
        // Object.defineProperty(Object.prototype, 'toString', {
        //         value: '.........'
        //     })
        // 修改后
    console.log(obj.toString())
        // 修改 重写 对象原型上的toString 方法

    // console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable)

    for (var i in obj) {
        console.log(i)
    }
    console.log(Object.keys(obj))

可以发现原型上的属性并没有被枚举出来

常用方法

(1) 怎样判断某个对象是否为另一个对象的原型对象 使用
Object.prototype.constructor.prototype进行比较

var obj1 = {name: "李雷"};
var obj2 = {age: 23};
obj1.constructor.prototype === Object.prototype; // true

(2)使用:
Object.prototype.isPrototypeOf()进行比较

var obj1 = {name: "Lilei"};
var obj2 = Object.create(obj1);

obj1.isPrototypeOf(obj2); // true

(3)扩展属性 ECMAScript 提案(第 3 阶段)的剩余/扩展属性将扩展属性添加到对象字面量。它将自己提供的对象的枚举属性复制到一个新的对象上。

使用比Object.assign()更短的语法,可以轻松克隆(不包括原型)或合并对象。

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };

var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }

(4)hasOwnProperty 继承的属性不显示

var triangle = {a: 1, b: 2, c: 3};

function ColoredTriangle() {
  this.color = 'red';
}

ColoredTriangle.prototype = triangle;

var obj = new ColoredTriangle();

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log(`obj.${prop} = ${obj[prop]}`);
  }
}

// Output:
// "obj.color = red"

(4)Object.create(null)生生的对象里面没有任何属性,非常“空”,我们称它为字典,这种字典对象适合存放数据,不必担心原型带来的副作用。

bject.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false

关于 _proto和 prototype

而构造函数的prototype是什么,它的原型链最终又指向了哪里呢?这个问题的答案是:函数的prototype是一个在函数声明阶段就会产生的对象(prototype只有函数才会有),这个对象只有两个属性constructor和__proto__,其中__proto__指向了我们原型链的顶点Object.prototype。constructor指向函数本身,里面包括了函数一些基本描述信息比如函数名称,参数个数等。

有意思的是constructor里面即有__proto__又有prototype,他们之间有什么关系和差别呢?首先prototype描述的是原型对象,它是一个实实在在的对象,__proto__是用来描述对象间的关联关系的。最终会指向一个prototype原型。函数由Function衍生而来,所以函数的__proto__指向的是Function.prototype。Function是由Object衍生而来,有意思的事情又发生了,Function的__proto__却并不指向Object.prototype,而是指向Function.prototype这个标准的内置对象。
Function.prototype.__proto__才是指向我们的原型链顶点Object.prototype

Function.proto === Function.prototype // true

相关推荐

半导体行业术语缩写词典总结-JKL_半导体词汇缩写表

作为半导体行业新人来说,最痛苦的莫过于各种缩写词术语了,有的缩写词一样但是会有不同的解释。这里作者给大家整理了部分术语词典,后面会按照更新顺序一一分享出来。废话不多说,直接开始,如有遗漏,欢迎大家在评...

JD.com Deepens Push Into Embodied Intelligence With Investment in Sensor Maker PaXiniTech

ToraOne,thesecond-generationmultidimensionaltactilehumanoidrobotdevelopedbyPaXiniTechTMTPOS...

Hong Kong's Consumer Market Becomes New Battleground for Chinese Mainland Internet Giants

AI-generatedimageTMTPOST--StrollthroughthestreetsofHongKongtoday,anditmightfeellikey...

http2解决了哪些问题_简述http2的优点

HTTP/2(最初称为SPDY)是HTTP协议的第二个主要版本,它在HTTP/1.1的基础上进行了重大改进,旨在解决其在性能和效率方面的诸多瓶颈。以下是HTTP/2主要解决的问题:队头阻...

China's economy stays strong and vital amid pressure

Peoplevisitthe4thChina-CEECExpo&InternationalConsumerGoodsFairinNingbo,eastChina's...

JD.com Makes $2.4 Billion Bid for Ceconomy in Bold Push to Build a Global Retail Empire

TMTPOST--JD.comhasunveiledplanstoacquireGermany’sCeconomyAG—theparentofEurope’sleading...

深入剖析 Java 中的装饰器设计模式:原理、应用与实践

在Java软件开发的广阔天地里,设计模式犹如璀璨星辰,照亮我们构建高效、可维护系统的道路。今天,让我们聚焦于其中一颗闪耀的星——装饰器设计模式,深入探究它的奥秘,看看如何利用它为我们的代码赋予...

组合模式应用-适配器模式_适配器组件

写在前面Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!该部分为各模式组合使用,涉及代码较多,熟能生巧。内容回顾定义适配器模式是一种结构型设计模式,...

OOM (Out Of Memory) 故障排查指南

1.确认OOM类型首先需要确认是哪种类型的OOM:JavaHeapOOM:Java堆内存不足NativeMemoryOOM:本地内存不足MetaspaceOOM:元空间内存不足Contai...

刷完这49题,面试官当场给Offer!Java程序员必备指南

1.问题:如果main方法被声明为private会怎样?答案:能正常编译,但运行的时候会提示”main方法不是public的”。2.问题:Java里的传引用和传值的区别是什么?答案:传引用是指传递的是...

C#编程基础(看这一篇就够了)_c#编程入门与应用

C#及其开发环境简介C#概述C#是一个现代的、通用的、面向对象的编程语言,由微软(Microsoft)开发,经Ecma和ISO核准认可。它由AndersHejlsberg和他的团队在.NET框架开发...

说一下JDK的监控和 线上处理的一些case

一句话总结JDK监控常用工具包括JConsole、VisualVM、JMC等,用于实时查看内存、线程、GC状态。线上常见问题处理:内存泄漏通过heapdump分析对象引用链;频繁GC可调整-Xmx/...

JavaScript深拷贝极简指南:3种方法解决嵌套与循环引用难题

为什么需要深拷贝?首先我们看看浅拷贝,point指向的是同一个地址,这时我们修改obj2.point的属性时,obj1的point属性也会被修改再看看深拷贝,point指向的是不同地址,这时我们修改o...

Java 25 在 JEP 519 中集成了紧凑对象头

作者|ANMBazlurRahman译者|刘雅梦策划|丁晓昀Java25通过JEP519将紧凑对象头作为产品特性进行了集成,在不需要更改任何代码的情况下,为开发人员提供了...

每日一练 Python 面试题(1)_python每日一记

以下是5道Python基本语法相关的面试题,涵盖变量、运算符、数据结构、函数和异常处理等核心概念:1.变量与作用域题目:以下代码的输出是什么?解释原因。x=10deffunc():...