-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES6-class #18
Comments
class 没有变量名提升,无法在定义之前使用。 |
named or unnamed// unnamed // named |
class 的内容定义在大括号中,并且其中开启了严格模式 |
constructorconstructor 用于创建和初始化类,一个类中有多个constructor时,会报语法错误(SyntaxError: 解析代码时,Javascript引擎发现了不符合语法规范的tokens或token顺序时抛出SyntaxError)。 |
Prototype methods定义在原型上的方法 |
静态属性值和原型上的属性值必须定义在class外部Rectangle.staticWidth = 20; |
基本的类的定义到此为止。看一下babel是如何处理的 |
class Animal {
constructor() {
this.name = 'animal';
}
speak() {
console.log('speak');
}
static eat() {
console.log('eat');
}
}
Animal.staticValue = 1;
Animal.prototype.prototypeWidth = 2; |
"use strict";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
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);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
var Animal =
/*#__PURE__*/
(function() {
function Animal() {
_classCallCheck(this, Animal);
this.name = "animal";
}
_createClass(
Animal,
[
{
key: "speak",
value: function speak() {
console.log("speak");
}
}
],
[
{
key: "eat",
value: function eat() {
console.log("eat");
}
}
]
);
return Animal;
})();
Animal.staticValue = 1;
Animal.prototype.prototypeWidth = 2; |
|
ES6中是不支持在类中直接声明字段的,所有的声明必须在构造函数内。虽然新的草案还没有正式通过,我们可以使用babel-plugin-proposal-class-properties.先来体验一下。 |
修改demo里的代码如下: class Animal {
constructor() {
this.name = 'animal';
}
speak1() {
console.log('speak');
}
speak2 = () => {
console.log('speak2');
}
speak3 = function (){
console.log('speak3');
}
} |
经过babel之后,可以看出,声明的字段方法全部放到了构造函数内,而不是原型上。如果有多个实例,性能相比原型方法就会下降。 var Animal =
/*#__PURE__*/
function () {
function Animal() {
_classCallCheck(this, Animal);
this.speak2 = function () {
console.log('speak2');
};
this.speak3 = function () {
console.log('speak3');
};
this.name = 'animal';
}
_createClass(Animal, [{
key: "speak1",
value: function speak1() {
console.log('speak');
}
}]);
return Animal;
}(); |
为什么不为了性能,把箭头函数也绑定到原型上呢?这和箭头中的this不会创建自己的this,而是从自己的作用域链的上一层继承this有关。例如: class Animal {
constructor() {
this.name = 'animal';
}
speak1() {
console.log(this);
}
speak2 = () => {
console.log(this);
}
speak3 = function (){
console.log(this);
}
}
var a = new Animal();
var speak1 = a.speak1;
var speak2 = a.speak2;
var speak3 = a.speak3;
speak1(); //undefined
speak2(); //Animal{}
speak3(); //undefined 为了实现这一点,babel需要将两种声明方式做区分。为了做到这一点,做了不少hack,JS真的是太男了。babel转换后代码如下: var Animal =
/*#__PURE__*/
function () {
function Animal() {
var _this = this;
_classCallCheck(this, Animal);
this.speak2 = function () {
console.log(_this);
};
this.speak3 = function () {
console.log(this);
};
this.name = 'animal';
}
_createClass(Animal, [{
key: "speak1",
value: function speak1() {
console.log(this);
}
}]);
return Animal;
}();
|
extends 创建子类 |
继续扩展原来的例子, 新建Animal的子类 class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
constructor() {
super();
}
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak(); |
babel编译之后的代码,省略了部分无关代码。 "use strict";
function _typeof(obj) { }
function _possibleConstructorReturn(self, call) {
if (
call &&
(_typeof(call) === "object" || typeof call === "function")
) {
return call;
}
return _assertThisInitialized(self);
}
// 判断是否先调用了父类构造函数。
// 构造函数内不调用super就会报错??? 和我想的不太一样
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError(
"this hasn't been initialised - super() hasn't been called"
);
}
return self;
}
function _getPrototypeOf(o) {
return Object.getPrototypeOf(o);
}
// 组合寄生式继承
function _inherits(subClass, superClass) {
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) {
return Object.setPrototypeOf(o, p);
}
function _classCallCheck(instance, Constructor) { }
function _defineProperties(target, props) {}
function _createClass(Constructor, protoProps, staticProps) {}
var Animal =
/*#__PURE__*/
(function() {
function Animal(name) {
_classCallCheck(this, Animal);
this.name = name;
}
_createClass(Animal, [
{
key: "speak",
value: function speak() {
console.log(this.name + " makes a noise.");
}
}
]);
return Animal;
})();
var Dog =
/*#__PURE__*/
(function(_Animal) {
_inherits(Dog, _Animal);
function Dog() {
_classCallCheck(this, Dog);
return _possibleConstructorReturn(
this,
_getPrototypeOf(Dog).call(this)
);
}
_createClass(Dog, [
{
key: "speak",
value: function speak() {
console.log(this.name + " barks.");
}
}
]);
return Dog;
})(Animal);
var d = new Dog("Mitzie");
d.speak(); |
假如Animal 和 Dog都有static speak方法,并且在Dog的speak方法中还调用了Animal的speak方法,如下: static speak() {
super.speak();
console.log('dog speak');
} 这时super应该指向的是构造函数,而不是实例了。经过babel转化为下: _createClass(Dog, null, [
{
key: "speak",
value: function speak() {
// 获取构造函数原型对象即构造函数Animal上的speak方法。
_get(_getPrototypeOf(Dog), "speak", this).call(this);
console.log("dog speak");
}
}
]); 重点在_get 方法 function _get(target, property, receiver) {
if (typeof Reflect !== "undefined" && Reflect.get) {
// 类似于target[property],只不过是通过调用函数来实现,最关键的是第三个参数,如果target对象中指定了getter,receiver则为getter调用时的this值。
_get = Reflect.get;
} else {
_get = function _get(target, property, receiver) {
// 按照原型链向上寻找,直到找到对应的property
var base = _superPropBase(target, property);
if (!base) return;
var desc = Object.getOwnPropertyDescriptor(base, property);
if (desc.get) { // getter,执行getter并且指定其中this值
return desc.get.call(receiver);
}
return desc.value; // 普通方法
};
}
return _get(target, property, receiver || target);
} |
继承的几种方式 |
原型链Child.prototype = new Parent(); function Parent() {
this.colors = [1, 2];
}
function Child(){}
Child.prototype = new Parent();
var c1 = new Child();
var c2 = new Child();
c1.colors.push(3);
console.log(c2.colors); // [1, 2, 3] |
借用构造函数function Child() {
Parent.call(this);
} 缺点:无法复用原型上的函数 |
组合继承使用借用构造函数继承属性,原型链继承方法 缺点:会调用两次父类构造函数,并且在子类原型上有多余的属性(来自原型链继承),例如 function Child() {
Parent.call(this);
}
// 这里存在多余属性
Child.prototype = new Parent(); |
原型式继承这种方法没有严格意义上的构造函数,借助已有的对象创建新对象 function object(o) {
function F(){}
F.prototype = o;
return new F();
}
function object(o) {
return Object.create(o);
} |
寄生式继承创建一个仅用于封装继承过程的函数 function createChild(o) {
var child = object.create(o);
// 增强对象
child.sayHi = function() {};
reutrn child;
} |
寄生组合式继承是对组合继承的一种优化,优化组合继承中的原型链部分,少调用一次父类构造函数 function inherit(child, parent) {
// 创建父类原型副本
var prototype = Object.create(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
function Parent() {}
function Child() {
Parent.call(this);
}
inherit(Child, Parent); |
No description provided.
The text was updated successfully, but these errors were encountered: