IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 【红宝书】第8章:对象、类和面向对象编程(一)理解对象 -> 正文阅读

[JavaScript知识库]【红宝书】第8章:对象、类和面向对象编程(一)理解对象

ECMA-262将对象定义为:一组属性的无序集合。 我们可以把JS中的对象想象成一张散列表,其中的内容就是一组键值对,值的类型可以是数据或者函数。

一、理解对象

创建自定义对象的通常方式是 new 一个 Object 的新实例,然后再给这个实例添加属性和方法。

let person = new Object();
person.name = 'Macc';
person.age = 18;
person.sayHi = function(){
    console.log('hi');
}

?现在更流行的是对象字面量方式定义对象

//对象字面量
let person = {
    name:'Macc',
    age:16,
    sayHi:function(){
        console.log('hi');
    }
}

上面两个对象的属性和方法都一样,可视为两者是等价的(注意,是等价而不是相同或者说是同一个对象)。

对象的属性都有自己的特征,而这些特征决定了它们在JS中的行为。

(一)属性的类型

ECMA-262用一些内部特性来描述属性的特征。既然是内部特性,也就是说开发者在JS中是不能直接访问这些特性的。

规范使用两个中括号括住特性的名称,以此来标识其为内部特性。例如:[[Enumberable]]

对象的属性分为两种:数据属性和访问器属性。

1.数据属性

数据属性有4个特性描述其行为

特性名称作用默认值
[[Configurable]]表示属性是否可通过 delete 删除并重新定义,是否可以修改属性的特性,是否可以把属性类型改为访问器属性。true
[[Enumberable]]属性是否可以通过 for-in 循环返回。true
[[Writable]]属性的值是否可以被修改。true
[[value]]属性实际值的存放位置,读取和写入属性值的都是操作这个位置。undefined

修改默认(内部)特性

上面提到过,开发者在js中是无法直接访问内部特性的。所以要修改属性的内部特性,必须要使用 Object.defineProperty() 方法。

Object.defineProperty(obj,‘propertyName’,decriptionObj)方法
参数名参数类型描述
objObject要添加/修改属性的对象
propertyNameString要添加或修改的属性的名称
decriptionObjObject描述符对象

描述符对象上的属性可以包含4个内部特性名称(即以内部特性的名称为属性名)。

let person = {};//定义一个person对象
//给对象添加属性
Object.defineProperty(person,'name',{
    writable:false, //属性值不可修改
    value:'Macc'  //属性的实际值
});
console.log(person.name);//访问属性值,输出'Macc'
person.name = 'GaGa';//尝试修改属性的值
console.log(person.name);//输出'Macc'

因为person对象的name属性的内部特性writable被改为false了,表示属性的值不可以被修改,因此后面尝试将其改为GaGa的时候,修改行为被忽略(在严格模式下会报错),依旧输出原值。

若把属性的configurable属性设为false,则不能再改回true,此时再调用Object.defineProperty()方法并修改任何非writable属性都会报错。

调用Object.defineProperty()时,configurable、enumerable、writable的值,若不指定,默认为false

let person = {
    name: 'Macc',
    age: 18
}
Object.defineProperty(person, 'hair', {
    value: 'black',
    //未指定其他值,其他值默认为false
});

let _p = Object.getOwnPropertyDescriptor(person, 'hair');
console.log(_p);

image.png

2.访问器属性

访问器属性不包含数据值。

访问器属性包含一个获取函数getter和一个设置函数setter

  • 在读取访问器属性时,会调用gettergetter的责任是return一个有效值。
  • 在写入访问器属性时,会调用setter并传入新值,setter决定对数据(属性的值)做什么修改。

访问器属性也有4个特性描述其行为

特性名称作用默认值
[[Configurable]]表示属性是否可通过 delete 删除并重新定义,是否可以修改属性的特性,是否可以把属性类型改为数据属性。true
[[Enumberable]]属性是否可以通过 for-in 循环返回。true
[[Get]]getter,在读取属性时调用。undefined
[[Set]]setter,在写入属性时调用。undefined

