《ES6标准入门》学习笔记
//1,声明关键字:const、let
const plus1 = a => a + 1;
const mult2 = b => b * 2;
console.log(mult2(plus1(1)));
//plus1 = 2;//const声明的变量的值不能重新被赋值
//let声明一个块级作用域,只在其所在包含块中有效。
//2 箭头函数=>
//箭头函数
/*
1.参数 => 返回值
2.this绑定(其内部并没有this,因此也不能作为构造函数和new构造器组合使用)
3.等同于匿名函数
4. 不能使用call、apply、bind方法
*/
console.log([1,2,3].map(x => x +1));//[2,3,4]
//箭头函数绑定this
let handler = {
id: '123456',
init:function () {
//因为箭头函数中没有this,所以下行代码中的this为init方法的this,指向handler
document.addEventListener('click', event => this.doSomething(event.type), false);
},
doSomething: function (type) {
console.log("Handling " + type + " for " + this.id);
}
};
handler.init();
//箭头函数练习
function foo() {
return () => {
return () => {
return () => {
console.log("id:", this.id);
}
}
}
}
foo.call({id: "zgatry"})()()();//输出zgatry,这里通过.call把foo函数内部的this指向了{id:"zgatry"}对象
//箭头函数也不像其他函数一样自带类数组arguments
function fn() {
setTimeout(() => {
//这里的arguments其实是fn函数的arguments
console.log("args:", arguments);
}, 1000);
}
fn("zgatry", 2, 3, 4);//输出"zgatry", 2, 3, 4
//箭头函数总结:主要用于解决this绑定、简化函数提升可读性问题。<<----个人理解
//关于this绑定的问题,ES7提出了“::”this绑定符。它会将符号左边的对象作为右边代码的this指向。该符号返回的是原对象,可以进行链式写法。
//尾调用优化:在一个函数的最后一步调用另一个函数
//函数调用——在内存形成调用记录(调用帧)——嵌套调用时,外部函数必须等内部的函数执行完毕,它的调用帧才会消失。它们的组合形成“调用栈”。
//所以调用帧最好是及时清除,否则对内存是极大的消耗。
//尾调用优点:及时清除外部函数的调用帧,减少调用帧的个数。
//注意:尾调用优化在严格模式才会生效
//例如:
function plusThenMult(a, b) {
var val = a + b;
console.log("加的结果", val);
return mult(a, b);
}
function mult(a, b) {
var val = a * b;
console.log("乘的结果", val);
}
plusThenMult(1,2);
//尾调用不一定出现在尾部,只要求是最后一步。
//尾调用拓展——尾递归, 还涉及到复杂度
//阶乘函数的例子
//尾递归的方式
function factorial(n, total) {
if(n === 1) return total;
return factorial(n - 1, n * total);
//只有一个调用帧,复杂度O(1);
}
//正常的方式
function factor2(n) {
if(n === 1) return 1;
return n * factor2( n - 1);
//形成多层调用帧,容易发生栈溢出错误stack overflow
//形成n层调用帧,复杂度O(n);
}
//尾调用优化对递归操作意义大
//上面使用尾调用优化的阶乘函数传参怪怪的,我要得到5的阶乘,还要这样传 (5, 1);
//使用ES6的函数默认值就优雅多了
//改写
function factorial(n, total = 1) { //默认值只有在total为undefined时才生效
if(n === 1) return total;
return factorial(n - 1, n * total);
//只有一个调用帧,复杂度O(1);
}
console.log("5的阶乘:",factorial(5));//输出120
//Symbol
/*
新的原始数据类型——独一无二——由Symbol函数生成——类似于字符串
*/
let s = Symbol();
console.log(typeof s);
let s1 = Symbol('foo'); //Symbol传参用以与其他值区分,解释该值。
let s2 = Symbol('bar');
s1.toString();
s2.toString();
console.log(s1);
console.log(s2);
//主要用于对象的属性名的标示符,避免属性名重复导致属性被覆盖的问题
//增强的对象写法
let s3 = Symbol('test');
let obj = {
[s](args) {
console.log(1);
},
name: 'zgatry'
}
console.log(obj[s]);
//ES6的class类————ES5的构造函数的一层包装
class userMethod {
constructor (ele) {
this.$class = ele;
}
renderHtml () {
console.log('渲染用户页面');
return true;
}
}
let userInfo = new userMethod('zgatry');
userInfo.renderHtml();
console.log(userInfo.$class);
//所有的实例共享一个原型对象
let user1 = new userMethod('aoao');
let user2 = new userMethod('aobo');
console.log("相同的原型对象?", user1.__proto__ === user2.__proto__);
//实例为原型添加方法<<---不推荐使用
user1.__proto__.plus = function (val){
return val + 1
}
console.log("原型方法添加成功", user2.plus(2));
//不存在变量提升:ES不会把变量声明提升到代码头部 let命令也是不提升的
// new Foo();//Foo is not defined
// class Foo{}
//上面的特性与继承有关:为了保证子类在父类之后定义。
{
let Foo = class {};
class Bar extends Foo { //通过extend关键字进行继承
}
}
//关于继承
//继续使用上面的userMethod的类
class VIPuser extends userMethod {
constructor($class, VIPnumber) {
super($class); //调用父类的constructor(x, y); 不调用该方法会报错 不加$class则继承不到父类的属性但this可以用了
this.VIPnumber = VIPnumber; //子类没有this,需要通过super关键字,它指代了父类的实例(即父类的this对象)
}
}
let VIP1 = new VIPuser('bobo', 1);
console.log(VIP1.$class, VIP1.renderHtml(), VIP1.VIPnumber);
//两条继承链的解释和说明
//例子
class A {}
class B extends A {}
//1.作为对象,B的原型(__proto__)就是父类A;
B.prototype.__proto__ = A.prototype;
//2.作为构造函数, 子类B的原型(prototype属性)是父类的实例.
B.prototype = new A();
//class的存值函数和取值函数,为某个属性添加取值和存值, 捕获取值和存值行为
class MyClass {
constructor() {
//...
}
get prop() {
console.log('getter');
}
set prop(value) {
console.log('setter:', value);
}
}
var inst = new MyClass();
inst.prop = 123;
inst.prop;
//ES6在类和模块的内部默认使用严格模式
//Generator方法 在方法前加*表示 暂不拓展
//静态方法与静态属性 在方法前加static表示
/*
1.静态方法不会被实例继承
2.静态方法可以被子类继承
3.只能直接通过类调用。
4.但也可以通过super对象调用(因为super是父类的this)
*/
class Foo {
static classMethod () {
return 'hello'
}
}
class Bar extends Foo {
static classMethod () {
return super.classMethod() + ', too';
}
}
console.log(Bar.classMethod());
//静态属性
//两种无效的写法
// class Foo {
// //写法一
// prop:2
// //写法二
// static prop:2
// }
//实例属性的新写法 ES7
// class Myclass {
// myProp = 42;
// constructor () {
// console.log(this.myProp);//42
// }
// }
// class Myclass {
// static myStaticProp = 42;
// constructor () {
// console.log(Myclass.myProp);//42
// }
// }
/*
模块
Module语法是JavaScript的标准语法
1.使用import替代require
2.使用export替代module.exports
//bad
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;
//good
import {func1, func2} form 'moduleA';
//CommonJs 写法
var React = require('react');
var Breadcrumbs = React.createClass({
render () {
return <nav />;
}
});
module.exports = Breadcrumbs;
//ES6写法
import React from 'react';
const Breadcrumbs = React.createClass({
render () {
return <nav />;
}
});
export default Breadcrumbs; //只有一个输出值的时候使用default,多个值就不适用。
*/
/*
异步操作和async函数
ES6前异步编程的方法
1.回调函数
2.事件监听
3.发布-订阅
4.promise对象
回调函数
-->>回调函数噩梦:多个回调函数嵌套的问题上,比如说依次读取多个文件,就会出现多重嵌套,代码很快就会乱做一团。
fs.readFile(fileA, function(err, data) {
fs.readFile(fileB, function(err, data) {
//...
})
})
Promise
Promise允许将回调函数的横向加载改成纵向加载。
Promise 提供了then方法用于执行回调函数,catch方法捕捉执行过程中跑出的错误。
缺点:代码冗余,缺乏语义化。
var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function(data) {
console.log(data.toString());
})
.then(function() {
return readFile(fileB);
})
.then(function(data) {
console.log(data.toString);
})
.catch(function(err) {
console.log(err);
});
基于Promise对象的自动执行器
var fs = require('fs');
var readfile = function(fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if(error) reject(error);
resolve(data);
});
});
};
var gen = function* () {
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
//手动执行Generator函数
var g = gen();
g.next().value.then(function(data) {
g.next().value.then(function(data) {
g.next(data);
});
});
//手动操作其实就是通过then层层执行回调函数。
//现在来写自动执行器
var run = function(gen) {
var g = gen();
function next() {
var result = g.next(data);
if(result.done) return result.value;
result.value.then(function(data) {
next(data);
});
}
next();
};
//这样Generator函数就可以自动执行了。
run(gen);
async函数———Generator函数的语法糖
用async实现读取两个文件的范例:
var asyncReadFile = async function() {
var f1 = await readFile('/etc/fatab');
var f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
var result = asyncReadFile();
*/
editTime: 2016/10/09
行为影响状态,状态影响视图