ES6 对象及拓展
一、对象与类
对象(object)是 JavaScript 最重要的数据结构。
类是一种数据类型,是具有相同特性(数据元素)和行为(功能)的对象的抽象。
1. 类和对象的区别
- 类实例化的结果就是对象,类描述了一组有相同特性(属性)和相同行为的对象。
- 类是对象的模板
//定义类
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name)
}
}
let person1 = new Person("张三", 18);
person1.sayName();
let person2 = new Person("李四", 20);
2. 对象定义(声明)的两种方式
2.1 字面量的方式进行定义
var obj = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
2.2 使用 new Object() 进行定义
var obj = new Object();
//定义属性
obj.name = "Tom ";
obj.sex = " man";
obj.age = 19;
//定义方法
obj.run = function(){
console.log("一天跑一公里");
}
二、创建对象的方式
1. 工厂模式
- 使用简单的函数创建对象,为对象添加属性和方法,然后返回对象
// Class 模板
function Person(name,sex,age){
var obj = {};
obj.name = name;
obj.sex = sex;
obj.age = age;
obj.run = function(){
console.log("每天坚持跑步");
}
return obj;
}
// 实例化
var person1 = Person("Tom","sex",19);
//操作
person1.run(); // 输出结果:每天坚持跑步
工厂模式的优缺点:
优点:
1、 在工厂模式中,用户只需要知道所要生产的具体东西,无须关心具体的创建过程,甚至不需要具体产品类的类名。
2、 在系统增加新的产品时,我们只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。
缺点:
1、 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
2. 构造函数模式(new)
- 创建自定义引用类型,可以像创建内置对象实例一样使用new操作符,这种方法的缺点是,构造函数的每个成员都无法复用,每次创建出的对象都只有私有变量和私有方法,不能实现共用
//构造函数(这里就创建了一个Class模板)
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
this.run = function(){
console.log("每天坚持跑步");
}
}
// 实例化 ( new Object())
var person1 = new Person("Tom","man",19);
//操作
person1.run();// 每天坚持跑步
//改造构造函数,把方法抽出来,定义成公共方法
// 构造全局的对象
var action = {
run:function(){
console.log("每天坚持跑步");
}
}
//构造函数
function Person(name,sex,age){
...
this.run = action.run;
}
//实例化
var person1 = new Person("Tom","man",19);
person1.run();
使用new操作符实例化类时,相当于使用new调用其的构造函数。构造流程图如下:
- 创建一个空对象,作为将要返回的对象实例。
- 将这个空对象的原型,指向构造函数的
prototype
属性。- 将这个空对象赋值给函数内部的this关键字。
- 开始执行构造函数内部的代码。(完成赋值等操作)
- 最后返回这个对象。
3. 原型模式
- 使用构造函数的prototype属性来指定共享的属性和方法,即使用构造函数定义实例属性,使用原型定义共享的属性和方法
//构造函数
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
}
//使用原型对象 Object.prototype
Person.prototype.run = function() {
console.log("每天坚持跑步");
}
//实例化
var person1 = new Person("Tom","man",19);
person1.run();// 每天坚持跑步
三、对象的方法
JS对象方法 | 作用 |
---|---|
Object.defineProperty(obj, prop,descriptor) |
定义/修改一个对象中的属性 |
Object.defineProperties(obj.props) |
在一个对象上定义新的属性或修改现有属性,并返回该对象。 |
Object.getOwnPropertyDescriptor(obj,prop) |
获取对象中的一个属性描述 |
Object.freeze(obj) |
冻结一个对象,再也不能被修改 |
Object.isFrozen(obj) |
返回布尔值,判断对象是否被冻结 |
Object.getOwnPropertyNames(obj) |
返回指定对象所有属性,同时也包括不可枚举属性组成的数组(除了Symbol属性) |
Object.getOwnPropertySymbols(obj) |
返回一个给定对象自身的所有Symbol属性的数组 |
Object.isExtensible(obj) |
判断对象是否具备可扩展性,返回布尔值 |
Object.create(obj,propertiesObject)** ** |
创建一个新对象,使用现有对象来提供新创建对象的proto |
Object.isSealed(obj) |
返回boolean, 判断对象是否为封闭对象 |
十九、Object.Seal(obj) |
封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置 |
ES6新增的对象方法 | |
Object.is(Value1 , Value2) |
判断两个值是否为"相同的值" |
Object.assign(target, source1, source2) |
用于对象合并,将源对象(source)所有可枚举属性,复制到目标对象(target) |
Object.getOwnPropertyDescriptors(obj) |
获取目标对象中的所有属性描述 |
Object.setPrototypeOf(obj,property) |
设置一个指定的对象的原型对象 |
Object.getPrototypeOf(obj) |
返回指定对象的原型对象 |
Object.keys(obj) |
获取一个对象中所有的键名key (除了不可枚举属性和Symbol属性) |
Object.values(obj) |
获取一个对象中所有的键值value(除了不可枚举属性和Symbol属性) |
Object.entries(obj) |
获取一个对象中所有的键值对(key和value) |
Object.fromEntries(obj) |
用于将一个键值对数组转为对象。 |
四、判断对象类型
1. typeof
- typeof 常用来判断基本数据类型,无法做到准确的判断对象类型,返回值字符串
function sum(a,b){
return a+b
}
var symbol1 = Symbol("a")
console.log(typeof 42); // "number"
console.log(typeof NaN); // "number"
console.log(typeof Infinity); // "number"
console.log(typeof new String(1)); // "object"
console.log(typeof new Number(1)); //"object"
console.log(typeof String(1)); // "string"
console.log(typeof Number(1)); //"number"
console.log(typeof 'string'); //"string"
console.log(typeof true);//"boolean"
console.log(typeof sum); //"function"
console.log(typeof symbol1);// "symbol"
console.log(typeof null); //"object"
console.log(typeof undefined); // "undefined"
console.log(typeof Array);
console.log(typeof Date);
console.log(typeof Object);
console.log(typeof new Array());
console.log(typeof new Date());
console.log(typeof Object());
console.log(typeof Bigint);
2. instanceof
- ES6新增,为了解决typeof 无法检查出具体对象类型,返回布尔值
- instanceof的本质:检测构造函数(右边)的 prototype 属性是否出现在某个实例对象(左边)的原型链上
// 检查是否属于某个构造函数
function A() {
return "A"
}
var a = new A();
console.log(a instanceof A) // true
var b = {};
console.log(b instanceof Object); //true
var c = [];
console.log(c instanceof Object); //true
console.log(c instanceof Array); //true
console.log( ({a:1}) instanceof Object) // true
let obj = Object.create(null)
console.log(obj instanceof Object) // false
// Object.create(null) 例外
//[].proto 原型是指向Array.prototype的,说明两个对象是属于同一条原型链的,返回true
3. constructor
- 通过constructor来判断数据的类型,但是除了null、undefined,因为他们不是由对象构建。
{1:"1"}.__proto__.contructor === Object; //true
1.__proto__.contructor === Number; // true
[1].__proto__.contructor === Array; // true
4.Object.prototype.toString.call()
- 通过Object.prototype.toString返回对象类型字符串,判断类型
- 建议:加上call() 改变this指向,因为如果在原型上定义了toString方法,this的指向会指向为原型定义的方法,可能达不到预期目的
Object.prototype.toString.call('1') // [object String]
Object.prototype.toString.call(1) // [object Number]
Object.prototype.toString.call([1]) // [object Array]
Object.prototype.toString.call(true) // [object Boolean]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(new Array()); // [object Array]
Object.prototype.toString.call(new Function()); // [object Function]
Object.prototype.toString.call(new Date()); // [object Date]
Object.prototype.toString.call(new Object()); // [object Object]
Object.prototype.toString.call(new RegExp()); // [object RegExp]
Object.prototype.toString.call(new Error()); // [object Error]
五、ES6对象新特性
1. 属性的简洁表示法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
- 如果对象的属性值和属性如果发生重名,我们只写一个属性名即可,他会根据相同的属性名来获取相应的属性值;
- 方法也可以简写。
let birth = '2000/01/01';
const Person = { //大括号里面,直接写入变量和函数,作为对象的属性和方法
name: '张三',
//等同于birth: birth
birth,
// 等同于hello: function ()...
hello() { console.log('我的名字是', this.name); }
};
2. 属性名表达式
// 方法一 用标识符作为属性名,ES5,ES6使用字面量方式定义对象可用
obj.foo = true;
// 方法二 用表达式作为属性名,ES6使用字面量方式定义对象可用
obj['a' + 'bc'] = 123;
3. 方法的 name 属性
- 对象中方法函数里面name隐式属性的值就是方法名
const person = {
sayName() {
//隐式属性name:"sayName"
console.log('hello!');
},
};
person.sayName.name // "sayName"
4. 属性的可枚举性和遍历
可枚举性:对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor
方法可以获取该属性的描述对象。
属性的遍历:
遍历对象属性的方法 | 区别 |
---|---|
for...in |
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性) |
Object.keys(obj) |
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名 |
Object.getOwnPropertyNames(obj) |
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名 |
Object.getOwnPropertySymbols(obj) |
返回一个数组,包含对象自身的所有 Symbol 属性的键名 |
Reflect.ownKeys(obj) |
返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举 |
5. super 关键字(做对象使用)
-
ES6 又新增了另一个类似的关键字
super
,指向当前对象的原型对象。 -
super()
的另一种使用场景:作为函数使用,子类必须在constructor
方法中调用super
方法,继承父类的属性和方法。
6. 对象的扩展运算符
- 扩展运算符是三个点(
...
),将一个数组转为用逗号分隔的参数序列。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
7. AggregateError 错误对象
-
AggregateError
在一个错误对象里面,封装了多个错误。如果某个单一操作,同时引发了多个错误,需要同时抛出这些错误,那么就可以抛出一个 AggregateError 错误对象,把各种错误都放在这个对象里面。 -
AggregateError
本身是一个构造函数,用来生成 AggregateError 实例对象。
-
AggregateError(errors[, message])
的实例对象有三个属性。-
name:错误名称,默认为“AggregateError”。
-
message:错误的提示信息。
-
errors:数组,每个成员都是一个错误对象。
-