ES6 标准入门

一、let所声明的变量只在let命令所在的代码块有效javascript

二、不存在变量提高html

在代码块内,使用let命令声明变量以前,该变量都是不可用的,称为暂时性死区。java

三、不容许重复声明es6

let 不容许在相同做用域内重复声明一个变量编程

四、块级做用域数组

没有块级做用域的不合理的场景数据结构

ar temp = new Date();
function f()
{ 
   console.log(temp);
   if(true)// true或false结果同样
    {
      var temp = "hello"
     }
}
f() //undefined

由于变量提高,致使内层的tmp变量覆盖了外层的tem变量app

提高的为变量声明 var tmp函数式编程

可是没有初始化,在if判断里才对声明的变量初始化函数

块级做用域的出现实际上使得普遍应用的当即执行函数再也不必要了

//IIFE写法function() {
   var tmp = ...;
}());
//块级做用域写法
{
   let tmp = ...;
}

五、const命令

 1)const用来声明常量。一旦声明,其值就不能改变

2)只在声明块级做用域有效

3)const命令声明的常量也不提高

4)对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,因此将一个对象声明为常量必须十分当心

六、ES6一共有6种声明变量的方法:

var,function,let ,const,import,class

七、全局对象的属性

let,class,const声明的全局变量不属于全局变量的属性(仅仅不是他的属性)

八、变量的解构赋值

解构赋值容许指定默认值

 var [a,b,c] = [1,2,3]

九、对象的解构赋值

var {foo,bar} = {foo:"aaa",bar:"bbb"}

对象的解构和数组有个重要的不一样,数组的元素是按次序排列的,变量由它的位置决定。

对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

第七章 数组的扩展

一、Array.from

Array.from 用于将两类对象转为真正的数组:相似数组的对象和可遍历对象

下面是一个相似数组的对象:

 

let arraylike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
};

// ES5的写法
var arr1 = [].slice.call(arraylike);//['a','b','c']
//es6的写法
let arr2 = Array.from(arraylike);//['a','b','c']

 

实际应用中,常见的相似数组的对象是DOM操做返回的Nodelist集合,以及函数内部的arguments对象,Array.from 均可以将他们转为真正的数组

 只要是部署了interater接口的数据结构,Array.from 都能将其转为数组

set 

所谓相似数组的对象,本质特征只有一点,必须有length属性,所以任何有 length属性的对象,均可以经过Array.from()转为数组

Array.from第二个参数相似map

Array.from(arraylike,x=>x*x)
Array.from(arraylike).map(x => x*x)

 Array.of用于将一组值转为数组

copyWithin()

复制数组,会修改当前数组

find()

用于找到第一个符合条件的数组成员,他的参数为一个回调函数,全部成员执行这个回调函数,找到第一个返回true的成员,返回该成员,不然返回undefined

findIndex()

返回第一个符合条件的数组成员的位置,全部都不符合返回-1

fill()

使用给定值填充数组

entries(),keys(),values()

遍历数组

includes()

返回一个布尔值,表示某个数组是否包含给定的值

以前使用indexof,有两个缺点一、不够语义化 二、内部使用严格运算符(===)判断,对NaN误判

map和set解构有一个has注意区分,Map.prototype.has(key) 查找键名

Set.prototype.has(value)查找值

数组的空位

空位不是undefined一个位置等于undefined依然是有值的,空位是没有任何值

0 in [undefined,undefined,undefined]//true
0 in [, , ,]//false

0号位置有值,没值

Array.from()、扩展运算符会将空位转为undefined

数组推导

容许直接经过现有数组生成新数组

var a1 = [1,2,3,4];
var a2 = [for (i of a1) i*2];
a2 //[2,4,6,8]

 

 第九章 函数的扩展

一、ES6以前,不能直接为函数的参数指定默认值,只能采用变通的方法

es6容许为函数的参数设置默认值,直接写在参数定义的后面

function log(x,y = 'World'){
  console.log(x,y)
  }

参数变量时默认声明的,因此不能用let或者const再次声明

 

二、函数的length属性

指定了默认值之后,函数的length属性将返回没有指定默认值的参数个数