?修改访问器属性也要使用Object.defineProperty()方法。

let book = {
    year_: 2017,//私有成员
    edition: 1  //公共成员
}
Object.defineProperty(book, 'year', {
    get() {
        return this.year_;
    },
    set(newValue) {
        if (newValue > 2017) {
            this.year_ = newValue;
            this.edition = newValue - 2017;
        }
    }
});

book.year = 2018;
console.log(book.edition); //输出2

上面代码就是访问器属性的典型使用场景:设置一个属性的值会导致一些其他变化的发生

gettersetter 不一定都要定义:

  • 只定义getter 意味着属性是只读的,尝试修改属性会被忽略;
  • 只定义setter 在非严格模式下读取属性会返回 undefined

ES5之前没有 Object.defineProperty()方法。

3.同时定义多个属性

使用 Object.defineProperties(obj,descriptionObj)方法

参数名参数类型描述
objObject要添加/修改属性的对象
decriptionObjObject描述符对象
let person = {}
Object.defineProperties(person, {
    name: {
        value: 'Macc'
    },
    age: {
        value: 18
    },
    hair: {
        get() {
            return 'black';
        },
        set(newValue) {
            //....
        }
    }
});

4.读取属性的特性

4.1 读取属性的某个特性

使用方法 Object.getOwnPropertyDescriptor(属性所在对象,属性名称),该方法 return 一个对象。

4.2 读取对象的全部自有属性的特性

使用方法 Object.getOwnPropertyDescriptors(对象),该方法也 return 一个对象,对象包括指定对象的所有自有属性的特性,若对象没有属性,则返回一个空对象。

该方法实际上是在每个自有属性上调用 Object.getOwnPorpertyDescriptor() 方法并在一个新对象中返回它们。

(二)合并对象

把源对象的所欲本地属性一起复制到目标对象上,这种操作叫做合并(merge),也叫做混入(mixin)

合并对象使用的方法是 Object.assign(目标对象,源对象1, ... ,源对象n)
该方法会将源对象中的所有可枚举属性和自有属性复制到目标对象上。

所谓的可枚举属性指的是调用Object.prpertyIsEnumerable()返回true的属性;
所谓的自有属性指的是调用Object.hasOwnProperty()返回true的属性;

复制过程中,会使用源对象上的 [[Get]] 取得属性值,再使用目标对象上的 [[Set]] 设置属性的值。

Object.assign() 执行的是浅复制,只复制对象的引用。

