静态资源变量声明,不能修改变量的指向。即
- 是基本数据类型,则不能修改它的值。
- 是引用数据类型,则不能修改它的指向。
2.1. 不能重复声明,没有变量提升
先定义后使用,变量定义不会自动提升,否则会报变量未定义的错误。
2.2 块作用域
每个大括号被视为一个作用域。逐级外层作用域查找,直到找到为止。
2.3 for语句视为一个作用域
(function(){
let a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
})();
按照我们原有的思维会认为这里应该输出的是10,但并不是。变量i的声明是在for()中,它的作用域就是(),每次循环产生的i并不是同一个i。这样会有人问i++,是怎么执行的。这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
for的特殊使用:
(function(){
for(let i = 0;i<3;i++){
let i = "abc";
console.log(i)
}
for(let i = 0;i<3;i++){
console.log(i)
}
})();
输出:abc abc abc 1 2 3
JS基本数据类型有String、Number、Boolean、Null、Undefined,ES6新增Symbol的基本数据类型。
(function(){
let [name,time] = ["Bob","today"];
let str = `Hello ${name}, how are you ${time}?`
console.log(str)
})();
模板字符串中可以使用${}引用变量,有点类似与JSP的写法。需要注意的是,模板字符串可以将空格、换行如实打印出来。
新增方法,isFinite、isNaN、isInteger
let a = Number.isNaN("abc")
let b = Number.isNaN(Number("abc"));
console.log(a,b) //false true
在ES5中,我们知道NaN===NaN的值是false,判断一个数是不是NaN是不太容易的,ES6直接提供了isNaN方法可以判断是否是NaN。
let firstName = message?.body?.user?.firstName || 'default';
console.log(firstName)
等价于
let firstName = 'default';
if(message && message.body && message.body.user && message.body.user.firstName){
firstName = message.body.user.firstName;
}
这个设计避免了大量的判断,但是尚未支持。
表示独一无二的值,没有两个相等的Symbol。一般用于对象的属性名称,避免属性的误操作。
let [a,b] = [Symbol(),Symbol()];
let [c,d] = [Symbol('abc'),Symbol('abc')];
let [e,f] = [Symbol.for('swl'),Symbol.for('swl')];
let rs_a_b = Object.is(a,b);
let rs_c_d = Object.is(c,d);
let rs_e_f = Object.is(e,f);
console.log(rs_a_b,rs_c_d,rs_e_f) //false false true
JS引用数据类型Array、Object,新增Set、WeakSet、Map、WeakSet。
a. 赋值操作
(function(){
let [a,b,c] = [1,2,3];
console.log(a,b,c);
let [d,...e] = [11,22,33,]; //rest操作
console.log(d,e);
})();
数组解构时,依照一一对应关系,同时允许使用rest操作符。但是要注意的是,rest操作符只能放在最后一位,rest操作符返回的是一个数组。
b. 默认值
(function(){
let [x, y = 'b',z = 13] = ['a',undefined,]; // undefined或者不写任何东西,默认值才生效
console.log(x,y,z);
})();
注意:不能写null,null会赋值给变量。
c. 惰性执行
(function(){
function a(){
console.log("**");
return 5;
}
let [aa=a()] = []; //会输出“**”
let [bb=a()] = [1]; //不会输出“**”
})();
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
对象解构时根据属性名匹配模式,不再是像数组依靠位置关系进行解构。
a. 两种解构方式
(function(){
let { foo } = { foo: 'aaa', bar: 'bbb' };//第一种
console.log(foo) ///aaa
let { foo: bar ,bar:foe} = { foo: 'aaa', bar: 'bbb' }; //第二种 通过模式解构
console.log(bar,foe) //aaa bbb
})();
第一种:依靠相同属性名直接获取。
第二种:通过模式将获取的value值赋值给新的变量。
b.嵌套解构
(function(){
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
console.log(x,y) //Hello World
ES6允许对象数字混合在一起进行解构,只要符合数组和对象的解构规则即可成功解构。
c. 字符串解构
(function(){
let str = 'qwert';
let [a,b,c,d] = str;
let {length:len} = str;
console.log(a,b,c,d,len)
})();
字符串被认为是一个数组和对象的混合体,它符合数组和对象的特性。首先,它有可遍历的字符,可以认为是数组。其次,具有可枚举的属性length,可以认为是对象。
新增遍历:for…of…、entries、keys、values
与解构搭配使用:
let arr = [{name:'abc',id:1},{name:'def',id:2},{name:'hij',id:3}]
for(let {id,name} of arr){
console.log(id,name)
}
返回一个迭代器,通过next进行操作。而Object.entries、Object.keys、Object.values,返回的只是一个数组,不能使用next操作。
var arr = ["a", "b", "c"];
let a = arr.entries(); //迭代器也可以使用for...of...遍历
console.log(a.next()) //{ value: [ 0, 'a' ], done: false }
console.log(a.next()) //{ value: [ 1, 'b' ], done: false }
console.log(a.next()) //{ value: [ 2, 'c' ], done: false }
console.log(a.next()) //{ value: undefined, done: true }
迭代器与Java中迭代器类似,具有next( )操作。
存储二进制数据,主要在前端会使用:File API、XMLHttpRequest、Fetch API、Canvas、WebSockets
参考链接:http://es6.ruanyifeng.com/#docs/arraybuffer
(()=>{
let [name,obj_a,obj_b] = ['abc',{},{}];
let obj = {
name,
[obj_a]:'obj a',
[obj_b]:'obj b', // '[object Object]':'obj b'
['desc']:'this is description',
[Symbol('sym')]:'this is a Symbol'
}
console.log(obj)
})();
与ES5向比较,声明一个对象属性的方式灵活很多,具体:
- a. 省略key的书写,默认变量名、方法名、对象名为key值。
- b. 允许使用[expression]定义key,若expression不是个字符串,则将其转化为字符串
返回Boolean变量,它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
(()=>{
Object.is('foo', 'foo')// true
Object.is({}, {}); //false
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
})();
注意: Object.is(Nan,NaN)的返回值是true。
返回由对象的键值对、健、值组成的数值,可使用for…of…遍历。注意:若参数不是个对象,隐式转化为对象。Boolean、Number不能被转化为对象,所以返回一个空数组。
let a = true;
console.log(Object.entries(a)) //[ ]
console.log(Object.keys(a)) //[ ]
console.log(Object.values(a)) //[ ]
注意:通过这种方式获取的数组不能使用next( )进行遍历
方法 | 描述 | 备注 |
---|---|---|
Object.getPrototypeOf() | 获取原型属性 | 不能获取proto设置的属性 |
Object.setPrototypeOf() | 设置原型属性 | |
Object.getOwnPropertyDescriptors() | 获取自身属性 | {name:{value:’swl’,writable:true,enumerable: true,configurable: true }} |
Object.getOwnPropertySymbols() | 获取自身的Symbol类型属性 | |
Object.getOwnPropertyNames() | 获取自身的属性名 | 不包含Symbol类型的key |
Reflect.ownKeys(obj) | 获取非原型属性名 |
合并对象,如果参数不是对象,则先转化为对象。Null和undefined不能转化对象,会报错。
注意:执行浅拷贝…
(()=>{
let map = new Map([["name","swl"],["age",12],["sex","boy"]]);
for(let [key,value] of map){
console.log(`key: ${key} ,value: ${value}`)
}
let entries = map.entries();
for(let [key,value] of entries){
console.log(`key: ${key} ,value: ${value}`)
}
})();
Map可接受对象作为key,不会将对象转化为字符串。
WeakMap 与 Map 在 API 上的区别主要是两个,
- 1.没有遍历操作(即没有key()、values()和entries()方法)
- 2.没有size属性。
因此,WeakMap只有四个方法可用:get()、set()、has()、delete()。一般用于存储HTML DOM节点。
(()=>{
let set = new Set(['a','b','c']);
for(let ele of set){
console.log(ele)
}
let entries = set.entries();
for(let [key,value] of entries){
console.log(key,value)
}
})();
Set可接受NaN值。
WeakSet只接受对象,一般用于存储HTML DOM节点。WeakSet 不能遍历(即没有key()、values()和entries()方法),也没有size属性。WeakSet只有四个方法可用:add()、has()、delete()。
let getName = name => name;
console.log(getName('swl')); //swl
let sum = (a,b) => {
let sum = a + b;
return sum;
}
console.log(sum(2,3)); //5
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
(()=>{
const log = console.log;
var proxy = new Proxy({}, {
get(target, key, receiver) {
return `${target[key]}`;
},
set(target, key, value,receiver){
return Reflect.set(target, key, `TEST-${value}`,receiver);
}
});
proxy.name = 'profile';
proxy.time = '2017/9/9';
proxy.action = 'download';
log(proxy.time); //TEST-2017/9/9
log(proxy.name); //TEST-profile
log(proxy.action); //TEST-download
})();
参数obj:对象,{}或者[ ]
参数handler:处理器对象,可选处理方法get、set、apply、has…
ES6规定对象只要具有Symbol.iterator属性,那么此对象就是可遍历的。Symbol.iterator的返回值是一个遍历器,可以通过next()和for…of…遍历。
(()=>{
let arr = ['a','b','c'];
let gen = arr[Symbol.iterator]()
console.log(gen.next())
console.log(gen.next())
console.log(gen.next())
console.log(gen.next())
console.log(gen.next())
})();
也可以使用for…of…遍历出全部内容
(()=>{
function* he(){
yield 'hello';
yield 'world';
}
let a = he();
console.log(a.next())
console.log(a.next())
console.log(a.next())
})();
此外,使用Generator可以实现执行同步事件的效果。原理:可以通过yield的返回值判断是否继续执行next( )。
Promise具有三个状态,pending(进行中)、resolved[fulfilled](已完成)、rejected[rejected](已拒绝)。
promise的状态转换,只能由未完成到已完成或者已拒绝转换,这个过程不能逆转。
//Promise实例
new Promise((resolve,reject)=>{
resolve('fulfilled...')
}).then((val)=>{
console.log(val)
}).catch(error => {
console.log(error)
})
参数arr:arr中存放的是promise。
返回值:当所有的promise处于完成态时, Promise.all(arr)转变为完成态,否则一直是未完成或者已拒绝。
参数arr:arr中存放的是promise。
返回值:当任何一个的promise处于完成态时, Promise.race(arr)转变为完成态。
参数func:普通function
返回值:处于完成态的promise
参数func:普通function
返回值:处于已拒绝的promise
let timeout = (t)=>{
return new Promise(resolve=>{
setTimeout(resolve,t)
})
}
(async ()=>{
console.log(`两秒之后打印:`)
await timeout(2000)
console.log(`hello world`)
})();
通过关键字对function进行标识,指明这是一个异步方法。
需要注意的是:
通过async标识的function,其返回值是个Promise。比如,在函数内部返回的是个一个字符串,async自动将它封装成一个Promise。
await愿意是等待,它会等待它后面紧跟着的表达式的执行完成。分两种情况:
参考url:http://cnodejs.org/topic/5640b80d3a6aa72c5e0030b6
class Persion {
constructor(name,age){
this.name = name;
this.age = age;
}
getName(){
return this.name;
}
static getDesc(){
return `this is Persion class`;
}
}
let persion = new Persion('bob',11);
console.log(persion.getName()); //bob
console.log(Persion.getDesc()); //this is Persion class
a. typeof Persion == ‘function’;
b. Constructor、普通方法是定义在class的原型上的,等同于Persion.prototype = {constructor,getName};静态方法,等同于Persion.getDesc = func;
let tool = class Tool {
static print(){
return Tool.getDesc();
}
static getDesc(){
return `this is Tool class`;
}
}
console.log(tool.getDesc()); //this is Persion class
Tool为内部使用,tool为外部使用。若不需要引用Tool,则可以省去Tool,即let tool = Class {……};
静态方法:static+方法名,如,static getDesc
私有方法:_+方法名,如,_getName(){}
私有属性:#+属性名,如,#name
私有方法、私有属性仅是一种提议,未实现。
使用:创建一个不允许被实例化的工具类。new.target只能在constructor使用。
class Tool {
constructor(){
if(new.target == Tool){
throw new Error('this class can not be instanced')
}
}
static getLocalTime(){
return new Date().toLocaleString();
}
}
new Tool() //抛出一个Error
console.log(Tool.getLocalTime())
const log = console.log;
class Persion{
constructor(name,age){
this.name = name;
this.age = age;
}
toString(){
return `the presion's name is ${this.name} ,and age is ${this.age}`;
}
static getDesc(){
return 'this is Persion class'
}
}
class Man extends Persion{
constructor(name,age){
super(name,age);
}
toString(){
return super.toString(); //super指向父类的原型
}
static getOwnDesc(){
return super.getDesc();
}
}
let m = new Man("swl",2343);
log(m.toString()) //the presion's name is swl ,and age is 2343
log(Man.getOwnDesc()) //this is Persion class
log(Man.getDesc()) //this is Persion class
supper:既可以当方法用,也可以当做对象使用。
1. super作为函数调用时,代表父类的构造函数。ES6规定,必须在子类的constructor中调用一次supper,否则,报错。
2. super作为对象使用时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
extends A
A可以是多种类型的值,只要A具有prototype就可以。由于函数都有prototype属性(除了Function.prototype函数),因此A可以是任意函数。