H5W3
当前位置:H5W3 > JavaScript > 正文

【JS】Object重识(二)

Object重识(二)

yancy发布于 今天 03:02

接上文:Object重识(一)

3. 对象继承

对象继承,我们不介绍名词,不说是什么样的继承,只从头看下每个继承方式的不足,并介绍如何补充

3.1 最简单的继承

function A (name) {
this.name = name
}
function B () {}
B.prototype = new A('张三')
console.log(new B("李四").name) // 张三

此方法是将 B 的原型直接指向 A 的原型,从而达到继承的目的。Object.create方式创建对象等同于此方式。

优势:

可达到属性复用。

缺陷:

无法在实例化的时候传递参数,不可配置。上述示例中 AB 的名称都为 张三。即使我们在实例化 B 的时候传入一个名称。

3.2 改进版

改进版可在实例化的时候添加参数

function A (name) {
this.name = name;
}
function B (name) {
A.call(this, name)
}
console.log(new B('李四').name) // 李四

优势:

可实现定制化,支持传参配置

缺陷:

无法复用,所有内容都通过构造函数定义

3.3 结合版

function A (name) {
this.name = name;
}
A.prototype.address = '中国'
function B (name) {
A.call(this, name)
}
B.prototype = new A();
const b = new B('李四')
console.log(b.name) // 李四
console.log(b.address) // 中国

总结:

此继承方式也不是完整版,只是让大家了解继承的实现方式。像什么 寄生继承、寄生组合继承。咱们就多啰嗦了,容易越看越乱。有兴趣的读者可以之后再跟大家分享或者自行查阅。

3.4 ES6 继承

有了ES6之后感觉空气都甜了。之前复杂的继承写法都变得特别简单。看栗子↓↓↓↓↓

class A {
constructor (name) {
this.name = name;
}
}
class B extends A {
constructor (name) {
super(name)
}
}
const b = new B('李四')
console.log(b.name)

class方式创建对象注意点:

  • 写在 构造函数constructor 中的方法都属于自身的方法。
  • 写在构造函数constructor 之外的方法都属于原型方法

举栗说明:

class A {
constructor () {
this.log = function () {
console.log('111111')
}
}
log () {
console.log('222222')
}
}
const a = new A()
a.log() // 111111 -- 原型链的查找问题
console.log(a.log)
/*
ƒ () {
console.log('111111')
}
*/
console.log(a.__proto__.log)
/*
ƒ log () {
console.log('222222')
}
*/

4. 对象操作

4.1 对象转字符串

使用 JSON.stringify 方法将对象转换为字符串显示

const obj = {
a: 1,
b: 2,
c: 3
}
const strObj = JSON.stringify(obj)
console.log(strObj) // {"a":1,"b":2,"c":3}

注意点:

JSON.stringify(obj, replacer, space) 接收三个参数

  • obj 被转换的对象
  • replacer 可以是 函数 或 数组。为数组,只转换数组中的值
const obj = {
a: 1,
b: 2,
c: 3
}
// 第二个参数为数组
console.log(JSON.stringify(obj, ['a', 'b'])) // {"a":1,"b":2}
// 第二个参数为函数
function replacer(key, value) {
if (value === 1){
return undefined
}
return value
}
console.log(JSON.stringify(obj, replacer)) // {"b":2,"c":3}
  • space 可以为数字或字符串,添加输出结果中的间距。最大间距数量为 10 。最小为 0
const obj = {
a: 1,
b: 2,
c: 3
}
// 为数字
console.log(JSON.stringify(obj, null, 2))
/*
{
"a": 1,
"b": 2,
"c": 3
}
*/
// 为字符串
console.log(JSON.stringify(obj, null, '-'))
/*
{
-"a": 1,
-"b": 2,
-"c": 3
}
*/

4.2 对象转换为数组

1. Object.keys 返回对象的 key 值组成的数组
2. Object.values 返回对象的value值组成的数组
3. Object.entries 返回对象的 key 值和value值组成的数组
const obj = {
a: 1,
b: 2,
c: 3
}
console.log(Object.keys(obj)) // [ 'a', 'b', 'c' ]
console.log(Object.values(obj)) // [ 1, 2, 3 ]
console.log(Object.entries(obj)) // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]

上述方法会用就可以,没太多需要注意的点。

4.3 对象扩展,密封,冻结

