1、 函数的构造函数
内置函数 Object. proto === Function.prototype => true
内置函数和普通函数都是有Function构造出来的。
console.log(Object.constructor)
// Object函数自身没有constructor属性,
//会沿着原型链去找原型Functiono.protorype.constructor => Function
一切函数都是Function的实例,包括Function本身。
Function是实例对象,也是构造函数。
console.log(Function.__proto__ === Function.prototype) // true 函数都是Function的实例
2、对象的getter、setter方法
将对象属性绑定到查询该属性时将被调用的函数。
let obj = {
a:1;
get b(){
return 'b'
},
set b(val){
this.a = val
}
}
setter和getter尝尝用来创建伪属性,不能在具有真实值属性上同时拥有setter器
可在对象初始化时添加、使用delete删除、使用Object.defineProperty随时添加setter和getter
3、继承方式
(1)原型链继承
将祖辈实例对象作为父类的原型对象进行原型链继承。
缺点:
(1)原型链上引用值共享
(2)子类实例化的时候无法给父类传参。
function Super(){
this.name = 'SuperInstance'
this.arr = [1, 2, 3]
}
let superInstance = new Super()
function Father(){
this.name = 'FatherInstance'
}
//将祖辈原型实例作为父类原型对象
Father.prototype = superInstance
let son1 = new Father(),
son2 = new Father();
son1.arr.push(6);
console.log(son2.arr) // => [1,2,3,6]
// son的原型链 son.__proto__ => Father.prototype(superInstance) => Super.prototype
(2)盗用构造函数(constructor stealing)也被叫作经典继承
避免原型链引用值共享的方法:借用构造函数,子类实例可以给父类构造函数传参,原理是给每个实例对象添加自己的属性值。缺点:无法是子类实例继承父类构造函数的原型对象。
function Super(){
this.name = 'SuperInstance'
}
function Father(){
this.name = 'FatherInstance'
Super.call(this)
}
let son = new Father()
但是借用父类构造函数,没有让子类实例继承父类的原型对象。
所以还需造出父类实例,指为子类构造函数的原型对象
(3)组合继承(伪经典继承):
function Super(name){
this.name = name
}
let superInstance = new Super()
Father.prototyper = superInstance
function Father (opt){
Super.call(this)
this.habbit = opt.habbit
}
//这样解决了引用值共享的问题,也让子类实例继承了父类原型对象。
//但是,这样调用了两次父类构造函数
(4)寄生组合继承
组合继承解决了原型引用值共享的问题,并且让子类实例继承父类原型上的属性与方法。但是有效率问题,父类在创建子类构造函数原型对象时,和子类构造函数时一共调用了两次。可以用 Object.create()来优化
Father.prototype = Object.create(Super.prototype) // =>创造一个实例,并指定继承的对象。
function Super(c){
this.name = opt.name
}
function Son function(){
Super.call(this)
}
Son.prototype = Object.create(Super.prototype)
let son = new Son()
//Object.create的es6兼用方式
function correctProto(proto){
if(Object.create){
return Object.create(proto)
}else{
function Buffer(){}
Buffer.prototype = proto
return new Buffer()
}
}
Fater.prototype = correctProto(Super.prototype)
(5)圣杯模式
function Buffer(){}
Buffer.prototype = proto
let buffer = new Buffer()
Son.prototype = buffer
Son.prototype.constructor = Son
Son.superClass = Super
//创建一个继承自父类的干净对象,指定为子类构造函数的prototype。
//然后把子类构造函数的constructor矫正,并记录继承的超类。
(6)es6 class继承
同是解决了引用值共享问题,实现了子类实例对父类方法的继承
class Super{
constructor(){
this.a = [1,2,3]
}
superSay(){
console.log(this.a)
}
}
class Sub extends Super{
constructor(name){
super()
this.name = name
}
subSay(){
console.log(this.name)
}
}
let sub1 = new Sub('sub1'),
sub2 = new Sub('sub2');
sub1.a.push('sub1')
sub1.subSay()
sub2.subSay()
console.log(sub1,sub2)
(7)其他继承方式:拷贝继承,用的很少
(8)class的一些用法
1、可以直接在class内部添加实例自身属性
class Super{
a = [1,2,3,4,5]
}
let sub = new Super()
2、子类构造函数继承父类构造函数时,constructor中使用this之前,需要调用super方法
3、static静态方法,构造函数自身的方法(Object.create、Array.from、Array.of)。如果不加static关键字的话,就变成了构造函数原型对象上的方法了。
class Super{
static say(){
console.log('SuperSay')
}
}
相当于
Super.say = function(){console.log('SuperSay')}