【JavaScript】JS 对象
该随笔是一篇关于 JS 对象学习笔记,学习网站是w3school。
有些地方感觉不够具体,所以添加了些细节,辅助笔者进一步理解。
创建 JS 对象
对象文字方法
最简答的方法(推荐)
通过一对花括号包含的名称:值对集合创建对象。
var person = {
name: "Xiao Ming",
gender: "male",
age: 20,
greet: funcion(){
retrun "Hello!"
}
};
new 关键词创建
var person = new Object();
person.name = "Xiao Ming";
person.gender = "male";
person.age = 20;
person.greet = () => "Hello";
通过类创建对象
class Person {
constructor(name, gender, age){
this.name = name;
this,gender = gender;
this.age = age;
}
greet() {
return "Hello";
}
}
const person = new Person("Xiao Ming", "male", 20);
Object.create()
在 ECMAScript 5 中,也可以通过函数 Object.create() 来创建对象。
Object.create(proto, [propertiesObject])
JS 对象属性
JavaScript 对象可以说是由属性组成的,因为方法能看作是包含函数定义的属性。
属性可以被修改、添加、删除,但是某些属性是只读的。
访问属性
访问属性的途径有:
objectName.property //person.name
//或
objectName["property"] //person["name"]
//或
objectName[expression] //exp = "name"; person[exp] 表达式必须计算为属性名
for...in 遍历对象属性:
const person = {name: "Xiao Ming", gender: "male", age: 20}
let str = "";
for(let prop in person) {
str += person[prop] + " ";
}
添加新属性
通过简单的赋值,向已存在的对象添加新属性:
var person = {name: "Xiao Ming", gender: "male"}
person.age = 20;
注:避免使用 JavaScript 预留词命名属性
删除属性
通过 delete
关键词删除对象属性
var person = {name: "Xiao Ming", gender: "male", age: 20}
delete person.age; //person.age 变为 undefined
delete
关键词会同时删除属性值和属性本身。
不应该删除预定义的 JavaScript 对象属性,否则程序会崩溃。
特性
所有属性都有名称。此外它们还有值。
值是属性的特性之一。
其他特性包括:可列举、可配置、可写。
这些特性定义了属性被访问的方式(是可读的还是可写的?)
在 JavaScript 中,所有属性都是可读的,但是只有值是可修改的(只有当属性为可写时)。
(ECMAScript 5 拥有获取和设置所有属性特性的方法)
原型属性
JavaScript 对象继承了它们的原型的属性。
delete 关键词不会删除被继承的属性,但是如果您删除了某个原型属性,则将影响到所有从原型继承的对象。
JS 对象方法
JavaScript 方法是能够在对象上执行的动作。
JavaScript 方法是包含函数定义的属性。
创建对象方法
var objectName = {
methodName : function() {
//code
}
};
访问对象方法
objectName.methodName()
把 methodName() 描述为 objectName 对象的方法,把 methodName 描述为属性。
methodName 属性在被通过 () 调用后会以函数形式执行。
var person = {
greet : function() {
return "Hello";
}
};
person.greet(); //访问方法 返回 Hello
person.greet; //返回函数定义 function() { return "Hello"; }
添加新的方法
通过简单的赋值即可
person.eat = (food) => return "eat" + food;
JS 对象显示
显示 JavaScript 对象将输出 [object Object]。
显示 JavaScript 对象的一些常见解决方案是:
- 按名称显示对象属性(
objectName.prop
) - 循环显示对象属性(
for...in
) - 使用
Object.values()
显示对象 - 使用
JSON.stringify()
显示对象
其中前两个方案前面章节已经介绍过了。
使用 Object.values()
通过使用 Object.values()
,任何 JavaScript 对象都可以被转换为数组:
const person = {name:"Xiao Ming", gender:"male", age:20};
const myArray = Object.values(person); //["Xiao Ming", "male", 20]
使用 JSON.stringify()
任何 JavaScript 对象都可以使用 JavaScript 函数 JSON.stringify() 进行字符串化(转换为字符串):
const person = {name:"Xiao Ming", gender:"male", age:20};
//结果将是一个遵循 JSON 标记法的字符串:
let myString = JSON.stringify(person); //{"name":"Xiao Ming","gender":"male","age":20}
注意:JSON.stringify 不会对方法进行字符串化。
对象访问器
ECMAScript 5 (2009) 引入了 Getter 和 Setter,允许您使用类似于获取或设置属性的语法来定义对象方法。
Getter 和 Setter 允许您定义对象访问器(被计算的属性)。
- getter 是一种获得属性值的方法。当我们去读取属性的值时,调用getter。
- setter是一种设置属性值的方法。当我们去设定或修改属性值时,调用setter。
get && set
本例使用 lang 属性来获取 language 属性的值,本例使用 lang 属性来设置 language 属性的值。
// 创建对象:
var person = {
language : "en",
get lang() {
return this.language.toUpperCase();
},
set lang(lang) {
this.language = lang;
}
};
// 使用 setter 来设置对象属性:
person.lang = "en";
// 使用 getter 来显示来自对象的数据:
document.getElementById("demo").innerHTML = person.lang;
getter/setter 方法的名称不能与属性名称相同。
许多程序员在属性名称前使用下划线字符 _ 将 getter/setter 与实际属性分开:
var person = {
language : "en",
get language() {
return this._language.toUpperCase();
},
set language(lang) {
this._language = lang;
}
};
为什么使用 Getter 和 Setter?
- 它提供了更简洁的语法
- 它允许属性和方法的语法相同
- 它可以确保更好的数据质量
- 有利于后台工作
Object.defineProperty()
方法也可用于添加 Getter 和 Setter:
// 定义对象
var person = {language : ""};
// 创建一个 setter 和 getter 来确保语言的大写更新:
Object.defineProperty(person, "language", {
get : function() { return language },
set : function(value) { language = value.toUpperCase()}
});
// 操作计数器:
person.language = "en";
person.language; // 返回 EN
JS 对象构造器
在前面的例子中我们都是只创建了一个对象,但是有时我们需要创建很多相同“类型”的对象,这时候就需要一个对这些相同类别的东西进行抽象,形成一份“蓝图”,然后我们根据这份蓝图批量创建多个相同类型的对象。
创建“对象类型”的方法是使用对象构造函数,通过 new 关键词调用构造器函数可以创建相同类型的对象:
//用大写首字母对构造器函数命名是个好习惯
function Person(name, age, lang) {
this.name = name;
this.age = age;
this.language = lang;
}
var myFriend = new Person("Bob", 22, "en");
var myBrother = new Person("Jack", 26, "cn");
注:在构造器函数中,this 是没有值的。它是新对象的替代物。 当一个新对象被创建时,this 的值会成为这个新对象。请注意 this 并不是变量。它是关键词。您无法改变 this 的值。
为对象添加属性和方法不会影响到其他对象!
myBrother.nationality = "China";
myFriend.greet = () => "Hello";
myFriend.nationality; // 返回 undefined
myBrother.greet(); // 控制台报错,myBrother.greet is not a function
无法为对象构造器添加新属性和方法:
Person.nationality = "English";
myBrother.nationality; // 返回 undefined;
如需向构造器添加一个新属性和方法,必须在构造器函数内部向一个对象添加:
function Person(name, age, lang) {
this.name = name;
this.age = age;
this.language = lang;
this.nationality = "China"; //这样对象属性就可以拥有默认值。
this.changeAge = (age) => this.age = age;
}
myBrother.nationality; // 返回 China
myBrother.changeAge(28);
myBrother.age; // 返回 28
JavaScript 提供用于原始对象的构造器:
var x1 = new Object(); // 一个新的 Object 对象
var x2 = new String(); // 一个新的 String 对象
var x3 = new Number(); // 一个新的 Number 对象
var x4 = new Boolean(); // 一个新的 Boolean 对象
var x5 = new Array(); // 一个新的 Array 对象
var x6 = new RegExp(); // 一个新的 RegExp 对象
var x7 = new Function(); // 一个新的 Function 对象
var x8 = new Date(); // 一个新的 Date 对象
Math() 对象不再此列。Math 是全局对象。new 关键词不可用于 Math。
正如以上所见,JavaScript 提供原始数据类型字符串、数字和布尔的对象版本。但是并无理由创建复杂的对象。原始值快得多!
var x1 = {}; // 新对象
var x2 = ""; // 新的原始字符串
var x3 = 0; // 新的原始数值
var x4 = false; // 新的原始逻辑值
var x5 = []; // 新的数组对象
var x6 = /()/ // 新的正则表达式对象
var x7 = function(){}; // 新的函数对象
JS 对象原型
所有 JavaScript 对象都从原型继承属性和方法。
日期对象继承自 Date.prototype
。数组对象继承自 Array.prototype
。Person
对象继承自 Person.prototype
。
Object.prototype
位于原型继承链的顶端。
日期对象、数组对象和 Person 对象的继承链最上方是 Object.prototype
。
原型继承
要了解原型链,首先要了解 JS 对象。
JS 对象大致可以分为两类:普通对象和函数对象。
一般而言,通过 new Function 产生的对象是函数对象,其他都是普通对象。
所有的对象,都有一个__proto__
属性,指向构造该对象的构造函数的原型,从而保证了实例能访问构造函数原型中定义的属性和方法(注意是 proto 前后是双下划线)。
JavaScript 规定每个函数都有一个 prototype
属性,这个属性是一个指针,指向原型对象(包含所有实例共享的属性和方法)。
而原型对象也有个 constructor
属性,能指回原构造函数。
先来看下普通对象的原型链:
let parent = {a: 1};
let child = {
b: 2,
__proto__: parent
};
通过对象构造器构造出来的对象的原型链:
function F(a) {
this.a = a;
};
F.prototype.b = 2;
let obj = new F(1);
通过原型链的延续我们可以实现 Js 中的继承,原型链的顶端是 Object.prototype.__proto__
,而 Object.prototype
是一切对象的原型,所以这个对象上所有的属性都能被我们使用,它不能有任何对象为原型,所以递归访问__proto__
的终点Object.prototype.__proto__
等于null。
prototype 属性
JavaScript prototype 属性允许您为对象构造器添加新属性和方法:
function Person(name, age, lang) {
this.name = name;
this.age = age;
this.language = lang;
this.nationality = "China"; //这样对象属性就可以拥有默认值。
this.changeAge = (age) => this.age = age;
}
Person.prototype.nationality = "China";
Person.prototype.chageAge = (age) => this.age = age;
myBrother.nationality; // 返回 China
myBrother.changeAge(28);
myBrother.age; // 返回 28
prototype 可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。
作为一个对象,当你访问其中的一个属性或方法的时候,如果这个对象中没有这个 方法或属性,那么 Javascript 引擎将会访问这个对象的__proto__
属性所指向的对象,并在那个对象中查找指定的方法或属性,如果不能找到,那就会继续通过那个对象 的__proto__
属性指向的对象进行向上查找,直到这个链表结束。
注:请只修改您自己的原型。绝不要修改标准 JavaScript 对象的原型。
JS ES5 对象方法
ECMAScript 5 (2009) 向 JavaScript 添加了许多新的对象方法。
管理对象:
// 以现有对象为原型创建对象
Object.create()
/*
定义对象属性和/或更改属性的值和/或元数据。
*/
Object.defineProperty(object, property, descriptor)
// 添加或更改对象属性
Object.defineProperties(object, descriptors)
// 访问属性
Object.getOwnPropertyDescriptor(object, property)
// 以数组返回所有属性
Object.getOwnPropertyNames(object)
// 访问原型
Object.getPrototypeOf(object)
// 以数组返回可枚举属性
Object.keys(object)
保护对象:
// 防止向对象添加属性
Object.preventExtensions(object)
// 如果属性可以添加到对象,则返回 true
Object.isExtensible(object)
// 防止更改对象属性(不是值)
Object.seal(object)
// 如果对象被密封,则返回 true
Object.isSealed(object)
// 防止对对象进行任何更改
Object.freeze(object)
// 如果对象被冻结,则返回 true
Object.isFrozen(object)
Object.defineProperty()
Object.defineProperty(object, property, descriptor)
能够定义一个对象的新属性,或者修改一个对象已有的属性值,返回这个被处理过的对象。
object
:要操作的对象
property
:object 上要定义或修改的属性
descriptor
:属性描述器,用于定义或修改该属性的特性。
该属性描述器分为两类:数据描述符和存取描述符。
数据描述符:一个具有值的属性,该值可能是可写的,也可能不是可写的。
存取描述符:由getter-setter函数对描述的属性。
描述符必须是这两种形式之一;不能同时是两者,否则报错。
更改元数据:
ES5 允许更改以下属性元数据:
writable : true|false // 属性值是否可更改
enumerable : true|false // 属性是否可枚举
configurable : true|false // 属性是否可重新配置
- 仅为数据描述符:value、writable
value:属性对应的值,可以是任意类型的值,默认为undefined
let person = Object.create(null);
Object.defineProperty(person, "name", {value:"Jack"});
writable:属性的值是否能够被重新赋值,true为可以重新赋值,false为不可以重新赋值,默认为false
注意:writable为false,但是实际去重新赋值了,不报错,值也不改变
Object.defineProperty(person, "name", {writable:true});
person.name = "Bob";
person.name; //返回 Bob
Object.defineProperty(person, "name", {writable:false});
person.name = "Jack";
person.name; //返回 Bob
- 仅为存储描述器:set/get
当设置或获取对象的某个属性的值的时候,可以提供getter/setter方法。
Object.defineProperty(person, "name", {
get : function() { return this.name },
set : function(name) { this.name = name}
});
- 既为数据描述符,又为存储描述符:enumerable、configurable
enumerable:此属性是否可以被枚举(使用 for…in 或 Object.keys())。设置为true可以被枚举;设置为false,不能被枚举。默认为false。
const person = {name:"Jack", gender:"male", age:20, language:""};
// 更改属性:
Object.defineProperty(person, "language", {
value: "EN",
writable : true,
enumerable : false,
configurable : true
});
Object.keys(person); // 返回 name,gender,age
configurable:是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。
let person = {};
Object.defineProperty(person, "name", {
value: "Jack",
configurable: false
});
delete person.name; //不会删除该属性,并且不报错
person.name; //返回 Jack
Object.defineProperty(person, "name", {configurable: true});
delete person.name;
person.name; //返回 undefined
let person = {};
Object.defineProperty(person, "name", {
value: "Jack",
configurable: false
});
//重新修改特性
Object.defineProperty(person, "name", {
value: "Jack",
writable: true,
enumerable: true,
configurable: true
}); //报错 Uncaught TypeError: Cannot redefine property: name
Object.defineProperties()
Object.defineProperties(object, descriptors)
与 Object.defineProperty
相似,只不过该方法可以一次性操作多个属性
let obj = {};
Object.defineProperties(obj, {
"prop1": {
value: "",
writable: true,
enumerable: true
},
"prop2": {
value: "",
writable: true
}
//etc.
});
Object.getOwnPropertyDescriptor(object, property)
该方法返回指定对象上属性的描述符
const person = {name:"Jack", gender:"male", age:20, language:""};
console.log(Object.getOwnPropertyDescriptor(person, "name"));
//控制台打印 {value: 'Jack', writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyNames(object)
Object.getOwnPropertyNames(object)
返回对象所有自己的属性名
const person = {name:"Jack", gender:"male", age:20, language:""};
document.write(Object.getOwnPropertyNames(person)); //返回 name,gender,age,language
Object.keys(object)
和 Object.getOwnPropertyNames(object)
类似,只不过返回对象所有自己的可枚举属性名
const person = {name:"Jack", gender:"male", age:20, language:""};
// 更改属性:
Object.defineProperty(person, "language", {
value: "EN",
writable : true,
enumerable : false,
configurable : true
});
Object.keys(person); // 返回 name,gender,age
Object.getPrototypeOf(object)
const person = {name:"Jack", gender:"male", age:20, language:""};
const student = Object.create(person);
console.log(Object.getPrototypeOf(student));
//控制台打印 person 对象
Object.preventExtensions(object)
该方法让一个对象变的不可扩展,即永远不能再添加新的属性。并且返回原对象。
var obj = {};
var obj2 = Object.preventExtensions(obj);
obj === obj2; //true
Object.isExtensible(obj);
obj.name = "Bob";
console.log(obj.name); //打印 undefined
Object.seal(object)
Object.seal()
方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。
Object.seal()做了哪些事情?
- 设置Object.preventExtension(),禁止添加新属性(绝对存在)
- 设置configurable为false,禁止配置(绝对存在)
- 禁止更改访问器属性(getter和setter)
Object.freeze(object)
Object.freeze()
方法可以冻结一个对象。
一个被冻结的对象再也不能被修改。
冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。
此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
Object.freeze()做了哪些事情?
- 设置Object.preventExtension(),禁止添加新属性(绝对存在)
- 设置writable为false,禁止修改(绝对存在)
- 设置configurable为false,禁止配置(绝对存在)
- 禁止更改访问器属性(getter和setter)
Object.freeze()
只是浅冻结
使用Object.freeze()
冻结的对象中的现有属性是不可变的。用Object.seal()
密封的对象可以改变其现有属性。
JS ECMAScript 2017 对象方法
Object.entries()
方法返回对象中键/值对的数组:
const person = {name:"Jack", gender:"male", age:20};
Object.entries(person); //返回 name,Xiao Ming,gender,male,age,20
//Object.entries() 使循环中使用对象变简单了:
const fruits = {Bananas:300, Oranges:200, Apples:500};
let text = "";
for (let [fruit, value] of Object.entries(fruits)) {
text += fruit + ": " + value + " ";
}
//Object.entries() 也使得将对象转换为映射变得简单:
const myMap = new Map(Object.entries(fruits));
Object.values
类似 Object.entries
,但返回对象值的单维数组:
const person = {name:"Xiao Ming", gender:"male", age:20};
Object.values(person); //Xiao Ming,male,20
JavaScript 对象 Rest 属性
ECMAScript 2018 添加了 Rest 属性。
允许我们破坏一个对象并将剩余物收集到一个新对象上:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }
JS 对象是易变的
先来看下例子:
var person = {
name: "Xiao Ming",
gender: "male",
age: 20
}
var x = person;
x.age = 1; //x.age 和 person.age 均为 1
这是因为对象是通过引用来寻址的。
person 并不是把值都拷贝一份给 x,而是把引用地址拷贝给 x,所以x 和 person 指向了同一个对象。
x 和 person 就像一个人的大名和小名一样,不管哪个名,其实都是本人。
JS Map对象
Map 对象存有键值对,其中的键可以是任何数据类型。
Map 对象记得键的原始插入顺序。
Map 对象具有表示映射大小的属性。
属性
Property | Description |
---|---|
size | 返回Map的大小 |
基本方法
Method | Description |
---|---|
new Map() | 创建新的 Map 对象。 |
set() | 为 Map 对象中的键设置值。 |
get() | 获取 Map 对象中键的值。 |
entries() | 返回一个新的包含 [key, value]的 Iterator对象,按插入顺序 |
keys() | 返回 Map 对象中键的 Iterator对象 |
values() | 返回 Map 对象中值的 Iterator对象 |
其他方法
Method | Description |
---|---|
clear() | 删除 Map 中的所有元素。 |
delete() | 删除由键指定的元素。 |
has() | 如果键存在,则返回 true。 |
forEach() | 为每个键/值对调用回调。 |
// 创建对象
const apples = {name: 'Apples'};
const bananas = {name: 'Bananas'};
const oranges = {name: 'Oranges'};
// 创建新的 Map
const fruits = new Map();
// Add new Elements to the Map
fruits.set(apples, 500);
fruits.set(bananas, 300);
fruits.set(oranges, 200);
/*
或将 Array 传递给 new Map() 构造函数:
const fruits = new Map([
[apples, 500],
[bananas, 300],
[oranges, 200]
]);
*/
//获取 map 的大小
fruits.size; // 返回 3
//map.get(key)
fruits.get(apples); // 返回 500
//map.entries()
let fruitsIterator = fruits.entries();
console.log(fruitsIterator.next().value); //[apples, 500]
console.log(fruitsIterator.next().value); //[bananas, 300]
console.log(fruitsIterator.next().value); //[oranges, 200]
//keys()
fruitsIterator = fruits.keys();
console.log(fruitsIterator.next().value); //apples
console.log(fruitsIterator.next().value); //bananas
console.log(fruitsIterator.next().value); //oranges
//map.values()
fruitsIterator = fruits.values();
console.log(fruitsIterator.next().value); //500
console.log(fruitsIterator.next().value); //300
console.log(fruitsIterator.next().value); //200
//map.forEach()
let txt = "";
fruits.forEach((num,fruit) => (txt += fruit.name + ":" + num + " "));
document.write(txt); //Apples:500 Bananas:300 Oranges:200
//map.delete(key)
console.log(fruits.has(apples)); //true
fruits.delete(apples);
console.log(fruits.has(apples)); //false
//map.clear()
fruits.clear();
fruits.size;// 返回 0
JavaScript 对象 vs Map
JavaScript 对象和 Map 之间的差异:
对象 | Map | |
---|---|---|
Size | 对象没有 size 属性 | Maps 有 size 属性 |
键类型 | 对象键必须是字符串(或符号) | Map 键可以是任何数据类型 |
键顺序 | 对象键没有很好地排序 | Map 键按插入排序 |
默认 | 对象有默认键 | Map 没有默认键 |
JS Set对象
Set 是唯一值的集合。
每个值在 Set 中只能出现一次。
一个 Set 可以容纳任何数据类型的任何值。
属性
Property | Description |
---|---|
size | 返回元素计数 |
方法
Method | Description |
---|---|
new Set() | 创建新的 Set 对象。 |
add() | 向 Set 添加新元素。 |
clear() | 从 Set 中删除所有元素。 |
delete() | 删除由其值指定的元素。 |
entries() | 返回新的 Iterator 对象,包含 [value, value] 给定的每个元素的数组Set,按照插入顺序。 |
has() | 如果值存在则返回 true。 |
forEach() | 为每个元素调用回调。 |
keys() | 返回新的 Iterator 对象,包含 Set 的元素 |
values() | 与 keys() 相同。 |
// 创建 Set
const letters = new Set();
// Add the values to the Set
letters.add("a");
letters.add("b");
letters.add("c");
//或 const letters = new Set(["a","b","c"]);
//如果添加相等的元素,则只会保存第一个元素:
letters.add("a");
letters.size; //3
//map.forEach
letters.forEach(
function(value) {
txt += value + " ";
}
);
document.write(txt); //a b c
//map.entries()
let setIter = letters.entries();
console.log(setIter.next().value); // ["a", "a"]
console.log(setIter.next().value); // ["b", "b"]
console.log(setIter.next().value); // ["c", "c"]
//map.keys() 和 map.values() 结果相同
setIter = letters.values();
console.log(setIter.next().value); // "a"
console.log(setIter.next().value); // "b"
console.log(setIter.next().value); // "c"
//map.has(value)
letters.has("a"); //true
//map.delete(value)
letters.delete("a");
letters.has("a"); //false
//map.clear()
letters.clear();
letters.size; //0
本文来自博客园,作者:hzyuan,转载请注明原文链接:https://www.cnblogs.com/hzyuan/p/15900962.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)