es7
最新 es6关于在js中手写class (es6)类的说明方法
参考 mdn, es6,es7 的方法形式内容
mdn参考说明:
ECMAScript6 引入了一套新的关键字用来实现 class。使用基于类语言的开发人员会对这些结构感到熟悉,但它们是不同的。javaScript 仍然基于原型。这些新的关键字包括 class, constructor,static,extends 和 super。
1.关于super 中的说明:
另一个需要注意的地方是,在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例。
类似于java中的 继承来自于父亲的说法
Object.getprototypeOf(colorPoint) === Point
使用这个方法判断,一个类是否继承了另一个类。
第一种情况:
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。
class A {}
class B extends A {
constructor() {
super();
}
}
上面代码中,子类B的构造函数之中的super(),代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。
注意,super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。
第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
例1:普通方法
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p()); // 2
}
}
let b = new B();
上面代码中,子类B当中的super.p(),就是将super当作一个对象使用。这时,super在普通方法之中,指向A.prototype,所以super.p()就相当于A.prototype.p()。
例2:静态方法
class parent {
static myMethod(msg) {
console.log('static', msg);
}
myMethod(msg) {
console.log('instance', msg);
}
}
class Child extends Parent {
static myMethod(msg) {
super.myMethod(msg); // // 只有在子类的静态函数中才能调用父类的静态函数(babel环境测试, //按理说,在实例函数中应该也可以调用,不过实际测试环境中报错)
}
myMethod(msg) {
super.myMethod(msg);
}
}
Child.myMethod(1); // static 1 调用的是子类静态方法,子类静态调用父类的静态方法
var child = new Child();
child.myMethod(2); // instance 2 调用子类的一般方法,在一般方法里面继承来自父类的一般方法
super在静态方法之中指向父类,在普通方法之中指向父类的原型对象。
另外,在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例
=================================================
2.静态方法
.注意注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。
如:(static 里面的是类的方法,不含static 的是实例对象的方法)
Class 内部只有静态方法,没有静态属性。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello' 调用的是类本身的方法
var foo = new Foo();
foo.classMethod()// TypeERROR: foo.classMethod is not a function ,调用的是实例的方法
class Foo {
static bar () { // 第2步
this.baz(); //第3步
}
static baz () {
console.log('hello'); //第4步
}
baz () {
console.log('world'); //这是实例的方法
}
}
Foo.bar() // hello 第1步
class 的静态属性和实例属性
(1)类的实例属性
类的实例属性可以用等式,写入类的定义之中。
class MyClass {
myProp = 42;
constructor() {
console.log(this.myProp); // 42
}
}
(2)类的静态属性
类的静态属性只要在上面的实例属性写法前面,加上static关键字就可以了。
class MyClass {
static myStaticProp = 42;
constructor() {
console.log(MyClass.myStaticProp); // 42
}
}
3.关于class的简写形式;对比java更加相似,简单
原来
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
现在
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
其实也是在原行上的方法
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
class B {}
let b = new B();
b.constructor === B.prototype.constructor // true
4.构造方法
加图理解
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加
方法之间不需要逗号分隔,加了会报错。
类不存在变量提升(hoist),这一点与 ES5 完全不同。
5关于私有方法属性改怎么写?
class Widget {
foo (baz) {
bar.call(this, baz);
}
// ...
}
function bar(baz) {
return this.snaf = baz;
}
上面代码中,foo是公有方法,内部调用了bar.call(this, baz)。这使得bar实际上成为了当前模块的私有方法。
另一种方法就是索性将私有方法移出模块,因为模块内部的所有方法都是对外可见的。
还有一种方法是利用symbol值的唯一性,将私有方法的名字命名为一个Symbol值。
例子说明
const bar = Symbol('bar');
const snaf = Symbol('snaf');
export default class myClass{
// 公有方法
foo(baz) {
this[bar](baz);
}
// 私有方法
[bar](baz) {
return this[snaf] = baz;
}
// ...
};
name属性
class Point {}
Point.name // "Point"
6.关于继承的信理解:
1.prototype
2.Object.create
3. class 定义类 ,用extends 来继承来自父类的方法,也是可以的
4.子类.call()的方法,来继承也可以
7.异步函数
例子形式新语法
// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
// Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
const storage = new Storage();
storage.getAvatar('jake').then(…);
// 箭头函数
const foo = async () => {};
语法:async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句
async函数的语法规则总体上比较简单,难点是错误处理机制。只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
await命令
正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。 await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。只要一个await语句后面的 Promise 变为reject,那么整个async函数都会中断执行
出错的时候
async function f() {
await Promise.reject('出错了');
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
关于错误处理的时候用的方法
const superagent = require('superagent');
const NUM_RETRIES = 3;
async function test() {
let i;
for (i = 0; i < NUM_RETRIES; ++i) {
try {
await superagent.get('http://Google.com/this-throws-an-error');
break;
} catch(err) {}
}
console.log(i); // 3
}
test();
注意点
第一点,前面已经说过,await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
第二点,多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
第三点,await命令只能用在async函数之中,如果用在普通函数,就会报错。
关于super的说法更新实例
类的 prototype 属性和__proto__属性
例子
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
解释
(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。
(2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
看图理解
(关键是学生的prototype 是指向的人们的实例的,)
例子:
var p1 = new Point(2, 3);
var p2 = new ColorPoint(2, 3, 'red');
p2.__proto__ === p1.__proto__ // false
p2.__proto__.__proto__ === p1.__proto__ // true
子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型。
看上图的理解
min模式的实现方法
对象的扩展运算符
结构赋值的例子
对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
const o = Object.create({ x: 1, y: 2 });
o.z = 3;
let { x, ...newObj } = o;
let { y, z } = newObj;
x // 1
y // undefined
z // 3
let { x, ...{ y, z } } = o;
结构赋值只是浅拷贝,ES6 规定,变量声明语句之中,如果使用解构赋值,扩展运算符后面必须是一个变量名,
例子
对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
这等同于使用Object.assign方法。就是把多个对象,拷贝到一个对象中
let aclone = { ...a };
// 等同于
let aClone = Object.assign({}, a);
关于模块的说明import export
对比 common.jd, AMD是运行是就确定了, import 是静态的加载
module已经规定了编译时加载,而且自动架子啊为严格模式,
export 输出是要加大括号的
export default 制定默认输出,本质是default 的变量和方法
模块之间的继承
跨模块的常量
例子
// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4;
// test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 3
// test2.js 模块
import {A, B} from './constants';
import() 实现动态的加载文件
例子
import()加载模块成功以后,这个模块会作为一个对象,当作then方法的参数。因此,可以使用对象解构赋值的语法,获取输出接口
import('./myModule.js')
.then(({export1, export2}) => {
// ...·
});
模块的加载实现方式
1.浏览器加载
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
defer 等整个页面渲染完加载
asyn是异步加载
加moudule 相当于是模块的动态加载
<script type="module" src="./foo.js"></script>
<!-- 等同于 -->
<script type="module" src="./foo.js" defer></script>
讨论 Node 加载 ES6 模块之前,必须了解 ES6 模块与 CommonJS 模块完全不同。
2者的差异
它们有两个重大差异。
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
ES6 模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。
由于 ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
相关阅读
消息队列为什么写这篇文章?博主有两位朋友分别是小A和小B:小A,工作于传统软件行业(某社保局的软件外包公司),每天工作内容就是和产
网站上线后,不知道用户点击了网页那些地方?也许SEO站长可以试试百度统计热力图工具,该工具可以让站长清楚网页那些位置是点击次数最
现在人们生活质量提升,对于生活的消费也逐渐有所提高。人们在自己工作的闲暇之余,可以做一些兼职来赚钱一些零花钱。越来越多的微商
毋庸置疑,大数据市场是一座待挖掘的金矿。随着数据使用量的增长,将有更多的人通过数据来寻求专业问题的答案。可视化数据分析工具的
1月9日,发现百度分享的的数据用大拇指显示在了百度快照上,当时一阵狂喜。因为当初安这个东西没什么特别的目的,就是为了便于大家分享