1. 对象拓展

什么是对象拓展?

1.1小节中创建的对象都可以添加新的属性和方法,这就叫对象拓展。可以使用 Object.isExtensible 方法查看。

function B () {}
const a = {}
const b = new B()
console.log(Object.isExtensible(a)) // true
console.log(Object.isExtensible(b)) // true

禁止对象拓展, 可使用 Object.preventExtensions 方法

function B () {}
const a = {}
const b = new B()
// 禁止对象拓展
Object.preventExtensions(a)
Object.preventExtensions(b)
console.log(Object.isExtensible(a)) // false
console.log(Object.isExtensible(b)) // false
2. 对象密封 Object.seal

对象密封可以理解为字面的意思。就是把一个对象密封起来。

密封的对象不可拓展(不能添加新属性),不可删除属性,不能修改已有属性的属性描述符(writeable、value等)

将一个对象密封,可以使用Object.seal方法

同样,查询一个对象是否是密封对象,可以使用Object.isSealed方法

const obj = {
a: 1,
b: 2,
c: 3
}
// 密封一个对象
Object.seal(obj)
// 尝试删除
delete obj.a
console.log(obj) // { a: 1, b: 2, c: 3 }
// 尝试添加
obj.d = 4
console.log(obj) // { a: 1, b: 2, c: 3 }
// 查询对象是否是密封状态
console.log(Object.isSealed(obj)) // true
// 尝试修改原有属性值
obj.a = 4
console.log(obj) // { a: 4, b: 2, c: 3 }

注意:

虽然将对象密封了,但是依旧可以修改原有的属性值。如果想让一个对象不可更改,可以用到下面这个方法。

3. 对象冻结 Object.freeze

对象冻结顾名思义就是将对象的所有属性都冻结住,不可修改,不可增删。可以使用Object.freeze方法冻结一个对象。查看一个对象是否是冻结对象可以使用Object.isFrozen() 方法。

const obj = {
a: 1,
b: 2,
c: 3
}
// 冻结一个对象
Object.freeze(obj)
// 尝试新增
obj.d = 4
console.log(obj) //{ a: 1, b: 2, c: 3 }
// 尝试删除
delete obj.a
console.log(obj) //{ a: 1, b: 2, c: 3 }
// 尝试修改
obj.a = 4
console.log(obj) //{ a: 1, b: 2, c: 3 }
// 查看对象是否冻结
Object.isFrozen(obj) // true

看吧,冻结之后的对象你是不能对它做操作的。

但是………………

这种情况下可以修改

const obj = {
a: 1,
b: 2,
c: {
d: 4
}
}
Object.freeze(obj)
obj.c.d = 11
console.log(obj.c) //{ d: 11 }

也就是说,冻结对象只能冻结一层,不能深层次冻结,如果需要深层次冻结,则需要递归的冻结每个值为对象的属性。

4.4 对象解构

此操作等同于数组解构,不同的是,对象会根据属性值进行解构操作。话不多说,小栗子来看下

const obj = {
a: 1,
b: 2,
c: 3
}
// 普通解构
let {a, b} = obj
console.log(a, b) // 1, 2
// 带默认值的解构,解构不到时,赋值为默认值
let {a = 0, b = 0, d = 0} = obj
console.log(a,b, d) // 1,2,0
// 解构并重命名
let {a: newA, b: newB} = obj
console.log(newA, newB) // 1, 2
// 默认值 and 重命名
let {d: newA = 0, b: newB = 0} = obj
console.log(newA, newB) // 0, 2

注意点:

  • 解构可以添加默认值
  • 解构可以重命名
  • 可以使用重命名 and 默认值并存的方式解构对象

4.5 对象拷贝和对象比较 Object.assign、Object.is

1. 对象拷贝

Object.assign 可以实现对象的复制,合并,深拷贝等操作,需要注意的点是:继承的属性和不可枚举(enumerable为false)的属性不能拷贝

  • 对象拷贝
// 深拷贝
const obj1 = {
d: 4,
e: 5
}
const a = Object.assign({}, obj1)
console.log(a)
obj1.d = 2
console.log(a) // 修改之后不会变动a的值
  • 对象合并
const obj = {
a: 1,
b: 2,
c: 3
}
const obj1 = {
a: 4,
e: 5
}
const a = Object.assign(obj, obj1)
console.log(a) // { a: 4, b: 2, c: 3, e: 5 }

