前言
-
本篇博客因篇幅有限,仅提取出个人认为十分重要且有用的精华,由于本人能力有限,文章可能未能一一提及,仅供各位同学参考学习。
-
本文章所有代码已在WebMaker上有代码测试用例。请点击略解《JavaScript语言精粹》代码片段访问配合学习。
伪类(原型链继承)
JavaScript通过构造器函数产生对象。
const Persion = function (name) {
this.name = name
}
Persion.prototype.getName = function() {
return this.name
}
Persion.prototype.says = function() {
return this.saying || ''
}
const persion1 = new Persion('xiaoxi')
console.log(persion1.getName())
const Father = function (name) {
this.name = name
this.saying = "i am father"
}
Father.prototype = new Persion()
Father.prototype.getName = function() {
return "Father" + this.name
}
Father.prototype.says = function() {
return this.saying || ''
}
const father1 = new Father('xiaoxi')
console.log(father1.says())
伪类模式本意是向面向对象靠拢,但它看起来格格不入,但可以隐藏prototype的操作系统,使它看起来没那么怪异。
可以使用父类的实例方法和原型方法,但 new 实例化传参不可用,需要手动修改实例属性。静态方法也不能被继承。
使用构造器函数存在严重危害,如果调用构造器函数的时候忘记在前面加 new 关键字,那么this将会绑定到全局对象上,这是一个严重的语言设计错误。伪类的形式隐藏了语言的真实本质,JavaScript有更好的选择。
对象冒充继承
function Person(name, age) {
this.name = name; //实例属性
this.age = age; //实例属性
this.run = function () { //实例方法
console.log(this.name + ' is running');
}
}
Person.prototype.swim = function () { //类上添加原型方法
console.log(`${this.name} is swiming`);
}
Person.work = function () { //类上添加静态方法
console.log(`${this.name} is working`);
}
function Student(name, age, grade) {
Person.call(this, name, age); //对象冒充继承
this.grade = grade; //实例属性
}
通过call改变函数this的指向实现继承,但不能继承原型属性和方法。静态方法也不能被继承。
对象冒充+原型链继承
function Programmer(name, age, language) {
Person.call(this, name, age); //对象冒充继承
this.language = language; //实例属性
this.introduce = function () { //实例方法
console.log(`${this.name} is a ${this.language} developer`);
}
}
Programmer.prototype = new Person(); //原型链继承
可以使用父类的实例方法和原型方法,子类也能向父类传参,但同时静态方法仍然不能被继承。
ES6类的语法糖
class Animal {
constructor(name, age) { //实例属性创建
this.name = name;
this.age = age;
}
speak() { //实例方法
console.log(this.name + ' makes a noise.');
}
static words = 'All animals eat food.'; //静态属性
}
Animal.prototype.run = function () { //类上添加原型方法
console.log(this.name + ' is running.');
}
Animal.eat = function () { //类上添加静态方法
console.log(this.words);
}
class Dog extends Animal {
constructor(name, age, color) {
super(name, age);
this.color = color;
}
colorIs() {
console.log(this.name + ' is ' + this.color);
}
}
let dog1 = new Dog('Teddy', 2, 'white'); //实例化
//继承父类的实例方法
dog1.speak(); //Teddy makes a noise.
//子类方法使用父类的实例属性
dog1.colorIs(); //Teddy is white
//继承父类的原型方法
dog1.run(); //Teddy is running.
//继承父类的静态方法
Dog.eat(); //All animals eat food.
可以使用父类的实例方法和原型方法,子类也能向父类传参。重点是,静态方法在 ES6 上是能被继承的。
函数化模式
从构造一个生成对象的函数开始,我们以小写字母开头来命名它,因为它不需要用new关键词,分为四个步骤。
- 创建一个新对象
- 定义私有变量和方法
- 给这个新对象扩充方法
- 返回那个新对象
const mammal = function (spec) {
const that = {}
that.get_name = function () {
return spec.name
}
that.says = function () {
return spec.saying || ''
}
return that
}
const myMammal = mammal({ name: 'Herb' })
console.log(myMammal.get_name())
const cat = function(spec) {
spec.saying = spec.saying || 'meow';
const that = mammal(spec)
that.purr = function() {
return 'sssssssss'
}
that.get_name = function() {
return that.says() + spec.name
}
return that
}
const myCat = cat({name: 'Henrietta'})
console.log(myCat.get_name())
const coolcat = function(spec) {
const that = cat(spec)
const super_get_name = that.get_name
that.get_name = function() {
return 'like' + super_get_name() + 'baby'
}
return that
}
const myCoolCat = coolcat({name: 'Bix'})
const name = myCoolCat.get_name()
console.log(name)
总结
- 函数继承有5种方式
- 分别是伪类(原型继承)、对象冒充继承、冒充+原型继承、ES6语法糖、函数化模式
类型 | 实例方法 | 原型方法 | 实例属性 | 静态方法 | 建议 |
---|---|---|---|---|---|
伪类(原型链继承) | √ | √ | 可以访问但无法调用父类构造器初始化 | × | |
对象冒充继承 | √ | × | √ | × | |
冒充+原型继承 | √ | √ | √ | × | |
ES6语法糖 | √ | √ | √ | √ | 简单易用 |
函数化模式比较特殊,是利用函数内部对象对外不可见的形式形成对象,所以不是自身继承这样的理念,无法应用到上面的表格当中,函数化模式更多是管理对象,所谓的继承也是对对象的属性和方法进行的一些操作。