若多个源对象有相同属性,则使用最后一个复制的值(即哪个源对象靠后就使用哪个的值)(覆盖

不能在两个对象之间转移getter函数和setter函数。 从源对象访问器属性中取得的值比如getter函数,会作为一个静态的值赋值给目标对象。

若是在赋值期间出错,则操作中止并退出,抛错。但是该方法不会回滚,它是一个尽力而为,可能只完成部分复制的方法。

(三)对象标识及相等判定

在ES6之前,存在使用全等符(===)也无能为力的情况:

  1. 符合预期的情况如下
表达式结果
true === 1false
{} === {}false
"2" === 2false

2.不同js引擎表现不同,但仍被认为相等

表达式结果
+0 === -0true
+0 === 0true
-0 === 0true
  1. 要确定 NaN 的相等性必须使用 isNaN 函数
表达式结果
NaN === NaNfalse
isNaN(NaN)true

在ES6中新增了方法 Object.is() ,该方法与全等符相似,但是考虑了上述的边界条件。该方法必须接收两个参数。

表达式结果
Object.is(+0,-0)false
Object.is(+0,0)true
Object.is(-0,0)false
Object.is(NaN,NaN)true

如果要使用 Object.is() 检查超多两个值,可以递归的利用相等性实现:

function recursivelyCheckEqual(x, ...rest) {
    return Object.is(x, rest[0]) &&
        (rest.length < 2 || recursivelyCheckEqual(...rest));
}

console.log(recursivelyCheckEqual(1, 2, 3, 4)); //false

(四)增强的对象语法(语法糖)

1.属性值的简写

简写属性值只要使用变量名就会自动被解释为同名属性键,若是未找到同名的变量,则抛错。

let name = 'Macc',
    age = 18;
let person = {
    name,  //简写
    //下面是以前的写法
    age:age
};
console.log(person);//{name:"Macc",age:18}

2.可计算属性

在引入可计算属性前,如果想使用变量值作为属性(名),必须先声明对象,再使用中括号语法来添加属性。也即是说,不可以在对象字面量中直接动态命名属性。

const nameKey = 'name';
let person = {};//先声明对象
person[nameKey] = 'Macc';//使用中括号语法添加属性

在引入可计算属性后,就可以在对象字面量中完成动态属性赋值了。

let person = {
    [nameKey]:'Macc'
}

可计算属性表达式中抛出任何错误都会中断对象的创建,且不回滚。

const nameKey = 'Macc';
const ageKey = 'age';

let person = {
    [nameKey]: 'Macc',
    [jobKey]: '码农', //这里会出错
    [ageKey]: 18
}
console.log(person);//这里是打印不出来的,因为对象的创建被中断了。

3.简写方法名

在此之前,给对象定义方法的时候,是以下格式:

let person = {
    //方法名 冒号 匿名函数表达式
    sayHi:function(){
        //...
    }
}

现在则是:

let person = {
    sayHi(){
        //...
    }
}

而且,简写方法名与可计算属性相互兼容。

const methodKey = 'sayHi';
let person = {
    [methodKey](name){
        //...
    }
}

(五)对象解构

在一条语句中使用嵌套数据实现一个或多个赋值操作。
简而言之就是,使用与对象 匹配的结构来实现对象属性的赋值。

匹配的结构:就有点对号入座的味道。

  1. 可以使用简写语法
let person = {
    name:'Macc',
    job:'码农'
};
let {name,job} = person;
console.log(name,job);//Macc,码农
  1. 解构赋值不一定与对象的属性匹配(赋值时可以忽略某些属性,无需一一对应)
let {name,age} = person;//无需一一对应
console.log(name,age);//"Macc",undefined
  1. 可在解构赋值的同时设定默认值
let {name,age:18} = person;
console.log(name,age);//"Macc",18

解构在内部使用了 ToObject() 方法把源数据解构转换为对象,也就是说在对象解构上下文中,原始值会被当成对象null和undefined不能被解构,否则报错。

let { _ } = null;//报错
let { _ } = undefined;//报错

image.png

解构不要求变量必须在解构表达式中声明,但是如果给事先声明过的变量赋值,则表达式必须包在一对小括号中。

let personName,personAge;//事先声明变量
({name:personName,age:personAge} = person);

1.嵌套解构

首先是可以使用解构来复制对象的属性:

let person = {
    name: 'Macc',
    age: 18,
};

let personCopy = {}; //这里这个分号一定要记得加,不然报错

({ name: personCopy.name, age: personCopy.age } = person);
console.log(personCopy);
//{name: 'Macc', age: 18}

然后想一想,假如被复制的属性是个嵌套结构呢?解构还能用吗?答案是可以的,解构赋值可以使用嵌套结构,但是外层属性未定义时,不能使用。

let person = {
    job: {
        title: '码农'
    }
};

let personCopy = {}; //这里这个分号一定要记得加,不然报错

let { job: { title } } = person;
console.log(title); //码农

//foo在源对象上undefined未定义,报错
({ foo: { bar: person.bar } } = person);
//job在源对象上undefined未定义,报错
({ job: { title: person.job.title } } = person);

2.部分解构

如果一个解构表达式设计多个赋值操作,开始的赋值成功而后面的赋值出错,则整个解构赋值只会完成一部分

3.参数上下文匹配

在函数参数列表中也可以进行解构赋值,且不会影响到 arguments 对象。

let person = {
    name: 'Macc',
    age: 18
};

function printPerson(foo, { name, age }, bar) {
    console.log(arguments);
}
printPerson('1st', person, '2nd');

image.png

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-01 20:30:57  更:2022-02-01 20:31:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:10:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码