合并后,如果第二个参数中有和第一个参数相同的属性,则第二个参数的属性会覆盖第一个参数的属性。

2. 对象比较

之前的工作中,我们会知道这样一句话,NaN不等于任何东西,包括它自身 。那么我们用Object.is来试一下。

此方法用来比较两个对象是否相等。

Object.is(NaN, NaN) // true
Object.is(+0, -0) // false

除去上面这种案例,其他的表现与 === 相同

4.6 ?.?? (可选链和空值合并)

1. 可选链 ?.

日常工作中,像下面这种代码非常常见。

const obj = {
result: {
a: 1
}
}
let result = obj.result && obj.result.a;

当然,有了可选链之后,我们就不需要这么麻烦了 ,上述代码可改写成以下方式:

const obj = {
result: {
a: 1
}
}
let result = obj.result?.a;

如果obj.resultundefined 或者 null 时,会中断操作而返回undefined 或者 null

此方法也可用于函数

const obj = {
result: function (){
}
}
obj.result?.();

用于数组:

const arr = []
arr?.[0]

用于表达式:

const obj = {
parentResult
}
obj?.['parent' + 'Result']

可连用:

const arr = [[[1]]]
arr?.[0]?.[0]?.[0]

可选链具有短路功能,如果左边的操作数为 undefinednull ,则会中断表达式计算。 (类似于 &&)

但是,此方式不能用于赋值

obj?.['parent'] = 1
2. 空值合并

如果我们相给一个值赋默认值,通常是这么做

let obj = {}
let result = obj.a || 1

现在,我们可以这么做

let obj = 0
let result = obj.a ?? 1 

空值合并同样具有短路功能,当左边不为null时,中断操作。(类似于 || )

注意:

控制合并不能与 &&|| 连用哟。会出现问题。

?.??合用

let obj = {
a: 1,
b: 2
};
let result = obj?.a ?? 0;
console.log(result); // 1

好了,every body. 今天要分享的内容就到这里了。咱们下次再见~~

javascript前端oop原型原型链
阅读 33发布于 今天 03:02
本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议
avatar

yancy

你若盛开,清风自来

4 声望
1 粉丝

0 条评论
得票时间

avatar

yancy

你若盛开,清风自来

4 声望
1 粉丝

宣传栏

接上文:Object重识(一)

3. 对象继承

对象继承,我们不介绍名词,不说是什么样的继承,只从头看下每个继承方式的不足,并介绍如何补充

3.1 最简单的继承

function A (name) {
this.name = name
}
function B () {}
B.prototype = new A('张三')
console.log(new B("李四").name) // 张三

此方法是将 B 的原型直接指向 A 的原型,从而达到继承的目的。Object.create方式创建对象等同于此方式。

优势:

可达到属性复用。

缺陷:

无法在实例化的时候传递参数,不可配置。上述示例中 AB 的名称都为 张三。即使我们在实例化 B 的时候传入一个名称。

3.2 改进版

改进版可在实例化的时候添加参数

function A (name) {
this.name = name;
}
function B (name) {
A.call(this, name)
}
console.log(new B('李四').name) // 李四

优势:

可实现定制化,支持传参配置

缺陷:

无法复用,所有内容都通过构造函数定义

3.3 结合版

function A (name) {
this.name = name;
}
A.prototype.address = '中国'
function B (name) {
A.call(this, name)
}
B.prototype = new A();
const b = new B('李四')
console.log(b.name) // 李四
console.log(b.address) // 中国

总结:

此继承方式也不是完整版,只是让大家了解继承的实现方式。像什么 寄生继承、寄生组合继承。咱们就多啰嗦了,容易越看越乱。有兴趣的读者可以之后再跟大家分享或者自行查阅。

3.4 ES6 继承

有了ES6之后感觉空气都甜了。之前复杂的继承写法都变得特别简单。看栗子↓↓↓↓↓

class A {
constructor (name) {
this.name = name;
}
}
class B extends A {
constructor (name) {
super(name)
}
}
const b = new B('李四')
console.log(b.name)

class方式创建对象注意点:

  • 写在 构造函数constructor 中的方法都属于自身的方法。
  • 写在构造函数constructor 之外的方法都属于原型方法

举栗说明:

