JavaScript对象【一】

概述

在JavaScript中有一句颇有争议的话  ——   “一切皆对象”

这个观念是JavaScript设计哲学的一个重要部分,它让JavaScript在编程时提供了极大的灵活性和表达能力。

虽然在JS中确实几乎所有的东西都可以被视为对象,但有几个核心概念需要明确:

  • 原始类型:JS中的基本数据类型本身不是对象。但某些时候,JS会临时将它们包装成对象(除了null和undefined),比如,当它们被用作对象时(例如,通过调用方法)

      字符串"hello"可以调用.length属性,实际上是JS内部将其临时转换成了String对象。

let str = 'hello'
console.log(str.length) //5
  • 函数:在JS中,函数也是对象。这意味着函数可以拥有属性和方法。这是JS实现高阶函数(接受函数作为参数或返回函数的函数)和闭包等强大的编程模式的支撑。

  • 内置对象:JS还提供了许多内置对象,如Array、Date、RegExp等,这些内置对象提供了丰富的功能,使得开发者可以轻松地处理数组、日期、正则表达式等。

  • 特殊对象:JS还提供了许多功能强大的特殊对象,如代理proxy

关于对象包装:

  1. 原始包装对象:对于基本数据类型(数字、字符串、布尔值等),JS会临时使用它们的包装对象版本(如NumberStringBoolean),以便你可以访问它们的方法(如.toString().length等)。但是,这些包装对象是临时的,只在访问方法时存在,之后就会被丢弃
  2. null 和 undefined:对于nullundefined,它们没有对应的原始包装对象。因此,当你尝试对nullundefined使用属性访问操作符时,JS无法将它们转换为对象,从而会抛出一个TypeError

基础

对象的创建

JS提供了两种创建对象的主要方式:

  1. 对象字面量:通过{  }直接定义对象的属性和方法

    let person = {
        name: 'Alice',
        age: 30
    }
  2. 构造函数(Constructor):通过定义构造函数(用于初始化新创建对象的函数),并使用new关键字创建对象实例

    function Person(name, age) {
        this.name = name
        this.age = age
    }
    let person = new Person('Bob', 25)

对象的嵌套

对象的属性可以是原始数据类型,也可以是一个对象(包括函数数组等)

let person = {
    name: 'IKUN',
    work: {
        skill: '摸鱼'
    },
    greet: function () {
        console.log(`Hello, my name is ${this.name}.`)
    }
}
console.log(person.work.skill) //摸鱼
person.greet() //Hello, my name is IKUN

对象的属性访问

运算符( . )表示getattr(访问)的意思;通常,使用[ ]访问时需要加引号。

添加
let person = {}
person.name = 'IKUN'
person['skill'] = '守护最好的KUNKUN'
console.log(person.name) //IKUN
console.log(person['skill']) //守护最好的KUNKUN
修改
let person = {
    naem: 'IkUN',
    skilk: '守护最好的KUNKUN'
}
person.name = 'KUNKUN'
person['skill'] = '打篮球'
console.log(person.name) //KUNKUN
console.log(person['skill']) //打篮球
删除
let person = {
    name: 'IkUN',
    skill: '守护最好的KUNKUN'
}
delete person.name// 删除name属性
delete person['skill'] // 删除skill属性
delete person.gender // 删除一个不存在的gender属性也不会报错
判断是否拥有某属性

1.in操作符        不过这个属性不一定是对象自身的,它可能是继承得到的

let person = {
    name: 'IkUN',
}
console.log('name' in person) // true
console.log('age' in person) // false

2.hasOwnProperty()        检查对象自身(不包括原型链)是否具有指定的属性

let person = {
    name: 'IkUN'
}
console.log(person.hasOwnProperty('name')) // true
console.log('toString' in person) // true
console.log(person.hasOwnProperty('toString')) // false

进阶

原型对象

JS对象可以从一个“称为原型” 的对象里继承属性和方法。这种”原型链继承“是 JS 的核心特征之一

参考

​​​​​​JavaScript函数-CSDN博客  ——  “构造函数 ”

静态方法与实例方法
  1. 静态方法:定义在构造函数本身上的方法,它不能通过实例来调用,只能通过类本身来调用。静态方法通常用于实现与类本身相关的功能,比如工具类。
  2. 实例方法:实例对象从原型对象(prototype)上继承来的方法,可以由实例调用(通过原型链访问)。实例方法通常用于操作实例的属性或执行与实例相关的操作。

function Person(name) {
    this.name = name // 实例属性
}
// 静态方法
Person.staticMethod = function () {
    console.log('这是一个静态方法')
}
// 原型对象方法(实例方法)
Person.prototype.greet = function () {
    console.log(`Hello, my name is ${this.name}`)
}
// 使用
const person1 = new Person('Alice')
person1.greet() // 调用实例方法
// Person.greet(); // 错误,不能通过类直接调用实例方法
Person.staticMethod() // 调用静态方法
// person1.staticMethod(); // 错误,静态方法不能通过实例调用

        属性同理 —— 实际上对象的方法可以看作是对象属性的一种


 对象的常用方法

