ES6-Class 类

__proto______ 指向所属类的原型 浏览器中 (1).__proto________打印下
prototype 所有类都有一个prototype属性
constructor prototype.constructor 每个类的原型上都有这个属性

继承: 继承公共属性     继承实例上的属性
1
2
3
4
5
6
7
8
9
// 每个类上都有constructor 放置实例上的属性
class Animal{
constructor(){
this.type = '哺乳类';
}
}
let animal = new Animal();
console.log(animal); // Animal { type: '哺乳类' }
console.log(animal.hasOwnProperty('type'));// true 实例上的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Animal{
type = '哺乳类'; // 这个写法本质上和上面是一样的,只是这里node不支持,要运行用浏览器的console执行即可
say(){ // 放到了原型上 相当于之前的 Animal.prototype.say
console.log("this:", this);
}
}
let animal = new Animal();
let say = animal.say;
say(); // undefined

// 类似于react中
class Animal{
type = '哺乳类';
// 这个写法本质上和上面是一样的,只是这里es6不支持,加了.babelrc中的 插件
// ["@babel/plugin-proposal-class-properties", { "loose" : true }], 然后再运行webpack环境即可
say(){ // 放到了原型上 相当于之前的 Animal.prototype.say
console.log("this:", this);
}
render(){
return <div onClick={this.say.bind(this)}></div>;
}
}
// 这里line20要加bind
// 所以在上面的情况 line8将原型中的say方法拿出来,在es6中默认this就是undefined
class Animal{
type = '哺乳类';
say(){ // 放到了原型上 相当于之前的 Animal.prototype.say
console.log("this:", this);
}
}
let animal = new Animal(); // 如果将类中的方法拿出来用必须绑定this,否则默认指向undefined
let say = animal.say.bind(animal);
say(); // this: Animal {type: "哺乳类"}
有时候要定义个原型上的属性 Animal.prototype.a = 1;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Animal{
type = '哺乳类'; // 实例上的属性
// a = 1; // 这样是定义到实例上了,所以不能这样写
get a(){ // Object.defineProperty
return 1; // 等同于 Animal.prototype.a = 1;
}
say(){
console.log("this:", this);
}
}
let animal = new Animal();
let say = animal.say.bind(animal);
say(); // this: Animal {type: "哺乳类"}
console.log(animal.a); // 1
静态属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal{
type = '哺乳类';
// a = 1;
get a(){
return 1;
}
say(){
console.log("this:", this);
}
// 静态属性 定义到类上的属性
static flag = '动物'; // es6中是不支持这样等号赋值的,因为加了插件
}
let animal = new Animal();
console.log(Animal.flag); // 动物
console.log(animal.__proto__.constructor.flag); // 动物
静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Animal{
// type = '哺乳类'; // 这行也不支持
get a(){
return 1;
}
say(){
console.log("this:", this);
}
// 静态方法
static flag(){
return '动物'
};
}
let animal = new Animal();
console.log(Animal.flag()); // 动物
console.log(animal.__proto__.constructor.flag); // 动物

// 如果不想要方法 就想是属性 如下:
class Animal{
// type = '哺乳类';
get a(){
return 1;
}
say(){
console.log("this:", this);
}
// 静态属性
static get flag(){
return '动物'
};
}
let animal = new Animal();
console.log(Animal.flag); // 动物
类之间的继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 现在我希望Tiger继承Animal中的constructor实例上的属性和原型上的方法(say)
class Animal{
constructor(){
this.type = '哺乳类'
}
say(){
console.log('说话');
}
}
// call + Object.create() + Object.setPrototypeof 下面的继承用了这3个方法
// call(继承实例属性) 在子类中调用父类的构造函数
// Object.create() 继承公有属性
class Tiger extends Animal{

}
let tiger = new Tiger();
console.log(tiger);

打印结果:

1
2
3
4
5
// __proto__ 指向所属类的原型
tiger.__proto__ === Tiger.prototype //true
Tiger.prototype.__proto__ === Animal.prototype //true
// instanceof
tiger instanceof Tiger|Animal|Object // true

将类之间继承的代码 粘贴 => 打开babeljs.io => Try it out => 将内容复制进去 右边显示的就是转换成的es5代码 => 复制到新文件test.js中 => 在把代码格式化下如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// test.js
"use strict";

function _typeof(obj) {
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 _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}

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) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf: function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _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
}
}); //Tiger.__proto__ = Animal
if (superClass) _setPrototypeOf(subClass, superClass);
}

function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ||
function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}

function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return !! right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}

function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, 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.type = '哺乳类';
}

_createClass(Animal, [{ // 创建类
key: "say",
value: function say() {
console.log('说话');
}
}]);

return Animal;
} ();



var Tiger =
/*#__PURE__*/
function(_Animal) {
_inherits(Tiger, _Animal); // 实现了子类继承父类原型上的方法

function Tiger() {
_classCallCheck(this, Tiger); // 判断是否是 Tiger()这样调用的

return _possibleConstructorReturn(this,
// Object.getPrototypeOf
// Tiger.__proto__ = Animal Animal.apply(tiger)
_getPrototypeOf(Tiger).apply(this, arguments));
}

return Tiger;
} (Animal);

var tiger = new Tiger();
console.log(tiger);

// 大致看下
// line38_inherits 继承 line42 子类继承父类 子类的prototype 、 Object.create
// 现在来看下子类的Tiger line114-127 看下line115 line118有个_classCallCheck

刚才看了内部实现 这里面 Tiger.__proto__ = Animal
静态方法、属性在es6中也会被子类继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal{
constructor(){
this.type = '哺乳类'
}
say(){
console.log('说话');
}
static flag = 1;
}
class Tiger extends Animal{
constructor(){
super(); // 调用super 相当于 Animal.call(tiger)
}
}
let tiger = new Tiger();

当new的时候传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 当new的时候传参
class Animal{
constructor(name){ // #4
this.name = name;
this.type = '哺乳类'
}
say(){
console.log('说话');
}
static flag = 1;
}
class Tiger extends Animal{
constructor(name){ // #1
super(name); //#2 调用super 相当于 Animal.call(tiger, name) #3
//这里super指的是父类Animal
}
static getAnimal(){
console.log(super.flag); // super指的是父类
}
say(){ // 自己也有一个say方法
super.say(); // super 指的是 父类的原型
}
}
let tiger = new Tiger('老虎');
Tiger.getAnimal(); // 1
tiger.say(); // 说话
// static get / set super extends
// es6类怎么实现继承的?
// 这里可以再看下 test.js _defineProperties _createClass
// call + Object.create() 实现的继承
// Object.setPrototypeof 链的关联
// 通过Object.defineProperty 实现原型+静态属性 方法的定义
new的原理 未完待续