class A {
constructor () {
this.log = function () {
console.log('111111')
}
}
log () {
console.log('222222')
}
}
const a = new A()
a.log() // 111111 -- 原型链的查找问题
console.log(a.log)
/*
ƒ () {
console.log('111111')
}
*/
console.log(a.__proto__.log)
/*
ƒ log () {
console.log('222222')
}
*/

4. 对象操作

4.1 对象转字符串

使用 JSON.stringify 方法将对象转换为字符串显示

const obj = {
a: 1,
b: 2,
c: 3
}
const strObj = JSON.stringify(obj)
console.log(strObj) // {"a":1,"b":2,"c":3}

注意点:

JSON.stringify(obj, replacer, space) 接收三个参数

  • obj 被转换的对象
  • replacer 可以是 函数 或 数组。为数组,只转换数组中的值
const obj = {
a: 1,
b: 2,
c: 3
}
// 第二个参数为数组
console.log(JSON.stringify(obj, ['a', 'b'])) // {"a":1,"b":2}
// 第二个参数为函数
function replacer(key, value) {
if (value === 1){
return undefined
}
return value
}
console.log(JSON.stringify(obj, replacer)) // {"b":2,"c":3}
  • space 可以为数字或字符串,添加输出结果中的间距。最大间距数量为 10 。最小为 0
const obj = {
a: 1,
b: 2,
c: 3
}
// 为数字
console.log(JSON.stringify(obj, null, 2))
/*
{
"a": 1,
"b": 2,
"c": 3
}
*/
// 为字符串
console.log(JSON.stringify(obj, null, '-'))
/*
{
-"a": 1,
-"b": 2,
-"c": 3
}
*/

4.2 对象转换为数组

1. Object.keys 返回对象的 key 值组成的数组
2. Object.values 返回对象的value值组成的数组
3. Object.entries 返回对象的 key 值和value值组成的数组
const obj = {
a: 1,
b: 2,
c: 3
}
console.log(Object.keys(obj)) // [ 'a', 'b', 'c' ]
console.log(Object.values(obj)) // [ 1, 2, 3 ]
console.log(Object.entries(obj)) // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]

上述方法会用就可以,没太多需要注意的点。

4.3 对象扩展,密封,冻结

1. 对象拓展

什么是对象拓展?

1.1小节中创建的对象都可以添加新的属性和方法,这就叫对象拓展。可以使用 Object.isExtensible 方法查看。

function B () {}
const a = {}
const b = new B()
console.log(Object.isExtensible(a)) // true
console.log(Object.isExtensible(b)) // true

禁止对象拓展, 可使用 Object.preventExtensions 方法

function B () {}
const a = {}
const b = new B()
// 禁止对象拓展
Object.preventExtensions(a)
Object.preventExtensions(b)
console.log(Object.isExtensible(a)) // false
console.log(Object.isExtensible(b)) // false
2. 对象密封 Object.seal

对象密封可以理解为字面的意思。就是把一个对象密封起来。

密封的对象不可拓展(不能添加新属性),不可删除属性,不能修改已有属性的属性描述符(writeable、value等)

将一个对象密封,可以使用Object.seal方法

同样,查询一个对象是否是密封对象,可以使用Object.isSealed方法

const obj = {
a: 1,
b: 2,
c: 3
}
// 密封一个对象
Object.seal(obj)
// 尝试删除
delete obj.a
console.log(obj) // { a: 1, b: 2, c: 3 }
// 尝试添加
obj.d = 4
console.log(obj) // { a: 1, b: 2, c: 3 }
// 查询对象是否是密封状态
console.log(Object.isSealed(obj)) // true
// 尝试修改原有属性值
obj.a = 4
console.log(obj) // { a: 4, b: 2, c: 3 }

注意:

虽然将对象密封了,但是依旧可以修改原有的属性值。如果想让一个对象不可更改,可以用到下面这个方法。

3. 对象冻结 Object.freeze

对象冻结顾名思义就是将对象的所有属性都冻结住,不可修改,不可增删。可以使用Object.freeze方法冻结一个对象。查看一个对象是否是冻结对象可以使用Object.isFrozen() 方法。

