总结
JavaScript 原生对象:Object。所有其他对象都继承自Object对象。
Object 对象的方法分两类:
- 静态方法:直接定义在 Object 上的方法;
- 实例方法:定义在 Object.prototype 上的方法,所有实例继承。
对象创建的多种方式
// 1. 字面量(最常用)
var obj1 = { name: 'Alice', age: 25 };
// 2. new Object()
var obj2 = new Object();
obj2.name = 'Bob';
// 3. Object.create() — 指定原型
var proto = { greet() { return 'Hello, ' + this.name; } };
var obj3 = Object.create(proto);
obj3.name = 'Charlie';
obj3.greet(); // "Hello, Charlie"
// 4. 构造函数
function Person(name) { this.name = name; }
var obj4 = new Person('Dave');
// 5. ES6 class
class Animal { constructor(type) { this.type = type; } }
var obj5 = new Animal('cat');
属性描述符
每个属性都有描述符来控制其行为:
value:属性值writable:是否可写enumerable:是否可枚举configurable:是否可配置/删除get/set:访问器函数
var obj = {};
Object.defineProperty(obj, 'name', {
value: 'test',
writable: false,
enumerable: true,
configurable: false
});
obj.name = 'changed'; // 严格模式报错,非严格模式静默失败
obj.name; // "test"
Object.getOwnPropertyDescriptor(obj, 'name');
// { value: "test", writable: false, enumerable: true, configurable: false }
访问器属性:
var person = {
_age: 25,
get age() { return this._age; },
set age(val) {
if (val < 0 || val > 150) throw new Error('Invalid age');
this._age = val;
}
};
person.age = 30; // OK
person.age = -1; // Error
原型链
每个对象有内部链接指向原型,层层向上直到 null。
function Foo() { this.x = 1; }
Foo.prototype.y = 2;
var obj = new Foo();
obj.x; // 1(自身属性)
obj.y; // 2(原型上)
obj.toString; // function(来自 Object.prototype)
// 原型链:obj -> Foo.prototype -> Object.prototype -> null
Object.getPrototypeOf(obj) === Foo.prototype; // true
Object.getPrototypeOf(Foo.prototype) === Object.prototype; // true
Object.getPrototypeOf(Object.prototype) === null; // true
对象属性操作
var obj = { a: 1, b: 2 };
// delete:只能删除自身属性
delete obj.a; // true
delete obj.toString; // true(但无效,toString 是继承的)
// in:检查属性是否存在(含继承)
'b' in obj; // true
'toString' in obj; // true
// hasOwnProperty:只检查自身属性
obj.hasOwnProperty('b'); // true
obj.hasOwnProperty('toString'); // false
对象遍历方法对比
var parent = { inherited: true };
var obj = Object.create(parent);
obj.a = 1;
obj.b = 2;
Object.defineProperty(obj, 'c', { value: 3, enumerable: false });
| 方法 | 自身 | 继承 | 不可枚举 | 返回值 |
|---|---|---|---|---|
| for…in | 是 | 是 | 否 | - |
| Object.keys() | 是 | 否 | 否 | 键数组 |
| Object.values() | 是 | 否 | 否 | 值数组 |
| Object.entries() | 是 | 否 | 否 | [键,值] |
| getOwnPropertyNames() | 是 | 否 | 是 | 键数组 |
// for...in 遍历自身 + 继承的可枚举属性
for (var key in obj) { console.log(key); } // "a", "b", "inherited"
// 只遍历自身属性
for (var key in obj) {
if (obj.hasOwnProperty(key)) console.log(key); // "a", "b"
}
// Object.keys / values / entries
Object.keys(obj); // ["a", "b"]
Object.values(obj); // [1, 2]
Object.entries(obj); // [["a", 1], ["b", 2]]
// 含不可枚举属性
Object.getOwnPropertyNames(obj); // ["a", "b", "c"]
对象解构
var user = { name: 'Alice', age: 25, city: 'Shanghai' };
// 基本解构
var { name, age } = user;
// 重命名
var { name: userName } = user; // userName === 'Alice'
// 默认值
var { country = 'China' } = user;
// 剩余属性
var { name, ...rest } = user; // rest === { age: 25, city: 'Shanghai' }
// 嵌套解构
var data = { info: { title: 'Hello' } };
var { info: { title } } = data; // title === 'Hello'
// 函数参数解构
function greet({ name, greeting = 'Hello' }) {
return `${greeting}, ${name}!`;
}
greet({ name: 'Bob' }); // "Hello, Bob!"
浅拷贝与深拷贝
var original = { name: 'test', nested: { x: 1 }, arr: [1, 2] };
// 浅拷贝
var shallow1 = Object.assign({}, original);
var shallow2 = { ...original };
// 问题:嵌套对象仍是引用
shallow1.nested.x = 99;
original.nested.x; // 99(被修改了)
// 深拷贝方案1:JSON(不支持 function/undefined/Symbol/循环引用)
var deep1 = JSON.parse(JSON.stringify(original));
// 深拷贝方案2:structuredClone(现代浏览器,支持循环引用)
var deep2 = structuredClone(original);
// 深拷贝方案3:递归实现
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
var clone = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key]);
}
}
return clone;
}
常用静态方法
var obj = { a: 1, b: 2, c: 3 };
// Object.keys / values / entries
Object.keys(obj); // ["a", "b", "c"]
Object.values(obj); // [1, 2, 3]
Object.entries(obj); // [["a",1], ["b",2], ["c",3]]
// Object.assign(浅合并)
Object.assign({}, { a: 1 }, { b: 2 }); // { a: 1, b: 2 }
// Object.freeze / seal / preventExtensions
Object.preventExtensions(obj); // 不能添加新属性
Object.seal(obj); // 不能添加/删除,不能重配置
Object.freeze(obj); // 完全冻结
// Object.create(指定原型)
var bare = Object.create(null); // 无原型的纯净对象
'toString' in bare; // false
实例方法
// toString:判断类型的利器
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(/re/); // "[object RegExp]"
// hasOwnProperty
var obj = { a: 1 };
obj.hasOwnProperty('a'); // true
obj.hasOwnProperty('toString'); // false
// isPrototypeOf
var proto = { x: 1 };
var child = Object.create(proto);
proto.isPrototypeOf(child); // true
// valueOf:类型转换时默认调用
var obj = { valueOf() { return 42; } };
obj + 1; // 43