概述
在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会临时使用它们的包装对象版本(如
Number
、String
、Boolean
),以便你可以访问它们的方法(如.toString()
、.length
等)。但是,这些包装对象是临时的,只在访问方法时存在,之后就会被丢弃 - null 和 undefined:对于
null
和undefined
,它们没有对应的原始包装对象。因此,当你尝试对null
或undefined
使用属性访问操作符时,JS无法将它们转换为对象,从而会抛出一个TypeError
基础
对象的创建
JS提供了两种创建对象的主要方式:
-
对象字面量:通过{ }直接定义对象的属性和方法
let person = {name: 'Alice',age: 30 }
-
构造函数(Constructor):通过定义构造函数(用于初始化新创建对象的函数),并使用
new
关键字创建对象实例function Person(name, age) {this.name = namethis.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博客 —— “构造函数 ”
静态方法与实例方法
- 静态方法:定义在构造函数本身上的方法,它不能通过实例来调用,只能通过类本身来调用。静态方法通常用于实现与类本身相关的功能,比如工具类。
-
实例方法:实例对象从原型对象(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` 指向同一个对象。
Object.assign()
执行的是浅拷贝,如果对象的属性值是引用数据类型,那它只拷贝地址。-
如果source或target不是对象,则会先将其转换为一个对象。如果是
null
或undefined,
则会抛出一个TypeError
,因为null
和undefined
不能被转换为对象。 -
如果多个source具有相同的属性,则后面的source会覆盖前面的source中的属性值。
-
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"
-
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)
与 ===
的区别
- 处理
NaN
:Object.is(NaN, NaN)
返回true
,因为按照 ECMAScript 规范,NaN
被视为与自身相等的唯一值。NaN === NaN
返回false
,因为严格相等运算符认为NaN
不等于自身。
- 处理
+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
---------------------------------------------------------------------------------------------------------------------------------
如有不足或遗漏,烦请私信或评论留言