class 是基于原型繼承的語(yǔ)法糖,并不是另外的一套規(guī)則
class 與 構(gòu)造函數(shù)的區(qū)別在于,類聲明沒有提升
聲明
類聲明和類表達(dá)式的主體都執(zhí)行在嚴(yán)格模式下丑念。
// Uncaught ReferenceError: Cannot access 'Person' before initialization
// var p1 = new Person('Tom', 12)
class Person {
// constructor 構(gòu)造函數(shù) 一個(gè)類只能有一個(gè)
constructor(name, age) {
this.name = name
this.age = age
}
}
or
const Person = class {
constructor(name, age) {
this.name = name
this.age = age
}
}
實(shí)例化
class Person {
// 公有屬性
sex = '中性'
// 私有屬性
#height = 160
// constructor 構(gòu)造函數(shù) 一個(gè)類只能有一個(gè)
// 一個(gè)構(gòu)造函數(shù)可以使用 super 關(guān)鍵字來(lái)調(diào)用一個(gè)父類的構(gòu)造函數(shù)爱只。
constructor(name, age, height) {
this.name = name
this.age = age
this.#height = height
}
// Getter
get info() {
console.log('name: ' + this.name + '-- age: ' + this.age)
}
// Methods
log() {
console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex + '-- #height: ' + this.#height)
}
// static
// 靜態(tài)方法 作用于類本身
// 只有類本身才能調(diào)用
static getName() {
console.log(this.name)
}
static a = 1
}
const p1 = new Person('Tom', 22, 170)
p1.info
p1.log()
Person.getName()
console.log(Person.a)
console.log(p1.sex)
繼承
// 單繼承
class Man extends Person {
// 子類中定義了構(gòu)造函數(shù),那么它必須先調(diào)用 super() 才能使用 this
constructor(name, age, height, sex) {
super(name, age, height)
this.sex = sex
}
log() {
//+ '-- #height: ' + this.#height
// #height 私有的在這里拿不到
console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex)
}
}
const man = new Man('Joe', 10, 90, '男')
man.info
man.log()
Man.getName()
console.log(Man.a)
console.log(man.sex)
Mix-ins
實(shí)現(xiàn)多繼承
var calculatorMixin = Base => class extends Base {
calc() { console.log('calc methods') }
};
var randomizerMixin = Base => class extends Base {
randomize() { console.log('randomize methods') }
};
class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }
var bar = new Bar()
bar.randomize() // randomize methods
bar.calc() // calc methods
通過(guò) Babel 轉(zhuǎn)換
轉(zhuǎn)換前
class Person {
// 公有屬性
sex = '中性'
// 私有屬性
#height = 160
// constructor 構(gòu)造函數(shù) 一個(gè)類只能有一個(gè)
// 一個(gè)構(gòu)造函數(shù)可以使用 super 關(guān)鍵字來(lái)調(diào)用一個(gè)父類的構(gòu)造函數(shù)凰兑。
constructor(name, age, height) {
this.name = name
this.age = age
this.#height = height
}
// Getter
get info() {
console.log('name: ' + this.name + '-- age: ' + this.age)
}
// Methods
log() {
console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex + '-- #height: ' + this.#height)
}
// static
// 靜態(tài)方法 作用于類本身
// 只有類本身才能調(diào)用
static getName() {
console.log(this.name)
}
static a = 1
}
class Man extends Person {
// 子類中定義了構(gòu)造函數(shù)妥粟,那么它必須先調(diào)用 super() 才能使用 this
constructor(name, age, height, sex) {
super(name, age, height)
this.sex = sex
}
log() {
//+ '-- #height: ' + this.#height
// #height 私有的在這里拿不到
console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex)
}
}
const man = new Man('Joe', 10, 90, '男')
轉(zhuǎn)換后
// 全都運(yùn)行在嚴(yán)格模式下
"use strict";
function _typeof(obj) {
"@babel/helpers - typeof";
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _inherits(subClass, superClass) {
// 超類必須是 funciont or null
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
// 繼承
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
// 動(dòng)態(tài)這是原型對(duì)象的指向
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _createSuper(Derived) {
return function () {
// 拿到超類
var Super = _getPrototypeOf(Derived), result;
if (_isNativeReflectConstruct()) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
// 通過(guò) apply 的方式
// 繼承成員屬性
result = Super.apply(this, arguments);
}
// 返回當(dāng)前子類的實(shí)例
return _possibleConstructorReturn(this, result);
};
}
function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
function _assertThisInitialized(self) {
// 還沒有被初始化- super()還沒有被調(diào)用
// void 0 相當(dāng)于 undefined
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
// 判斷是否支持 Refect or Proxy
function _isNativeReflectConstruct() {
// Reflect 是一個(gè)內(nèi)置的對(duì)象,它提供攔截 JavaScript 操作的方法聪黎。這些方法與proxy handlers的方法相同罕容。Reflect不是一個(gè)函數(shù)對(duì)象备恤,因此它是不可構(gòu)造的。
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
// 判斷 Reflect 是否存在
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
// sham 屬性暫不知道有啥用
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Date.prototype.toString.call(Reflect.construct(Date, [], function () {
}));
return true;
} catch (e) {
return false;
}
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
// 判斷當(dāng)前 this 是不是 構(gòu)造函數(shù)的實(shí)例
function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return !!right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}
// 不能已函數(shù)的形式調(diào)用類
function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
// 終止程序
throw new TypeError("Cannot call a class as a function");
}
}
// 設(shè)置一些描述屬性并綁定值
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
// 給原型添加方法
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
// 添加靜態(tài)方法
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
function _classPrivateFieldGet(receiver, privateMap) {
var descriptor = privateMap.get(receiver);
if (!descriptor) {
throw new TypeError("attempted to get private field on non-instance");
}
if (descriptor.get) {
return descriptor.get.call(receiver);
}
return descriptor.value;
}
function _classPrivateFieldSet(receiver, privateMap, value) {
var descriptor = privateMap.get(receiver);
if (!descriptor) {
throw new TypeError("attempted to set private field on non-instance");
}
if (descriptor.set) {
descriptor.set.call(receiver, value);
} else {
// 試圖設(shè)置只讀私有字段
if (!descriptor.writable) {
throw new TypeError("attempted to set read only private field");
}
descriptor.value = value;
}
return value;
}
var Person = /*#__PURE__*/function () {
// 構(gòu)造函數(shù)
function Person(name, age, height) {
// 判斷構(gòu)造函數(shù)的調(diào)用方式
_classCallCheck(this, Person);
// 給當(dāng)前實(shí)例添加 sex 屬性
_defineProperty(this, "sex", '中性');
// 私有屬性
_height.set(this, {
writable: true,
value: 160
});
// 添加成員屬性
this.name = name;
this.age = age;
// 設(shè)置私有屬性
_classPrivateFieldSet(this, _height, height);
}
_createClass(Person, [{ // 原型上的方法
key: "log",
value: function log() {
console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex + '-- #height: ' + _classPrivateFieldGet(this, _height));
}
}, {
key: "info",
get: function get() {
console.log('name: ' + this.name + '-- age: ' + this.age);
}
}], [{ // 靜態(tài)方法
key: "getName",
value: function getName() {
console.log(this.name);
}
}]);
return Person;
}();
// WeakMap 以對(duì)象做于 key ,值為任意類型
// 弱引用 不影響垃圾回收機(jī)制
var _height = new WeakMap();
// 靜態(tài)屬性
_defineProperty(Person, "a", 1);
var Man = /*#__PURE__*/function (_Person) {
// 實(shí)現(xiàn)繼承 并 動(dòng)態(tài)綁定構(gòu)造函數(shù)的原型對(duì)象
_inherits(Man, _Person);
// 創(chuàng)建一個(gè)獲取父類的方法
// 返回一個(gè)函數(shù)
var _super = _createSuper(Man);
function Man(name, age, height, sex) {
var _this;
_classCallCheck(this, Man);
// 調(diào)用父類的構(gòu)造函數(shù)
_this = _super.call(this, name, age, height);
_this.sex = sex;
return _this;
}
_createClass(Man, [{
key: "log",
value: function log() {
console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex);
}
}]);
return Man;
}(Person);
var man = new Man('Joe', 10, 90, '男');
// 動(dòng)態(tài)的將 Man.__proto__ 指定成 Person
// 默認(rèn)應(yīng)該指向 Function.prototype
console.log(Man.__proto__ === Person) // true
console.log(Man.__proto__ === Function.prototype) // false
【筆記不易锦秒,如對(duì)您有幫助露泊,請(qǐng)點(diǎn)贊,謝謝】