1.Object.assign()       

将所有可枚举的自有属性的值从一个或多个对象复制到目标对象,并返回目标对象。

 语法:

Object.assign(target, source1,source1....)
  • target: 目标对象
  • source: 源对象,其可枚举的自有属性将被复制到目标对象上

 示例:

const target = { a: 1, b: 2 }
const source1 = { b: 4, c: 5 }
const source2 = { c: 6 }
const returnedTarget = Object.assign(target, source1, source2)
console.log(target)
// 输出: Object { a: 1, b: 4, c: 6 }
console.log(returnedTarget)
// 输出: Object { a: 1, b: 4, c: 6 }
// 注意,`Object.assign()` 改变了 `target` 对象
//,并且 `target` 和 `returnedTarget` 指向同一个对象。
  1. Object.assign() 执行的是浅拷贝,如果对象的属性值是引用数据类型,那它只拷贝地址。
  2. 如果source或target不是对象,则会先将其转换为一个对象。如果是 null 或 undefined,则会抛出一个 TypeError,因为 null 和 undefined 不能被转换为对象。

  3. 如果多个source具有相同的属性,则后面的source会覆盖前面的source中的属性值。

  4. Object.assign() 会复制source的所有自有属性,包括字符串和符号属性名。

2.Object.create()

指定一个对象作为新创建对象的原型链的起点。新对象将继承指定原型对象的属性和方法。

 语法:

const newObject = Object.create(proto[, propertiesObject])
  • proto:新创建对象的原型对象
  • propertiesObject(可选):一个对象,其属性描述符将会被添加到新创建的对象上,这些属性对应新对象的自身属性(即非继承自原型的属性)

示例:

// 创建一个空对象,其原型为null
const obj1 = Object.create(null)
console.log(obj1.hasOwnProperty) // undefined,因为obj1没有原型

// 创建一个对象,其原型为另一个对象
const personProto = {
    isHuman: true,
    printIntroduction: function () {
        console.log(
            `My name is ${this.name}. Am I human? ${this.isHuman}`
        )
    }
}
// 使用propertiesObject来定义新对象的自身属性
const properties = {
    name: {
        value: 'John',
        writable: true,
        enumerable: true,
        configurable: true
    }
}
// 创建新对象,其原型为personProto,并添加name属性
const john = Object.create(personProto, properties)
john.printIntroduction()
// 预期输出: "My name is John. Am I human? true"
  1. Object.create(null) ,得到一个没有原型的对象,它不会有任何继承自Object.prototype的方法,如hasOwnProperty、toString等。这在某些需要避免继承自Object.prototype的默认属性和方法的场景中很有用。

3.Object.defineProperty() 

直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。这个方法允许你精确地添加或修改对象的属性。

语法:

Object.defineProperty(obj, prop, descriptor)
  • obj:要定义属性的对象
  • prop:要定义或修改的属性的名称或Symbol
  • descriptor:将被定义或修改的属性描述符

   属性描述符(可包含以下之一或多个

  • value:属性的值。
  • writable:当且仅当该属性的值可以被改变时为true
  • configurable:当且仅当该属性的描述符可以被改变,且该属性可以从对应的对象中被删除时为true
  • enumerable:当且仅当该属性出现在对象的枚举属性中时为true
  • get:作为该属性的 getter 函数,如果没有 getter 则为undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入this值(即被访问的对象)。
  • set:作为该属性的 setter 函数,如果没有 setter 则为undefined。当属性值被修改时,会调用此函数。该函数将接收唯一参数,即被赋予的新值。

示例:

const person = {
    firstName: 'John',
    lastName: 'Doe',
    fullName: ''
}
//writable属性描述符
Object.defineProperty(person, 'age', {
    value: 18,
    writable: false
})
console.log(person.age) // 18
// 尝试修改属性失败,因为writable为false
person.age = 22
console.log(person.age) // 仍然是18
//getter和setter
Object.defineProperty(person, 'fullName', {
    get: function () {
        return `${this.firstName} ${this.lastName}`
    },
    set: function (value) {
        ;[this.firstName, this.lastName] = value.split(' ')
    }
})
console.log(person.fullName) // John Doe
person.fullName = 'Alice Idorila '
console.log(person.firstName) // Alice
console.log(person.lastName) // Idorila
4.Object.defineProperties() 

语法与 Object.defineProperty() 方法基本一样,不同的是,Object.defineProperties() 可以一次定义或修改多个属性。

var obj = {};
Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    value: 'Hello',
    writable: false
  }
});
console.log(obj); //  property1: true  property2: "Hello"
5.Object.keys()

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

这个方法在需要遍历对象的键或获取对象的所有键名时非常有用。

语法:

​Object.keys(obj)
  •  obj : 目标对象

示例:

const person = {
    firstName: 'John',
    lastName: 'Doe',
    age: 30,
    [Symbol.for('id')]: 12345
}
console.log(Object.keys(person))
// 输出: ["firstName", "lastName", "age"]
// 注意:Symbol 类型的属性不会被包括在内
6.Object.values()

