您的位置:首页 > 其它

关于es7,es8值得说的地方,你一定不知道

2018-09-19 14:12 441 查看
版权声明:转载请说明出处 https://blog.csdn.net/qq_33167665/article/details/82771266

最新 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 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。

 

 

 

 

 

 

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