const obj = {
a: 1,
b: 2,
c: 3
}
// 冻结一个对象
Object.freeze(obj)
// 尝试新增
obj.d = 4
console.log(obj) //{ a: 1, b: 2, c: 3 }
// 尝试删除
delete obj.a
console.log(obj) //{ a: 1, b: 2, c: 3 }
// 尝试修改
obj.a = 4
console.log(obj) //{ a: 1, b: 2, c: 3 }
// 查看对象是否冻结
Object.isFrozen(obj) // true

看吧,冻结之后的对象你是不能对它做操作的。

但是………………

这种情况下可以修改

const obj = {
a: 1,
b: 2,
c: {
d: 4
}
}
Object.freeze(obj)
obj.c.d = 11
console.log(obj.c) //{ d: 11 }

也就是说,冻结对象只能冻结一层,不能深层次冻结,如果需要深层次冻结,则需要递归的冻结每个值为对象的属性。

4.4 对象解构

此操作等同于数组解构,不同的是,对象会根据属性值进行解构操作。话不多说,小栗子来看下

const obj = {
a: 1,
b: 2,
c: 3
}
// 普通解构
let {a, b} = obj
console.log(a, b) // 1, 2
// 带默认值的解构,解构不到时,赋值为默认值
let {a = 0, b = 0, d = 0} = obj
console.log(a,b, d) // 1,2,0
// 解构并重命名
let {a: newA, b: newB} = obj
console.log(newA, newB) // 1, 2
// 默认值 and 重命名
let {d: newA = 0, b: newB = 0} = obj
console.log(newA, newB) // 0, 2

注意点:

  • 解构可以添加默认值
  • 解构可以重命名
  • 可以使用重命名 and 默认值并存的方式解构对象

4.5 对象拷贝和对象比较 Object.assign、Object.is

1. 对象拷贝

Object.assign 可以实现对象的复制,合并,深拷贝等操作,需要注意的点是:继承的属性和不可枚举(enumerable为false)的属性不能拷贝

  • 对象拷贝
// 深拷贝
const obj1 = {
d: 4,
e: 5
}
const a = Object.assign({}, obj1)
console.log(a)
obj1.d = 2
console.log(a) // 修改之后不会变动a的值
  • 对象合并
const obj = {
a: 1,
b: 2,
c: 3
}
const obj1 = {
a: 4,
e: 5
}
const a = Object.assign(obj, obj1)
console.log(a) // { a: 4, b: 2, c: 3, e: 5 }

合并后,如果第二个参数中有和第一个参数相同的属性,则第二个参数的属性会覆盖第一个参数的属性。

2. 对象比较

之前的工作中,我们会知道这样一句话,NaN不等于任何东西,包括它自身 。那么我们用Object.is来试一下。

此方法用来比较两个对象是否相等。

Object.is(NaN, NaN) // true
Object.is(+0, -0) // false

除去上面这种案例,其他的表现与 === 相同

4.6 ?.?? (可选链和空值合并)

1. 可选链 ?.

日常工作中,像下面这种代码非常常见。

const obj = {
result: {
a: 1
}
}
let result = obj.result && obj.result.a;

当然,有了可选链之后,我们就不需要这么麻烦了 ,上述代码可改写成以下方式:

const obj = {
result: {
a: 1
}
}
let result = obj.result?.a;

如果obj.resultundefined 或者 null 时,会中断操作而返回undefined 或者 null

此方法也可用于函数

const obj = {
result: function (){
}
}
obj.result?.();

用于数组:

const arr = []
arr?.[0]

用于表达式:

const obj = {
parentResult
}
obj?.['parent' + 'Result']

可连用:

const arr = [[[1]]]
arr?.[0]?.[0]?.[0]

可选链具有短路功能,如果左边的操作数为 undefinednull ,则会中断表达式计算。 (类似于 &&)

但是,此方式不能用于赋值

obj?.['parent'] = 1
2. 空值合并

如果我们相给一个值赋默认值,通常是这么做

let obj = {}
let result = obj.a || 1

现在,我们可以这么做

let obj = 0
let result = obj.a ?? 1 

空值合并同样具有短路功能,当左边不为null时,中断操作。(类似于 || )

注意:

控制合并不能与 &&|| 连用哟。会出现问题。

?.??合用

let obj = {
a: 1,
b: 2
};
let result = obj?.a ?? 0;
console.log(result); // 1

好了,every body. 今天要分享的内容就到这里了。咱们下次再见~~

本文地址:H5W3 » 【JS】Object重识(二)

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址