优秀的编程知识分享平台

网站首页 > 技术文章 正文

对象 (基础详解)(对象指的是)

nanyue 2025-05-02 20:19:24 技术文章 3 ℃

创建对象的方式

(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

最近发表
标签列表