文章目录
- Object 应用大集合
- Object 属性应用
- 技术名词解释 object.assign
Object 应用大集合
- 创建对象的方法
- 对象字面量
- 这是最常见的创建对象的方式。例如:
let person = {name: "John",age: 30,greet: function () {return `Hello, my name is ${this.name}`;} };
- 在这里,
{}
用来定义一个对象,对象内部包含属性(name
和age
)和方法(greet
)。属性可以是基本数据类型(如字符串、数字),方法是函数。
- 这是最常见的创建对象的方式。例如:
- 构造函数
- 可以使用构造函数来创建对象。例如:
function Person(name, age) {this.name = name;this.age = age;this.greet = function () {return `Hello, my name is ${this.name}`;}; } let person1 = new Person("Alice", 25);
- 构造函数(这里是
Person
)是一个普通函数,不过按照约定,构造函数的名称首字母大写。使用new
关键字来调用构造函数创建对象。在构造函数内部,this
指向新创建的对象,通过this
可以为对象添加属性和方法。
- 可以使用构造函数来创建对象。例如:
- Object.create()
- 此方法用于创建一个新对象,使用现有对象作为新对象的原型。例如:
let protoObj = {sayHello: function () {return "Hello from prototype";} }; let newObj = Object.create(protoObj);
- 这里
newObj
的原型是protoObj
。如果newObj
本身没有sayHello
方法,JavaScript会在它的原型链中查找(也就是在protoObj
中查找)。
- 此方法用于创建一个新对象,使用现有对象作为新对象的原型。例如:
- 对象字面量
- 访问对象属性和方法的方式
- 点表示法
- 对于上面的
person
对象,可以使用点表示法访问属性和方法。例如:console.log(person.name); console.log(person.greet());
- 这种方式比较直观,适用于属性名是合法的标识符(不包含特殊字符等)的情况。
- 对于上面的
- 方括号表示法
- 当属性名是一个变量或者包含特殊字符时,需要使用方括号表示法。例如:
let propertyName = "age"; console.log(person[propertyName]);
- 或者如果对象有属性名为
"first - name"
这样包含特殊字符的情况,也需要用方括号表示法:let anotherObj = {"first - name": "Bob" }; console.log(anotherObj["first - name"]);
- 当属性名是一个变量或者包含特殊字符时,需要使用方括号表示法。例如:
- 点表示法
- 对象属性的操作方法
- Object.defineProperty()
- 可以用来定义一个新属性或者修改现有属性的特性。例如:
let obj = {}; Object.defineProperty(obj, "prop", {value: 42,writable: false,enumerable: true,configurable: false });
- 这个方法接受三个参数:要定义属性的对象(
obj
)、属性名(prop
)和一个描述符对象。描述符对象可以包含属性的值(value
)、是否可写(writable
)、是否可枚举(enumerable
)和是否可配置(configurable
)等特性。
- 可以用来定义一个新属性或者修改现有属性的特性。例如:
- Object.defineProperties()
- 用于同时定义多个属性。例如:
let anotherObj = {}; Object.defineProperties(anotherObj, {prop1: {value: "value1",writable: true},prop2: {value: 100,enumerable: true} });
- 第一个参数是要定义属性的对象,第二个参数是一个对象,其中键是属性名,值是属性描述符对象。
- 用于同时定义多个属性。例如:
- Object.getOwnPropertyDescriptor()
- 用于获取指定对象上一个自有属性的描述符。例如:
let myObj = {myProp: "test" }; let descriptor = Object.getOwnPropertyDescriptor(myObj, "myProp"); console.log(descriptor.value); console.log(descriptor.writable);
- 它返回一个对象,包含属性的各种特性(如
value
、writable
、enumerable
和configurable
)。
- 用于获取指定对象上一个自有属性的描述符。例如:
- Object.getOwnPropertyNames()
- 返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组。例如:
let testObj = {a: 1,b: 2 }; Object.defineProperty(testObj, "c", {value: 3,enumerable: false }); let propertyNames = Object.getOwnPropertyNames(testObj); console.log(propertyNames);
- 这里会输出
["a", "b", "c"]
,即使c
属性是不可枚举的。
- 返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组。例如:
- Object.keys()
- 返回一个由一个给定对象的自身可枚举属性组成的数组。例如:
let keyObj = {key1: "value1",key2: "value2" }; let keys = Object.keys(keyObj); console.log(keys);
- 只会输出可枚举属性名,如
["key1", "key2"]
。
- 返回一个由一个给定对象的自身可枚举属性组成的数组。例如:
- Object.defineProperty()
- 对象的继承相关方法
- 原型链继承(隐式继承)
- 在JavaScript中,对象可以通过原型链来实现继承。当访问一个对象的属性或方法时,如果对象本身没有该属性或方法,JavaScript会在它的原型对象中查找。例如:
function Animal() {this.species = "unknown"; } Animal.prototype.eat = function () {return "Eating..."; }; function Dog() {this.breed = "Labrador"; } Dog.prototype = new Animal(); let myDog = new Dog(); console.log(myDog.species); console.log(myDog.eat());
- 这里
Dog
的原型被设置为Animal
的一个实例。所以Dog
的实例myDog
可以访问Animal
原型中的方法eat
和属性species
。
- 在JavaScript中,对象可以通过原型链来实现继承。当访问一个对象的属性或方法时,如果对象本身没有该属性或方法,JavaScript会在它的原型对象中查找。例如:
- Object.getPrototypeOf()
- 用于返回指定对象的原型(内部
[[Prototype]]
属性的值)。例如:let myObj = {}; let proto = Object.getPrototypeOf(myObj); console.log(proto === Object.prototype);
- 对于普通对象,它的原型通常是
Object.prototype
。
- 用于返回指定对象的原型(内部
- Object.setPrototypeOf()
- 可以设置一个对象的原型。例如:
let targetObj = {}; let newProto = {newProp: "new value" }; Object.setPrototypeOf(targetObj, newProto); console.log(targetObj.newProp);
- 这会将
targetObj
的原型设置为newProto
,从而targetObj
可以访问newProto
中的属性。不过,这种方式可能会影响性能,并且在一些情况下可能会导致难以理解的行为,使用时要谨慎。
- 可以设置一个对象的原型。例如:
- 原型链继承(隐式继承)
- 对象的遍历方法
- for…in循环
- 用于遍历对象的可枚举属性。例如:
let loopObj = {a: 1,b: 2,c: 3 }; for (let key in loopObj) {console.log(key + ": " + loopObj[key]); }
- 它会遍历对象
loopObj
的所有可枚举属性,key
是属性名,loopObj[key]
是属性值。注意,for...in
循环也会遍历对象原型链上的可枚举属性,除非使用hasOwnProperty
方法来过滤。
- 用于遍历对象的可枚举属性。例如:
- Object.entries()
- 返回一个给定对象自身可枚举属性的
[key, value]
数组。例如:
输出let entriesObj = {name: "Mike",age: 35 }; let entries = Object.entries(entriesObj); console.log(entries);
[["name", "Mike"], ["age", 35]]
。可以使用for...of
循环来遍历这个数组:for (let [key, value] of Object.entries(entriesObj)) {console.log(key + ": " + value); }
- 返回一个给定对象自身可枚举属性的
- Object.values()
- 返回一个给定对象自身可枚举属性值的数组。例如:
输出let valuesObj = {x: 10,y: 20 }; let values = Object.values(valuesObj); console.log(values);
[10, 20]
。
- 返回一个给定对象自身可枚举属性值的数组。例如:
- for…in循环
这只是JavaScript中与对象相关的部分主要函数和方法,它们在处理对象、实现面向对象编程风格以及数据结构等方面都有重要的作用。
Object 属性应用
- 判断对象是否具有某个属性
hasOwnProperty
方法- 这是
Object.prototype
的一个方法,用于判断对象自身(不包括原型链)是否具有指定的属性。例如:let person = {name: "John",age: 30 }; console.log(person.hasOwnProperty("name")); // true console.log(person.hasOwnProperty("toString")); // false
- 在这个例子中,
person
对象自身有name
和age
属性,所以hasOwnProperty("name")
返回true
。而toString
方法是在Object.prototype
中,不是person
对象自身的属性,所以hasOwnProperty("toString")
返回false
。
- 这是
in
运算符- 用于判断对象(包括原型链)是否具有指定的属性。例如:
let person = {name: "John",age: 30 }; console.log("name" in person); // true console.log("toString" in person); // true
- 这里,因为
name
是person
对象自身的属性,toString
是Object.prototype
中的方法,在person
对象的原型链上,所以"name" in person
和"toString" in person
都返回true
。
- 用于判断对象(包括原型链)是否具有指定的属性。例如:
- 判断对象是否为某个类型或具有某种特征
typeof
运算符- 主要用于判断基本数据类型和函数,但对于对象类型的判断比较有限。例如:
let num = 5; let str = "Hello"; let obj = {}; let func = function () {}; console.log(typeof num); // "number" console.log(typeof str); // "string" console.log(typeof obj); // "object" console.log(typeof func); // "function"
- 注意,
typeof
对于null
值也返回"object"
,这是JavaScript语言的一个历史遗留问题。并且所有对象(如数组、日期对象等)都会返回"object"
,不能精确区分不同类型的对象。
- 主要用于判断基本数据类型和函数,但对于对象类型的判断比较有限。例如:
instanceof
运算符- 用于判断一个对象是否是某个构造函数的实例,也就是判断对象的原型链上是否有指定构造函数的原型。例如:
function Person() {} let person = new Person(); console.log(person instanceof Person); // true
- 但是
instanceof
在跨框架或者复杂的继承场景下可能会有不准确的情况。例如,在一个页面中加载了两个不同的JavaScript框架,它们可能有同名的构造函数,此时instanceof
的判断可能不符合预期。
- 用于判断一个对象是否是某个构造函数的实例,也就是判断对象的原型链上是否有指定构造函数的原型。例如:
Object.prototype.toString.call()
方法- 这是一种比较准确的判断对象类型的方法。例如:
let arr = []; let date = new Date(); let obj = {}; console.log(Object.prototype.toString.call(arr)); // "[object Array]" console.log(Object.prototype.toString.call(date)); // "[object Date]" console.log(Object.prototype.toString.call(obj)); // "[object Object]"
- 它可以精确地区分不同类型的对象,如数组、日期对象、普通对象等,在需要准确判断对象类型的场景下非常有用。
- 这是一种比较准确的判断对象类型的方法。例如:
技术名词解释 object.assign
-
参数介绍
- **
Object.assign()
**方法接受多个参数,第一个参数是目标对象,后面的参数是源对象。它将所有可枚举属性的值从一个或多个源对象复制到目标对象。 - 例如:
let target = { a: 1, b: 2 }; let source1 = { b: 3, c: 4 }; let source2 = { d: 5 }; let result = Object.assign(target, source1, source2); console.log(target); console.log(result);
- 这里
target
是目标对象,source1
和source2
是源对象。最终target
和result
都变为{ a: 1, b: 3, c: 4, d: 5 }
,可以看到源对象中的属性按照顺序依次覆盖目标对象中的同名属性。
- 这里
- **
-
应用场景
- 对象属性合并
- 当需要将多个对象的属性合并到一个对象中时非常有用。例如,在配置对象的场景下,假设有一个默认配置对象和一个用户自定义配置对象,就可以使用
Object.assign()
来合并它们。
let defaultConfig = {theme: "light",fontSize: 16 }; let userConfig = {theme: "dark",fontFamily: "Arial" }; let finalConfig = Object.assign({}, defaultConfig, userConfig); console.log(finalConfig);
- 这里首先创建了一个空对象
{}
作为目标对象,然后将defaultConfig
和userConfig
的属性合并进去,得到最终的配置对象{ theme: "dark", fontSize: 16, fontFamily: "Arial" }
。
- 当需要将多个对象的属性合并到一个对象中时非常有用。例如,在配置对象的场景下,假设有一个默认配置对象和一个用户自定义配置对象,就可以使用
- 浅拷贝对象(部分场景)
- 可以用于简单地复制一个对象的属性到另一个对象,实现浅拷贝。例如:
let original = {a: 1,b: {c: 2} }; let copy = Object.assign({}, original); console.log(copy);
- 不过需要注意,这种浅拷贝对于对象属性中的对象引用,只是复制了引用,而不是深拷贝对象。在这个例子中,
copy.b
和original.b
指向同一个对象。
- 对象属性合并
-
注意事项
- 浅拷贝特性
- 如前面提到的,
Object.assign()
是浅拷贝。如果源对象中的属性值是对象,那么目标对象中的该属性会复制这个对象引用。例如:
let sourceObj = {nested: {value: 10} }; let targetObj = {}; Object.assign(targetObj, sourceObj); sourceObj.nested.value = 20; console.log(targetObj.nested.value);
- 这里
targetObj.nested.value
也会变为20
,因为targetObj.nested
和sourceObj.nested
指向同一个对象。
- 如前面提到的,
- 属性覆盖顺序
- 当源对象中有多个同名属性或者源对象和目标对象有同名属性时,后面的属性会覆盖前面的属性。例如:
let target1 = { a: 1 }; let source3 = { a: 2 }; let source4 = { a: 3 }; Object.assign(target1, source3, source4); console.log(target1.a);
- 最终
target1.a
的值为3
,因为source4
中的a
属性最后覆盖了前面的a
属性值。
- 只拷贝可枚举属性
Object.assign()
只拷贝源对象的可枚举属性。例如:
let nonEnumerableObj = {}; Object.defineProperty(nonEnumerableObj, "hiddenProp", {value: 1,enumerable: false }); let target2 = {}; Object.assign(target2, nonEnumerableObj); console.log(target2.hiddenProp);
- 这里
target2.hiddenProp
是undefined
,因为hiddenProp
是不可枚举属性,没有被Object.assign()
拷贝。
- 浅拷贝特性