多个数据的封装体,用以保存多个数据的容器
一个对象代表现实中的一个事物
用对象统一管理多个数据
JavaScript 基于 prototype,而不是基于类的。
组成
属性:属性名(字符串)和属性值(任意)
方法:属性值为函数的属性
分类
- 内置对象:
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
- 比如:Object、Math、Date、String、Array、Number、Boolean、Function、arguments、error、regexp等。
- 宿主对象:
- 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象。
- 比如 BOM DOM。比如console、document。
- 自定义对象:
- 由开发人员自己创建的对象
- 通过 new 关键字创建出来的对象实例,都是属于对象类型,比如Object、Array、Date等。
Number对象
数字可以私有数据进行初始化
var y = new Number(123);
String对象
通常, JavaScript 字符串是原始值,可以使用字符创建: var firstName = "John"
但我们也可以使用 new 关键字将字符串定义为一个对象: var firstName = new String("John")
var x = "John"; // x是一个字符串
var y = new String("John"); // y是一个对象
typeof x // 返回 String
typeof y // 返回 Object
注释:
- 不要创建 String 对象。它会拖慢执行速度,并可能产生其他副作用
- 原始值字符串虽然没有属性和方法 但是可以调用JavaScript的属性和方法,因为JavaScript会在调用时把原始值当做对象
创建对象
- 对象构造函数创建:
var object = newObject();
- 对象创建方法创建:Object 的 create 方法通过将原型对象作为参数传递来创建一个新对象
var object = Object.create(null);
- 字面量创建:
var object = {};
- 构造器:使用new关键字
function Person(name){
var object = {};
object.name=name;
object.age=21;
return object;
}
var object = new Person("Sudheer");
- new 和不 new的区别
- 如果 new 了函数内的 this 会指向当前这个 person 并且就算函数内部不 return 也会返回一个对象。
- 如果不 new 的话函数内的 this 指向的是 window,获取的是该函数的返回值(所以不return就获取不了对象)
function person(firstname,lastname,age,eyecolor)
{
this.firstname=firstname;
this.lastname=lastname;
this.age=age;
this.eyecolor=eyecolor;
return [this.firstname,this.lastname,this.age,this.eyecolor,this]
}
var myFather=new person("John","Doe",50,"blue");
var myMother=person("Sally","Rally",48,"green");
console.log(myFather) // this 输出一个 person 对象
console.log(myMother) // this 输出 window 对象
- 带有原型的函数构造函数
function Person(){}
Person.prototype.name = "Sudheer";
var object = new Person();
- 类创建(es6)
class Person {
constructor(name) {
this.name = name;
}
}
var object = new Person("Sudheer");
- 单例模式创建:Singleton 是一个只能实例化一次的对象。对其构造函数的重复调用返回相同的实例,这样可以确保它们不会意外创建多个实例。
var object = new function(){
this.name = "Sudheer";
}
访问对象
- 访问属性:
**objectName.propertyName**
:简单但不通用**objectName[propertyName]**
**:**麻烦但通用 可以是变量、属性名包括特殊字符:- 空格
- 访问方法
- 调用:
**objectName.methodName()**
**objectName.methodName**
则只输出整个函数代码
- 调用:
- 计算属性:在创建一个对象时,可以在对象字面量中使用方括号
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {
[fruit]: 5, // 属性名是从 fruit 变量中得到的
};
alert( bag.apple ); // 5 如果 fruit="apple"
- 可选链 ?.:如果可选链 ?. 前面的值为 undefined 或者 null,它会停止运算并返回 undefined。
value?.prop
- 如果 value 存在,则结果与 value.prop 相同,
- 否则(当 value 为 undefined/null 时)则返回 undefined,和直接“.”来说不会报错
- 注意:
- 过度使用会导致代码中的错误在不应该消除的地方消除
- ?.前的变量必须已声明
- 可以用于读取或者删除,但是不能写入
user?.name ="John";//不起作用
- 短路效应:?.左边的部分不存在,就会立刻停止运算(短路效应)
- 变体:
- ?.()
let userAdmin = {
admin() {
alert("I am admin");
}
};
let userGuest = {};
userAdmin.admin?.(); // I am admin
userGuest.admin?.(); // 啥都没发生(没有这样的方法)
- ?.[]
let key = "firstName";
let user1 = {
firstName: "John"
};
let user2 = null;
alert( user1?.[key] ); // John
alert( user2?.[key] ); // undefined
遍历对象
for in
** **for…in 循环中的代码块将针对每个属性执行一次。
for (variable in object)
{执行的代码……}
var person={fname:"John",lname:"Doe",age:25};
for (x in person)
{
txt=txt + person[x];
}
Object.keys
Object.keys() 是 ES5 新增的一个对象方法,该方法返回对象自身属性名组成的数组,它会自动过滤掉原型链上的属性,然后可以通过数组的 forEach() 方法来遍历
另外还有 Object.values() 方法和 Object.entries() 方法,这两方法的作用范围和 Object.keys() 方法类似,因此不再说明
for in 循环和 Object.keys() 方法都不会返回对象的不可枚举属性
如果需要遍历不可枚举的属性,就要用到前面提到的 Object.getOwnPropertyNames() 方法了
Object.keys(obj).forEach((key) => {
console.log(obj[key]) // foo
})
Object.getOwnPropertySymbols
Object.getOwnPropertyNames
Reflect.ownKeys
基本数据类型转换成对象
JS 为我们提供了三个基本包装类:
- String():将基本数据类型字符串,转换为 String 对象。
var num = new Number(3);
- Number():将基本数据类型的数字,转换为 Number 对象。
var str = new String("a");
- Boolean():将基本数据类型的布尔值,转换为 Boolean 对象。
var bool = new Boolean(true);
通过上面这这三个包装类,我们可以将基本数据类型的数据转换为对象。
同样的包装类,每一次调用,都会产生不同的对象(对象地址的唯一性)
对象比数据类型功能强大,但是可能造成错误
- 转换后对象和转换之前对象不全等
- 转换后对象的布尔值都为true
包装类作用
当我们对一些基本数据类型的值去调用属性和方法时,浏览器会临时使用包装类将基本数据类型转换为引用数据类型,这样的话,基本数据类型就有了属性和方法,然后再调用对象的属性和方法;调用完以后,再将其转换为基本数据类型。
var str = 'qianguyihao';
console.log(str.length); // 打印结果:11
// 步骤(1):把简单数据类型 string 转换为 引用数据类型 String,保存到临时变量中
var temp = new String('qianguyihao');
// 步骤(2):把临时变量的值 赋值给 str
str = temp;
// 步骤(3):销毁临时变量
temp = null;
对象转换成布尔值
所有对象类型均为true
对于空对象来说,因为是object类型,因此直接用于if判断条件时就会被转化为true。
但是将空对象{}与布尔值false比较,false转化为0,而空对象{}转化为NaN,由于NaN与任何数都不相等,因此{} == false的判断得到false。
iterable object 可迭代对象
可迭代(Iterable) 对象是数组的泛化。这个概念是说任何对象都可以被定制为可在 for…of 循环中使用的对象。
数组是可迭代的。但不仅仅是数组。很多其他内建对象也都是可迭代的。例如字符串也是可迭代的。
如果从技术上讲,对象不是数组,而是表示某物的集合(列表,集合),for…of 是一个能够遍历它的很好的语法,因此,让我们来看看如何使其发挥作用。
symbol.iterator
- 当
for...of
循环开始,会调用symbol.iterator
方法,该方法必须返回一个iterator迭代器(一个有next方法的对象)且for...of
仅适用于这个被返回的对象 - 当
for...of
循环希望获得下一个数值,就调用这个对象的next方法 - next() 方法返回的结果的格式必须是 {done: Boolean, value: any},当 done=true 时,表示循环结束,否则 value 是下一个值。
let range = {
from: 1,
to: 5
};
// 1. for..of 调用首先会调用这个:
range[Symbol.iterator] = function() {
// ……它返回迭代器对象(iterator object):
// 2. 接下来,for..of 仅与下面的迭代器对象一起工作,要求它提供下一个值
return {
current: this.from,
last: this.to,
// 3. next() 在 for..of 的每一轮循环迭代中被调用
next() {
// 4. 它将会返回 {done:.., value :...} 格式的对象
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// 现在它可以运行了!
for (let num of range) {
alert(num); // 1, 然后是 2, 3, 4, 5
}
let range = {
from: 1,
to: 5,
[Symbol.iterator]() {
this.current = this.from;
return this;
},
next() {
if (this.current <= this.to) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
for (let num of range) {
alert(num); // 1, 然后是 2, 3, 4, 5
}