返回一个数组,包含对象自身的所有可枚举属性的值。

这个方法允许你轻松地获取对象属性的值数组,而无需手动遍历对象的键。

语法:

​Object.keys(obj)
  •  obj : 目标对象

 示例:

const person = {
    name: 'John',
    age: 30,
    city: 'New York'
}
console.log(Object.values(person))
// 输出: ["John", 30, "New York"]
7.Object.entries()

返回一个数组,包含对象自身可枚举属性的键值对。

其排列与使用 for...in 循环遍历对象时返回的顺序一致(两者的主要区别是 for...in 循环还会枚举其原型链上的属性)。

语法:

Object.entries(obj)
  • obj:目标对象

示例:

const object1 = {
    a: 'somestring',
    b: 42,
    c: false
}
console.log(Object.entries(object1))
// 输出: [ ['a', 'somestring'], ['b', 42], ['c', false] ]
// 可以通过解构赋值来提取键和值
for (let [key, value] of Object.entries(object1)) {
    console.log(`${key}: ${value}`)
}
// 输出:
// a: somestring
// b: 42
// c: false
// 映射对象的值到一个新数组
const values = Object.entries(object1).map(([key, value]) => value)
console.log(values)
// 输出: ['somestring', 42, false]
7.Object.is()

用于确定两个值是否相同。这个方法与严格相等运算符(===)非常相似,但在处理 +0 和 -0,以及 NaN 时有所不同。

语法:

Object.is(value1, value2)

与 === 的区别

  1. 处理 NaN
    • Object.is(NaN, NaN) 返回 true,因为按照 ECMAScript 规范,NaN 被视为与自身相等的唯一值。
    • NaN === NaN 返回 false,因为严格相等运算符认为 NaN 不等于自身。
  2. 处理 +0 和 -0
    • Object.is(+0, -0) 返回 false,因为 +0 和 -0 被视为不同的值。
    • +0 === -0 返回 true,因为严格相等运算符认为 +0 和 -0 是相等的。

示例:

console.log(Object.is(NaN, NaN)) // true
console.log(NaN === NaN) // false
console.log(Object.is(+0, -0)) // false
console.log(+0 === -0) // true
console.log(Object.is(42, 42)) // true
console.log(42 === 42) // true
console.log(Object.is('foo', 'foo')) // true
console.log('foo' === 'foo') // true
console.log(Object.is(true, true)) // true
console.log(true === true) // true
console.log(Object.is(Object.create(null), Object.create(null))) // false
console.log(Object.create(null) === Object.create(null)) // false
8.hasOwnProperty()

判断一个对象自身(不包括其原型链)是否含有指定的属性。

示例:判断是否拥有某属性

9.isPrototypeOf()

判断当前对象是否为另一个对象的原型链中的的原型对象。

 语法:

prototypeObject.isPrototypeOf(object)
  • prototypeObject:需要判断是否为原型的对象。
  • object:需要检查其原型链中是否包含 prototypeObject 的对象。

示例:

function Person(name) {
    this.name = name
}
let person1 = new Person('Alice')
console.log(Person.prototype.isPrototypeOf(person1)) // true
console.log(Object.prototype.isPrototypeOf(person1)) // true
console.log(Function.prototype.isPrototypeOf(Person)) // true

10.valueOf()和toString()

valueOf 和toString()方法都是JS中所有对象都继承自 Object.prototype 的方法。当你尝试将一个对象转换成某种基本类型时,JS 引擎会尝试调用该对象的 这两个方法来获取一个适当的值。注意,valueOf 方法主要用于与数字相关的转换,而 toString 方法则用于与字符串相关的转换。

valueOf:

const person = {
    name: 'Jack',
    // 重写valueOf方法以返回某个值
    valueOf: function () {
        return 22
    }
}
// 当尝试将person用作数学运算的操作数时,会调用valueOf方法
console.log(person + 10) // 输出:32
// 使用Number()函数也会触发valueOf方法
console.log(Number(person)) // 输出:22

toString:

const obj = {
    value: [1, 2],
    toString: function () {
        return `[${this.value}]`
    }
}
console.log(String(obj)) //输出"[1 ,2]"

 注意:如果valueOf方法返回的不是一个基本类型值,JS会继续尝试调用toString方法,如果想要确保数学运算正确执行,必须确保valueOf返回的是基本类型。如下

const obj= {
    value: 22,
    valueOf: function () {
        return { value: this.value }//valueOf返回一个对象
    },
    toString: function () {
        return `Value is ${this.value}`
    }
}
// 由于valueOf返回的不是基本类型,JS会尝试调用toString
person.console.log(obj+ 10) 
// 输出:"Value is 2210",注意这可能不是你所期望的数学运算结果

JavaScript函数对象: JavaScript函数

JavaScript内置对象/特殊对象:


如有不足或遗漏,烦请私信或评论留言😊

  • 37
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值