(function(a){}).length // 1
(function(a = 5){}).length // 0

三、做用域

若是参数默认值是一个变量,则该变量所处的做用域与其余变量的做用域规则是同样的,先是当前函数的做用域而后才是全局做用域

let x = 1;
function f(x,y = x){
  console.log(y)
}
f(2);//2

以上,函数做用域的内部变量x已经生成,因此y等于参数x而不是全局变量x

let x = 1;
function f(y = x){
  let x = 2;
  console.log(y)
}
f();//1

函数调用时y的默认值变量x尚未在函数内部生成,因此x指向全局变量

 若是函数A的参数默认值是函数B,那么因为函数的做用域是其声明时所在的做用域,函数B的做用域就不是函数A而是全局做用域。

四、rest参数

...变量名

用于获取函数的多余参数,这样就不须要使用arguments对象了

rest参数以后不能有其余参数,函数length属性不包括rest参数

五、扩展运算符

...

比如rest参数的逆运算,将一个数组转为用逗号分割的参数序列

console.log(...[1,2,3]) //1 2 3

 六、替代数组的apply方法

因为扩展运算符能够展开数组,因此不须要apply方法将数组转为函数的参数了

//ES5 的写法
function f(x,y,z){}
var args = [0,1,2];
f.apply(null,args);

//ES6的写法
function f(x,y,z){}
var args = [0,1,2];
f(...args);

七、扩展运算符的应用

1)合并数组

var arr1 = ['a','b']
var arr2 = ['c']
var arr3 = ['d','e']

//es5
arr1.concat(arr2,arr3)
//es6
[...arr1,...arr2,...arr3]

 2)字符串

扩展运算符能够将字符串专为真正的数组

八、name属性

函数的name属性返回该函数的函数名

function foo() {}
foo.name // 'foo'

九、箭头函数

var sum =(num1, num2) => num1 + num2;
//等同于
var sum =function(num1, num2) {
  return num1 + num2;
}

若是箭头函数的代码多于一条语句,就要使用大括号将其括起来,并使用return语句

箭头函数能够与变量解构结合使用

const full = ({first,last}) => first + '' + last;
//等同于
function full(person) {
  return person.first + '' +person.name;
}

箭头函数使用注意点:

一、函数体内this 对象就是定义时所在的对象,而不是使用时所在的对象

二、不能够看成构造函数,不可使用new命令

三、不可使用arguments对象,该对象在函数体内不存在,若是要用能够用rest参数代替

this指向的固定化并非由于箭头函数内部有绑定this的机制,实际缘由是箭头函数根本没有本身的this

因为箭头函数没有本身的this,固然也就不能用call(),apply(),bind()这些方法去改变this的指向

十、尾调用优化

 尾调用是函数式编程的一个重要概念

就是指某个函数的最后一步是调用另外一个函数

function f(x){
  return g(x);
}

函数调用会在内存中造成一个‘调用记录’。称为调用帧,保存调用位置和内部变量的信息。

若是在函数A的内部调用函数B,那么在A的调用帧的上方还会造成B的调用帧,等到b运行结束,将结果返回A,B的调用帧才会消失

尾调用因为是函数最后一步操做,因此不须要保留外层函数的调用帧,由于调用位置,内部变量等信息都不会再用到了,直接用内层函数的调用帧取代外层函数便可

function f() {
  let m = 1;
  let n = 2;
  return g(m+n);
}
f()
//等同于
function f() {
  return g(3);
}
f()
//等同于
g(3)

十一、尾递归

 递归很是耗费内存,由于同时须要保存成百上千个调用帧,很容易发生栈溢出错误,但对于尾递归来讲,因为只存在一个调用帧,因此永远不会发生栈溢出错误

非尾调用,

function factorial(n) {
  if(n === 1) return 1;
  return n * factorial(n-1);
}
factorial(5) // 120

尾调用

function factorial(n, total) {
  if(n === 1) return total;
   return factorial(n - 1,n*total);
}
factorial(5,1);

 若是改写为一个尾递归,只保留一个调用记录,复杂度为O(1)

