1.es5继承有哪些方式?
原型链继承
<!-- 父类 -- >
function Super(name) {
this.name = name
}
Super.prototype = {
name: '我要走走看看',
age: 18,
hobby: { a: '篮球' },
}
<!-- 子类 -- >
function Sub() {}
Sub.prototype = new Super() // 子类的原型等于父类的实例
const sub = new Sub()
console.log(sub.age) // 18
缺点:
- 子类无法想父类的构造函数传参. new Sub( name )父类也接收不到
- 子类修改父类原型中引用类型的值时,原型的属性发生改变,导致之后的实例的值都发生改变
const sub1 = new Sub()
const sub2 = new Sub()
sub1.hobby.a = '羽毛球' // 这里修改了sub1的hobby的值
console.log(sub1.hobby) // { a: '羽毛球' }
console.log(sub2.hobby) // { a: '羽毛球' }
借用构造函数继承
// 父类
function Super(name) {
this.name = name
}
Super.prototype = {
name: '我要走走看看',
age: 18,
hobby: { a: '篮球' },
}
// 子类
function Sub(name) {
Super.call(this,name)// 通过 call / apply 继承父类构造函数内的属性和方法
}
const sub = new Sub('猫咪')
console.log(sub.name) // 猫咪
console.log(sub.age) // undefined
优点 :
- 解决了子类实例向父类传参的缺点
- 解决了子类实例修改父类原型属性或者方法的问题
- 可以继承多个构造函数属性(call多个)。
缺点:
- 无法继承父类原型的方法和属性
- 每个新实例都有父类构造函数的副本,无法复用,臃肿。
组合继承 (j原型链继承 + 构造函数继承 )
// 父类
function Super(name) {
this.name = name
}
Super.prototype = {
name: '我要走走看看',
age: 18,
hobby: { a: '篮球' },
}
// 子类
function Sub(name) {
Super.call(this,name) // 1: 调用第一次
}
Sub.prototype = new Super() // 2: 调用第二次
优点:可传参 + 继承了父类的原型
缺点:两次调用父类的构造函数(耗内存)
寄生组合式继承(常用)
function Super(name) {
this.name = name
this.age = 21
}
Super.prototype = Object.assign({
sayName: () => {
console.log(this.name)
},
address: '上海',
hobby: ['唱歌'],
})
function Sub(name) {
Super.call(this, name) // 继承父类构造函数的属性
}
Sub.prototype = Object.create(Super.prototype) // 继承父类的原型
const sub1 = new Sub('姓名1')
console.log(this.name) // 姓名1
既可以传参又实现了原型的复用
2.Symbol简单理解
Symbol值通过Symbol函数,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。而Symbol类型的属性名都是独一无二的,保证不会与其他属性名发生冲突。- 注意:Symbol函数前不能用
new命令,这是因为生成的 Symbol 是一个原始类型的值,不是对象。
let s = Symbol();
typeof s;//Symbol
注意:
Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。- Symbol值不能与其他类型的值进行运算
- Symbol值可以显式转为字符串
- Symbol值可以转为布尔型,但不能转为数值。
- 属性名的遍历。
Symbol 作为属性名,该属性不会出现在
for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。
Object.getOwnPropertySymbols():返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。Reflect.ownKeys():返回所有类型的键名。
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
- Symbol的方法:
Symbol.for()(重新使用同一个Symbol值), 它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
Symbol.Keyfor()返回一个已登记的Symbol类型的值Key。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined