JavaScript:原型链继承与对象冒充继承及ES6语法的解决
- 在ES5语法中,没有类这种概念,只能通过特殊的方式来实现继承;
- 在学习原生js继承的过程中,遇到了两种继承模式的特点,特此记录下来以便下次复习。
1.原型链继承
-
原型链继承可以继承构造函数以及原型链上的属性和方法,但实例化子类的时候,无法给父类传参;
function Father(name,age){ this.name = name; this.age = age; this.info = function(){ console.log(this.name + ',' + this.age); } } // 静态方法 Father.prototype.work = function(){ console.log('work'); } function Son(){ // 属性和方法 } Son.prototype = new Father(); // 实例化子类 let son = new Son('张三',18); son.info(); // undefined,undefined son.work(); // work
2.对象冒充继承
-
对象冒充继承可以继承构造函数的方法,但是无法继承原型链上的方法;
function Father(name,age){ this.name = name; this.age = age; this.info = function(){ console.log(this.name + ',' + this.age); } } Father.prototype.work = function(){ console.log('work'); } function Son(name,age){ // 对象冒充继承 Father.call(this,name,age) } // 实例化子类 let son = new Son('张三',18); son.info(); // 张三,18 son.work(); // Uncaught TypeError: son.work is not a function
3.ES6语法的类
-
在ES6语法中,添加类的概念——class,类的引入使得js面向对象开发更为简便;
// 定义父类 class Father{ // 构造函数 constructor(name,age){ this._name = name; this._age = age; } getName(){ console.log(this._name); } setName(name){ this._name = name; } // 静态方法 static work(){ console.log('work'); } } // 静态方法和属性 Father.sleep = function(){ console.log('sleep'); } let f = new Father('马云',50); f.getName(); // 马云 f.setName('马化腾'); f.getName(); // 马化腾
-
而ES6的继承方式也与java类似——extends;这种继承方式可以兼顾以上两种继承方法的优点:即既可以继承静态方法和构造函数上的属性和方法,实例化子类时也可以给父类传参。
// 定义父类 class Father{ // 构造函数 constructor(name,age){ this._name = name; this._age = age; } getName(){ console.log(this._name); } setName(name){ this._name = name; } // 静态方法 static work(){ console.log('work'); } } // 静态方法和属性 Father.sleep = function(){ console.log('sleep'); } // 子类继承父类 class Son extends Father{ constructor(name,age,sex){ super(name,age); this._sex = sex; } getSex(){ console.log(this._sex); } } // 实例化 let s = new Son('allen',19,'male'); s.getName(); // allen s.getSex(); // male Son.work(); // work Son.sleep(); // sleep
4.ES6中的单例
-
在实际应用场景中,我们有时在多次实例化中只需执行一次特定的操作,如数据库的操作;
-
让我们看看非单例情况下实例化会发生什么:
class Db{ constructor(){ this.connect(); } connect(){ console.log('连接数据库'); } find(){ console.log('查询数据库'); } } let db1 = new Db(); let db2 = new Db(); // 执行结果 连接数据库 连接数据库
-
上面的例子很明确指出,非单例情况下实例化多次,会执行多次连接数据库的方法,这样造成了大量的时间和空间资源;
-
单例的实现方式很简单,只需构造一个静态方法即可:
class Db{ static getInstance(){ if(!Db.instance){ Db.instance = new Db(); } return Db.instance; } constructor(){ this.connect(); } connect(){ console.log('连接数据库'); } find(){ console.log('查询数据库'); } } let db1 = Db.getInstance(); let db2 = Db.getInstance(); let db3 = Db.getInstance(); db3.find(); db2.find(); // 执行结果 连接数据库 查询数据库 查询数据库
-
所有实例都共享一个实例,称为 单例。运用好单例模式,在特定场景中可以节省不必要的资源浪费,十分推荐。