尾递归的实现每每须要改写递归函数,确保最后一步只调用自身。作到这一点的方法就是把全部用到的内部变量改写成函数的参数

缺点是不太直观

方法一:在尾递归函数以外再提供一个正常形势的函数

function tailfactorial(n, total) {
  if(n === 1) return total;
  return factorial(n - 1,n*total);
}
function factorial(n) {
  return tailfactorial(n,1);
}
factorial(5);

函数式编程有一个概念:柯里化 :将多参数的函数转换成单参数的形式

柯里化是这样的一个转换过程,把接受多个参数的函数变换成接受一个单一参数(译注:最初函数的第一个参数)的函数,若是其余的参数是必要的,返回接受余下的参数且返回结果的新函数。

function currying(fn,n) {
  return function(m) {
    return fn.call(this, m, n)
  }
}
function tailfactorial(n, total) {
  if(n === 1) return total;
  return factorial(n - 1,n*total);
}
const factorial = currying(tailfactorial, 1);
factorial(5)

方法二:采用ES6的默认值

function tailfactorial(n, total = 1) {
  if(n === 1) return total;
  return factorial(n - 1,n*total);
}

 第9章 对象的扩展

一、ES6容许在对象中只写属性名不写属性值

function f(x,y){
  return {x,y};
}
//等同于
function f(x,y){
  return {x:x,y:y};
}

二、属性名表达式

方法一:

obj.foo = true

方法二:

obj['a'+'bc'] = 123

三、方法的name属性

函数的name属性返回函数名,对象方法也是函数,所以也有name属性

 若是对象方法是一个symbol值,那么name属性返回的是这个symbol值的描述

每一个从Symbol()返回的symbol值都是惟一的。一个symbol值能做为对象属性的标识符;这是该数据类型仅有的目的。

四、object.is()

object.is 用来比较两个值是否严格相等,它与严格比较运算符(===)的行为基本一致

Object.is('foo','foo') // true
Object.is({},{}) // false

五、Object.assign() 这是一种浅复制

用来将源对象的全部可枚举属性复制到目标对象。它至少须要两个对象做为参数,第一个参数是目标对象,后面的参数都是源对象。

只要有一个参数不是对象,就会抛出错误

var target = {a: 1};
var source1 = {b:2};
var source2 = {c:3};
Object.assign(target,source1,source2);
target //{a:1,b:2,c:3}

若是目标属性和源对象有同名属性,或者多个源对象有同名属性,后面的属性会覆盖前面的属性

var target = {a: 1,b:1};
var source1 = {b:2,c:2};
var source2 = {c:3};
Object.assign(target,source1,source2);
target //{a:1,b:2,c:3}

 Object.assign()  只复制自身属性,不可枚举属性和继承属性不会被复制。

对于嵌套的对象,Object.assign() 处理方法是替换而不是添加

var target = {a:{b:'c',d:'e'}}
var source = {a:{b:'hello'}}
Object.assign(target,source);//{a:{b:'hello'}}

为对象添加属性

为对象添加方法

Object.assign(someClass.prototype,{
  someMethod(arg1, arg2) {
    ...
  },
  anotherMethod() {

  }
});

克隆对象

不过这种方法克隆,只能克隆原始对象自身的值,不能克隆他继承的值

function clone(origin) {
  return Object.assign({},origin);
}

合并多个对象

将多个对象合并到某个对象,若是但愿合并后返回一个新对象,能够对一个空对象合并

const merge = (...sources) => Object.assign({},...sources);

为属性指定默认值

六、属性的可枚举性

for...in:只遍历对象自身的和继承的可枚举属性

object.keys():返回对象自身的全部可枚举属性

Object.assign()只复制对象自身的可枚举属性

七、属性的遍历

es6一共有6种方法能够遍历对象的属性

1)for ...in

2)Object.keys(obj)

返回一个数组

3)Object.getOwnPropertyNames(obj)

4) Object.getOwnPropertySymbols(obj)

5)Reflect.ownKeys(obj)

6) Reflect.enumerate(obj)

八、__proto__属性:用来读取或设置当前对象的prototype对象。

object.setPrototypeOf方法做用和__proto__相同

例子:

