JavaScript对象指南:从新手到轻松掌握
前言
你好,我是刚入门的前端萌新,正在学习JavaScript。今天我想和大家分享我学习JavaScript对象的心得体会,希望能帮助到同样在学习路上的小伙伴们。
一、初识对象:万物皆对象的JavaScript世界
在JavaScript中,万物皆对象。这句话可能有点夸张,但确实说明了对象在JS中的重要地位。
1.1 两种主要类型
// 1. 原始类型(基本类型)
const str = 'hello' // string
const num = 123 // number
const bool = true // boolean
const und = undefined // undefined
const nul = null // null
const sym = Symbol('id') // Symbol
const big = 123n // bigInt
// 2. 引用类型(本质上都是对象)
const func = function() {} // function(特殊对象)
const arr = [1, 2, 3] // array(特殊对象)
const obj = { name: '玉米' } // object
二、创建对象的三种方式
想创建一个对象?JavaScript给你准备了三种方法,从简单到复杂,总有一款适合你。
2.1 对象字面量(最常用)
// 直接使用大括号创建
const person = {
name: '玉米',
age: 18,
sayHello: function() {
console.log(`大家好,我是${this.name}`)
}
}
console.log(person.name) // 玉米
person.sayHello() // 大家好,我是玉米
2.2 new Object()构造函数
const obj = new Object() // 创建一个空对象
obj.name = '玉米'
const abc = 'age'
obj[abc] = 18 // 使用变量作为属性名
obj['job'] = '前端开发' // 使用字符串作为属性名
console.log(obj) // { name: '玉米', age: 18, job: '前端开发' }
// 动态操作属性
delete obj[abc] // 删除age属性
console.log(obj) // { name: '玉米', job: '前端开发' }
2.3 自定义构造函数(批量创建)
看到这里你可能觉得:这两种方法都挺简单的嘛,一个个创建不就完了?别急,当你需要创建的对象数量从几个变成几十个、几百个时,问题就来了。
三、构造函数:批量生产对象的工厂
3.1 为什么需要构造函数?
让我给你讲个真实的故事。上个月我实习时,老板让我处理公司员工数据。一开始我觉得很简单:
// 我的第一版“解决方案”
function createEmployee(name, age, position) {
const emp = {
name: name,
age: age,
position: position,
company: '掘金科技',
joinDate: '2024-01-15'
}
return emp
}
// 创建几个员工
const emp1 = createEmployee('张三', 25, '前端开发')
const emp2 = createEmployee('李四', 28, '后端开发')
const emp3 = createEmployee('王五', 30, '产品经理')
// 然后一个个处理
console.log(emp1.name, emp1.position)
console.log(emp2.name, emp2.position)
console.log(emp3.name, emp3.position)
// ... 还有97个要写!
第一天我还干劲十足,到第三天我就崩溃了。想象一下:你要手动创建100个员工对象,每个都要单独处理,代码写到手软,debug调到眼花。
这时候我导师走过来看了一眼,说了句:“你这是在手工作坊里搞工业生产啊!”
3.2 “自动化工厂”拯救生产力
导师给我展示了真正的“工业级”解决方案——构造函数。
// 这就是我们的“自动化工厂”
function Employee(name, age, position) {
// new操作符在这里扮演“自动化流水线”的角色
this.name = name
this.age = age
this.position = position
this.company = '掘金科技'
this.employeeId = 'JUEJIN' + Date.now() + Math.random().toString(36).substr(2, 9)
this.introduce = function() {
return `我是${this.name},${this.position},工号${this.employeeId}`
}
this.work = function(task) {
return `${this.name}正在处理:${task}`
}
}
// 现在创建100个员工?小菜一碟!
const employeeList = []
const positions = ['前端开发', '后端开发', 'UI设计', '产品经理', '测试工程师']
for (let i = 0; i < 100; i++) {
const randomPosition = positions[Math.floor(Math.random() * positions.length)]
const age = 22 + Math.floor(Math.random() * 15)
employeeList.push(
new Employee(`员工${i + 1}`, age, randomPosition)
)
}
// 批量操作才是真正的快乐!
console.log(`=== 掘金科技员工系统 ===`)
console.log(`员工总数:${employeeList.length}人`)
// 统计各部门人数
const deptStats = {}
employeeList.forEach(emp => {
deptStats[emp.position] = (deptStats[emp.position] || 0) + 1
})
console.log('各部门人数统计:')
for (const [dept, count] of Object.entries(deptStats)) {
console.log(`${dept}: ${count}人`)
}
// 找出所有前端开发人员
const frontendDevs = employeeList.filter(emp => emp.position === '前端开发')
console.log(`\n前端开发团队(${frontendDevs.length}人):`)
frontendDevs.slice(0, 5).forEach(emp => {
console.log(` ${emp.introduce()}`)
})
从“手工小作坊”到“自动化工厂”,我的生产力直接提升了10倍!原来要写几天的代码,现在几分钟就搞定了。
3.3 构造函数和普通函数的区别
当一个函数被 new 调用时,它就成为了构造函数:
function Car(color) {
this.name = 'su7'
this.height = '1400'
this.color = color
}
// 使用new:构造函数模式
const car1 = new Car('purple')
console.log(car1) // Car { name: 'su7', height: '1400', color: 'purple' }
// 不使用new:普通函数调用
const car2 = Car('purple')
console.log(car2) // undefined(因为没有返回值)
console.log(window.name) // 'su7'(this指向了window)
四、new关键字的神秘面纱
4.1 new到底做了什么?
// new关键字背后的秘密
function Person(name) {
// 1. new会创建一个空对象,并让this指向它
// const this = {}
// 2. 执行构造函数代码
this.name = name
// 3. 返回this对象
// return this
}
// 手动模拟new的过程
function person(name) {
const _this = {} // 第1步:创建空对象
_this.name = name // 第2步:添加属性
return _this // 第3步:返回对象
}
const obj = person('玉米')
console.log(obj) // { name: '玉米' }
4.2 更复杂的模拟
function myNew(constructor, ...args) {
// 1. 创建一个空对象,并继承构造函数的原型
const obj = Object.create(constructor.prototype)
// 2. 执行构造函数,绑定this到新对象
const result = constructor.apply(obj, args)
// 3. 如果构造函数返回对象,则返回该对象,否则返回新对象
return typeof result === 'object' && result !== null ? result : obj
}
// 测试
function Student(name, grade) {
this.name = name
this.grade = grade
}
const stu = myNew(Student, '小明', '一年级')
console.log(stu) // Student { name: '小明', grade: '一年级' }
五、包装类:原始类型的"临时对象外套"
5.1 什么是包装类?
学习过程中我还遇到一些有趣的细节,比如包装类这个“魔术师”:
// 看起来是普通的字符串
const greeting = 'hello world'
// 但它居然有“方法”!
console.log(greeting.toUpperCase()) // HELLO WORLD
console.log(greeting.length) // 11
// 其实JavaScript在背后偷偷做了这些:
// 1. 临时创建一个String对象:new String('hello world')
// 2. 调用这个对象的方法
// 3. 用完就扔掉这个临时对象
// 所以下面这种情况就会出现
greeting.customProp = 'test' // 临时对象被添加属性
console.log(greeting.customProp) // undefined - 临时对象已经消失了
这种“临时工”机制,虽然有时让人困惑,但也体现了JavaScript的灵活性。
5.2 包装类的陷阱
// 错误示范:忘记写new
function Person(name) {
this.name = name
}
const p1 = Person('小明') // 没有new,this指向全局!
console.log(p1) // undefined
console.log(window.name) // 小明(浏览器环境)
// 正确做法:要么记得new,要么用严格模式
function Person(name) {
'use strict'
this.name = name
}
// 现在如果忘记new,就会直接报错
5.3 我的最佳实践
// 1. 构造函数命名用大驼峰
function Employee(config) {
// 2. 支持传入配置对象
this.name = config.name
this.age = config.age
// 3. 设置默认值
this.status = config.status || '在职'
}
// 4. 批量创建时使用数组方法
const employees = Array.from({length: 50}, (_, i) => {
return new Employee({
name: `员工${i + 1}`,
age: 22 + (i % 10),
status: i % 20 === 0 ? '离职' : '在职'
})
})
最后
学习JavaScript对象时,我最大的体会是:多写代码,多尝试。刚开始我也被构造函数、包装类这些概念搞得头晕,但通过实际写代码、调试、看结果,慢慢就理解了。
希望这篇文章对你有帮助!如果有任何问题或建议,欢迎在评论区交流。我们一起进步!