接上文: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
形式创建对象等同于此形式。
劣势:
可达到属性复用。
缺点:
无奈在实例化的时候传递参数,不可配置。上述示例中 A
和 B
的名称都为 张三。即便咱们在实例化 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)) // trueconsole.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)) // falseconsole.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.aconsole.log(obj) // { a: 1, b: 2, c: 3 }// 尝试增加obj.d = 4console.log(obj) // { a: 1, b: 2, c: 3 }// 查问对象是否是密封状态console.log(Object.isSealed(obj)) // true// 尝试批改原有属性值obj.a = 4console.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 = 4console.log(obj) //{ a: 1, b: 2, c: 3 }// 尝试删除delete obj.aconsole.log(obj) //{ a: 1, b: 2, c: 3 }// 尝试批改obj.a = 4console.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 = 11console.log(obj.c) //{ d: 11 }
也就是说,解冻对象只能解冻一层,不能深层次解冻,如果须要深层次解冻,则须要递归的解冻每个值为对象的属性。
4.4 对象解构
此操作等同于数组解构,不同的是,对象会依据属性值进行解构操作。话不多说,小栗子来看下
const obj = { a: 1, b: 2, c: 3}// 一般解构let {a, b} = objconsole.log(a, b) // 1, 2// 带默认值的解构,解构不到时,赋值为默认值let {a = 0, b = 0, d = 0} = objconsole.log(a,b, d) // 1,2,0// 解构并重命名let {a: newA, b: newB} = objconsole.log(newA, newB) // 1, 2// 默认值 and 重命名let {d: newA = 0, b: newB = 0} = objconsole.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 = 2console.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) // trueObject.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.result
为undefined
或者 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]
可选链具备短路性能,如果右边的操作数为 undefined
和 null
,则会中断表达式计算。 (相似于 &&)
然而,此形式不能用于赋值
obj?.['parent'] = 1
2. 空值合并
如果咱们相给一个值赋默认值,通常是这么做
let obj = {}let result = obj.a || 1
当初,咱们能够这么做
let obj = 0let result = obj.a ?? 1
空值合并同样具备短路性能,当右边不为null时,中断操作。(相似于 || )
留神:
管制合并不能与 &&
或 ||
连用哟。会呈现问题。
?.
与??
合用
let obj = { a: 1, b: 2};let result = obj?.a ?? 0;console.log(result); // 1
好了,every body. 明天要分享的内容就到这里了。咱们下次再见~~