let proto = {};
let obj = {x:10};
Object.setPrototypeOf(obj, proto);

proto.y = 20;
proto.z = 40;
obj.x //10
obj.y // 20
obj.z //40

以上代码将prop对象设置为obj对象的原型,因此从obj对象能够读取proto对象的属性 。

object.getPrototypeOf() 用于读取一个对象的prototype属性

function rectangle() {
}
var rec = new rectangle();
Object.getPrototypeOf(rec) === rectangle.prototype // true

九、对象的扩展运算符

rest参数

rest参数复制的是这个值的引用,而不是这个值的副本,即若是一个键的值是复合类型的值(数组,对象,函数),那么rest参数复制的是这个值的引用,而不是这个值的副本

let obj = {a: {b:1}};
let {...x} = obj;
obj.a.b = 2;
x.a.b // 2

扩展运算符

扩展运算符用于取出参数对象的全部可遍历属性,复制到当前对象

let aClone = {...a};
//等同于
let aClone = Object.assign({},a);

 第13章 set和map数据结构

一、set

它相似于数组。可是成员的值都是惟一的,没有重复的值,Set自己是一个构造函数,用来生成Set数据结构

var s = new Set();
[2,3,5,4,5,2,2].map(x=>s.add(x));
for(i of s){
  console.log(i)//2,3,5,4
}

结果代表,set结构不会添加剧复的值

Set函数能够接受一个数组做为参数,用于初始化

var set = new Set([1,2,3,4,4]);
[...set] //[1,2,3,4]

二、Set实例的属性和方法

属性:

Set.prototype.constructor; // 构造函数
Set.prototype.size; // 返回Set实例的成员总数

方法:

add(value)

delete(value)

has(value)

clear()

 数组去重:

//数组去重
function dedupe(array) {
  return Array.from(new Set(array));
}
// 数组去重
let arr = [3,5,2,2,5,5];
let unique = [...new Set(arr)];
//[3,5,2]

使用set能够很容易的实现并集,交集,差集

// 数组求交 
util.intersection = function (a, b) {
    let set1 = new Set(a);
    let set2 = new Set(b);
    let Intersect = new Set([...set1].filter(x => set2.has(x)));
    // console.log([...Intersect]);
    return [...Intersect];
}

  

// 数组求差
util.difference = function (a, b) {
    let set1 = new Set(a);
    let set2 = new Set(b);
    let difference = new Set([...set1].filter(x => !set2.has(x)));
    // console.log([...difference]);
    return [...difference];
}
// 并集
let a = new Set([1,2,3]);
let b = new Set([4,3,2]);
let union = new Set([...a,...b]);

三、Map

map结构的目的和基本用法

js的对象本质上是键值对的集合(hash结构)可是只能用字符串做为键

为了解决这个问题,es6提供了Map数据结构,它相似于对象,也是键值对的集合,可是键的范围不限于字符串,各类类型的值(包括对象)均可以看成键

object 结构提供了字符串-值的对应,map结构提供了值-值的对应,是一种更完善的hash结构实现

若是须要键值对的数据结构,map比object更合适

var m = new Map();
var o = {p:"hello world"};

m.set(o,"content");
m.get(o); // "content"
m.has(o); //true
m.delete(o); //true
m.has(o); // false

 第14章 iterator 和 for...of 循环

一、iterator 的概念

 js 的原有的表示“集合”的数据结构,主要是数组和对象,es6又添加了map和set

须要一种统一的接口机制来处理全部不一样的数据结构

遍历器是这样一种机制,它是一种接口,为各类不一样的数据结构提供统一的访问机制。

任何数据结构只要部署了iterator 接口,就能够完成遍历操做。

iterator 做用有3个:

1)为各类数据结构提供一个统一的简便的访问接口

2)使得数据结构的成员可以按某种次序排列

3)es6创造了一种新的遍历命令,for...of循环,iterator 接口主要供for...of消费

 

Iterator 的遍历过程是这样的。

 

(1)建立一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。

 

(2)第一次调用指针对象的next方法,能够将指针指向数据结构的第一个成员。

 

(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

 

(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置

 二、for...of循环

相关文章
相关标签/搜索