# 类
基类:没有使用 extends
关键字的类声明被称作基类。
如果你的派生类需要引用它的父类,可以使用 super
关键字。
委托:在另一个对象上查找不存在属性的过程称作委托。
静态方法:是构造方法自己的方法,不能被类的实例化对象调用。我们使用 static 关键字定义静态方法。
// FatFreeFood 是一个派生类
class FatFreeFood extends Food {
constructor (name, protein, carbs) {
super(name, protein, carbs, 0);
}
print () {
super.print();
console.log(`Would you look at that -- ${this.name} has no fat!`);
}
}
在 JavaScript 中仅有两个 super 关键字的使用场景:
- 在子类构造函数中调用。如果初始化派生类是需要使用父类的构造函数,我们可以在子类的构造函数中调用 super(parentConstructorParams),传递任意需要的参数。
- 引用父类的方法。在常规方法定义中,派生类可以使用点运算符来引用父类的方法:super.methodName。
# 原型链
每个实例对象( object )都有一个私有属性(称之为 __proto__
)指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( __proto__
) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。
**JavaScript 对象是动态的属性“包”(指其自己的属性)。**JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
构造函数的 prototype
属性,为其生成的实例 原型
指针。与其实例 __proto__
# 关于原型的要点
- 所有的函数都有一个属性,叫做 .prototype,它指向这个函数的关联对象。
- 所有函数的原型都有一个属性,叫做 .constructor,它指向这个函数本身。
- 一个函数原型的 .constructor 并非必须指向创建这个函数原型的函数……有点绕,我们等下会深入探讨一下。
# create 设置原型
还记得使用 new 调用函数的时候,JavaScript 在幕后干了哪四件事儿吗?Object.create 就干了这三件事儿:
- 创建一个新对象;
- 设置它的原型引用;
- 返回这个新对象。
"use strict";
const foo = {
speak () {
console.log('Foo!');
}
};
const bar = Object.create(foo);
bar.speak(); // 'Foo!'
Object.getPrototypeOf(bar) === foo; // true
# 强行 new 构造调用
"use strict";
// 强行构造调用
function Food (name, protein, carbs, fat) {
// 如果用户忘了手工调用一下
if (!new.target)
return new Food(name, protein, carbs, fat);
this.name = name;
this.protein = protein;
this.carbs = carbs;
this.fat = fat;
}
const fish = Food('Halibut', 26, 0, 2); // 糟了,不过没关系!
fish; // 'Food {name: "Halibut", protein: 20, carbs: 5, fat: 0}'
"use strict";
function Food (name, protein, carbs, fat) {
if (!(this instanceof Food))
return new Food(name, protein, carbs, fat);
this.name = name;
this.protein = protein;
this.carbs = carbs;
this.fat = fat;
}
# 参考
(opens new window) 【进阶5-1期】重新认识构造函数、原型和原型链 (opens new window)