function Animal (name, age) {
this.name = name;
this.age = age;
}
构造函数的缺点
- 不看函数体, 无法知道是普通函数还是构造函数
- 构造函数当做普通函数执行, 会产生全局变量.
es6 class
class Animal {
}
console.log(typeof Animal);/ function
babel翻译
"use strict";
/ 可以看出 这个函数的作用,就是为了让构造函数只能用 new 的方式进行调用
function _classCallCheck(instance, Constructor) {
if(!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Animal = function Animal() {
_classCallCheck(this, Animal);
};
- 只能通过 new 进行调用
Animal();/ 报错
new Animal();/ 不报错
- 在同一个块级作用域下,不允许重复声明
- 先定义后使用, 也就是有暂时性死区(TDZ)
constructor
class Animal {
/注意在这里定义函数 不能出现 function (){} 只能用es6声明函数的方法
constructor(name, age = 18){
this.name = name;
this.age = age;
}
}
console.log(Animal.prototype.constructor == Animal);/ true
- 可知 class {} 这个大括号不是 对象, 是一种语法糖
- 语义化很好, 类名, 构造函数 两个概念分了开来.
- 疑问? 在 这个类里定义的函数, 是在这个类的 原型上定义嘛?
是的
为什么用原型?
- 增加代码复用性
- 节省空间
class Animal {
constructor(name, age = 18){
this.name = name;
this.age = age;
}
/ 相当于定义在原型上.
showName () {
console.log(this.name);
}
}
let dog = new Animal('dog',2);
console.log(dog.showName == Animal.prototype.showName);/true
可知, 在class{ } 里定义的函数, 就是定义在原型上的.
什么是静态属性,静态方法? 就像 jq里的工具方法
对应的是 实例方法, 原型链上的方法.
例子Object.is()
class Animal {
constructor(name, age = 18){
this.name = name;
this.age = age;
}
showName () {
console.log(this.name);
}
/ 相当于 Animal.createInstance 在Animal 函数上进行定义
static createInstance (name,age) {
return new Animal(name,age)
}
static a = 123/ 报错
}
let dog = Animal.createInstance('dog',2);
console.log(dog);
可知, static 方式只能在 Animal 上定义方法, 暂不能定义属性
一等公民 class function
- 可以当做参数
- 可以被返回
- 可以立即执行
- 可以赋值给其他变量
当参数
function create (fn) {
return new fn();
}
let obj = create(class{
constructor (){
this.name = 'mike'
}
});
console.log(obj);
立即执行
let obj = new class {
constructor (name ){
this.name = name;
}
}('mike');
console.log(obj);
被返回
function returnClass () {
let count = 0;
return class{
constructor (name) {
this.name = name;
this.count = count;
}
}
}
let obj = new (returnClass())('mike')/ 正常
/这里可以看出 默认会先 执行 new returnClass, 再对返回函数进行()执行
let obj = new returnClass()('mike')/ 报错
console.log(obj);
class 生成器方法
class iteratorArray {
constructor (arr = []) {
this.arr = arr;
}
*[Symbol.iterator](){
yield *this.arr[Symbol.iterator]()
}
}
let arr = new iteratorArray([1,2,3]);
for(let item of arr) {
console.log(item);
}
上面的代码到底干了什么?
一个类返回的对象可以通过 设置 *Symbol.iterator{yield} , 进行迭代
yield *this.arrSymbol.iterator 的意思是把arr的指针添加进实例对象的指针组之中.
测试 可以 yield * this.arr, 因为默认会调用arr的迭代器[Symbol.iterator]
class iteratorArray {
constructor (arr = []) {
this.arr = arr;
}
*[Symbol.iterator](){
yield *this.arr
}
}
let arr = new iteratorArray([1,2,3]);
for(let item of arr) {
console.log(item);
}
测试: 我们可以任意的添加各种指针
class iteratorArray {
constructor (arr = [],arr1 = []) {
this.arr = arr;
this.arr1 = arr1;
}
*[Symbol.iterator](){
yield *this.arr;
yield *this.arr1;
yield *[7,8,9];
yield 10
}
}
let arr = new iteratorArray([1,2,3],[4,5,6]);
for(let item of arr) {
console.log(item);
}
测试是否可以用next
继承,
增加代码复用
类,本身的概念里就包好,要把相似共同的部分抽象出来
es5继承
function Father (name,age) {
this.name = name;
this.age = age;
}
Father.prototype.showName = function () {
console.log(this.name);
}
function Son () {
Father.call(this);
}
严格来讲, 实际上是有几种继承方式的
这几种方式,都会继承但不会让父级实例化,
或者说, 这几种算是 无new继承
Son.prototype = Object.create(Father.prototype);
Son.prototype.__proto__ = Father.prototype;
Object.setPrototypeOf(Son.prototype,Father.prototype);
当然最经典的继承 应该是 new 实例化
圣杯继承
function temp () {}
temp.prototype = Father.prototype;
Son.prototype = new temp();
es6继承
class Animal {
constructor (name = 'mike', age) {
console.log(name);
this.name = name;
this.age = age;
}
showName(){
console.log(this.name);
}
}
子类,派生类
class Person extends Animal {
constructor(name){
super(name)
/相当于 Animal.call(this,name)
/ 或者应该这么理解?
/this = new Animal() / 返回一个this?
}
show () {
console.log(super.showName = Animal.prototype.showName);/true
console.log(super == Animal.prototype);/ 报错,
}
}
let p = new Person();
注意, 子类使用extends 继承父类时, constructor里一定要有super字段
否则报错.
不许把super() 放在 this.赋值语句的前面,否则报错.
super 作为对象的时候, 指向的是父类的原型 Father.prototype,
但this自动指向实例
super 必须执行,或者调用属性, 否则报错?
好奇,babel怎么翻译的
'use strict';
// 这是用来在 原型上或者构造函数上定义函数用的.
var _createClass = 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);
}
}
return function(Constructor, protoProps, staticProps) {
if(protoProps) defineProperties(Constructor.prototype, protoProps);
if(staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
// 返回最终的实例, 要跟下面调用的语句一起看
function _possibleConstructorReturn(self, call) {
if(!self) {
// 这一句确实不太懂, 如果new 了个构造函数, 有可能会让this 是 undefined嘛?
// 下面报错信息翻译 大概是说, super 没有被调用, 初始化失败?
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
// 用来继承的
function _inherits(subClass, superClass) {
确保 传入的是个函数
if(typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
生成目标构造函数的原型,并继承 父级构造函数的原型,
并且让目标原型的构造函数指向目标构造函数.
我这说的肯定不是人话.
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
这一句非常,相当的让人意外,
此前考虑过继承的时候,从来没有考虑这个东西,
这一句的意思是, 让目标构造函数继承 父级构造函数.
这是把函数当成了对象.
我有点明白了, 因为函数上有可能定义一些函数和属性,
单纯只是原型上的继承,无法继承这一类的函数和属性.
真是周密啊周密.
if(superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
// 这是用来 保证 用 new
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Animal = function () {
function Animal() {
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'mike';
var age = arguments[1];
_classCallCheck(this, Animal);
console.log(name);
this.name = name;
this.age = age;
}
_createClass(Animal, [{
key: 'showName',
value: function showName() {
console.log(this.name);
}
}]);
return Animal;
}();
var Person = function (_Animal) {
让原型和函数各自继承
_inherits(Person, _Animal);
function Person(name) {
保证用new 的方式调用
_classCallCheck(this, Person);
return _possibleConstructorReturn(this, (Person.__proto__ || Object.getPrototypeOf(Person)).call(this, name));
}
return Person;
}(Animal);
var p = new Person();
好奇害死猫, 陌生字段有点多, 回头再看吧...