1、下载安装babel npm install babel-cli -g 我们之所以可以使用babel命令,是因为在全局环境下会生成一些xxx.cmd的文件,而这里的xxx就是可以在doc窗口中执行的命令 执行babel命令后,可以完成一些编译或者其他任务,原因是执行babel命令后,会自动加载处理任务的文件; 配置.babelrc文件,安装在一些语言解析包 我们需要把.babelrc文件配置在当前项目的根目录下 注意:在电脑上不能直接创建没有文件名的文件,但是可以在webS中new->file来创建,或者使用命令创建m 1、babelrc这个后缀名在某些ws中是不识别的,我们需要设置关联 2、在这个文件中编写内容:
{ "presets":[],//存的是我们编译代码时候需要依赖的语言解析包 "plugins":[]//存的是我们编译代码时候需要依赖的插件信息 }3、安装依赖的语言解析包 在当前项目的根目录下安装 npm install babel-preset-latest安装最新已经发布的语言标准解析模块 npm install babel-preset-stage-2 安装当前还没有发布但是已经进入草案的语言解析模块 4、完成最后.babelrc
{ "presets":[ "latest", "stage-2" ],//存的是我们编译代码时候需要依赖的语言解析包 "plugins":[]//存的是我们编译代码时候需要依赖的插件信息 }三、使用命令编译JS代码 基本上所有支持命令操作的模块都有一个命令 babel –help/babel -h 查看帮助 babel -V 查看版本号 babel -o 把某一个JS文件中的ES6代码进行编译 babel -d 把某一个文件夹中所有的JS文件中的ES6代码进行编译 babel -w 监听文件中代码的改变,当代码改变后,会自动进行编译
let&&const
let 变量名=变量值 使用let创建变量和使用var创建变量的区别
1、用var声明的变量会变量提升,用let声明的变量不会进行变量提升
用let创建变量 let xxx=xxx; 用let创建函数 let xxx=function(){} 创建自执行函数 ;(function(){ })();2、用let定义变量不允许在同一个作用域中重复声明一个变量(只要当前作用域中有这个变量,不管是用var还是用let声明的,再用let声明的话会报错:不能重复声明一个变量),但是可以重复定义(赋值)
let i=10; let i=20;/会报错, i=20;重复赋值不会报错3、暂时性死区:在代码块内,使用let命令声明变量之前,该变量都是不可以使用的,
if (true) { // TDZ开始 tmp = 'abc'; // ReferenceError,报错之后下面都不会输出 console.log(tmp); // ReferenceError,报错之后下面都不会输出 let tmp; // TDZ结束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123 } //下面也会报错出现TDZ console.log(typeof x); // ReferenceError let x; //作为比较如果一个变量根本没有被声明,使用typeof反而不会报错。 console.log(typeof x);// "undefined"4、ES6语法创建的变量(let)存在块级作用域 [ES5] window全局作用域 函数执行形成的私有作用域 [ES6] 除了有ES5中的两个作用域,ES6中新增加块级作用域(我们可以把块级作用域理解为之前学习的私有作用域,存在私有作用域和作用域链的一些机制)ES6中把大部分用{}包起来的都称之为块级作用域; 5、let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
const细节知识点和let类似 const声明的常量只要声明就必须赋值,而且变量的值是一定的,不能被修改;
注意:并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。 const声明的变量也存在暂时性死区,即只能在声明的位置之后使用;
JS中创建变量的方式汇总 [ES5]
var :创建变量 function:创建函数 ES5中创建变量或者函数:存在变量提升,重复声明等特征; [ES6]
let创建变量 const:ES6中创建常量 ES6中创建的变量或者常量:都不存在变量提升,也不可以重复声明,而且还存在块级作用域; class:创建一个类 import:导入 ES6中的解构赋值 按照原有值的结构,把原有值中的某一部分内容快速获取到(快速赋值给一个变量)
解构赋值本身是ES6的语法规范,使用什么关键字来声明这些变量是无所谓的,如果不用关键字来声明,那么就相当于给window添加的自定义属性;(严格模式下必须使用关键字来声明,因为严格模式下不允许出现不用关键字声明的变量;),如果解构不到值,那么变量的值就是undefined;
let [a,b,c]=[12,23,34]; var [d,e,f]=[35,41,63]; console.log(a,b,c)//12,23,34; console.log(d,e,f)//35,41,63; [q,w,e]=[1,2,3];//相当于给window添加了三个属性:q,w,e值分别为1,2,3;(严格模式下会报错)多维数组的解构赋值,可以让我们快速的获取到需要的结果
let [a,b,c]=[[45,36],12,[23,43,[1,2[4,[8]]]]23,34]; console.log(a)//[45,36] console.log(b)//12 console.log(c)//[23,43,[1,2,[4,[8]]]] //数组中不需要解构的值可用逗号(,)空开,一个逗号代表空开一项 let [,,,A]=[12,23,45]; console.log(A)//undefined let [,,B]=[12,23,45] console.log(B)//45在解构赋值中,支持扩展运算符即…,只要用了扩展运算符,就相当于新生成了一个数组或者对象,如果解构不到值的话,新生成的数组或者对象为空,而不是undefined,但是扩展运算符必须放在末尾
let [a,...c]=[12,1,4,83,34]; console.log(a)//12 console.log(c)//[1,4,83,34]; let [a,...b,c]=[12,1,4,83,34];//会报错,扩展运算符只能放在末尾; 对象的解构赋值 对象的简洁表示法: const foo = 'bar'; const baz = {foo}; baz // {foo: "bar"} // 等同于 const baz = {foo: foo};对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { foo, bar } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb" 如果变量名与属性名不一致,必须写成下面这样。 let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; baz // "aaa" 真正被赋值的是后者,而不是前者。 let obj = { first: 'hello', last: 'world' }; let { first: f, last: l } = obj; f // 'hello' l // 'world' first//error: first is not defined 如果要将一个已经声明的变量用于解构赋值,必须非常小心。 // 错误的写法 let x; {x} = {x: 1};//会报错因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
// 正确的写法 let x; ({x} = {x: 1});放在圆括号当中就可以避免 JavaScript 将其解释为代码块。
解构赋值中支持指定默认值
let [foo = true] = []; console.log(foo);// true let [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ['a', undefined]; // x='a', y='b' var {x: y = 3} = {}; y // 3 var {x: y = 3} = {x: 5}; y // 51、快速交换两个变量的值
let a=12; let b=13; [a,b]=[b,a]; console.log(a);//13 console.log(b);//122、可以接收函数返回的多个值
let fn = function () { let a = 12, b = 13, c = 14; return [a, b, c]; }; let [a,b,c] = fn(); console.log(a, b, c);//=>12 13 141、扩展运算符(注意,在解构赋值中,叫做扩展运算符,只能放在末尾)
只要用了扩展运算符,就相当于新生成了一个数组或者对象,如果解构不到值的话,新生成的数组或者对象为空,而不是undefined,但是扩展运算符必须放在末尾
数组中的扩展运算符
let [a,b,...c]=[12,1,4,83,34] console.log(a);//12 console.log(b);//1 console.log(c);//[4,83,34] 对象中的扩展运算符 let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x);//1 console.log(y );//2 console.log(z );//{ a: 3, b: 4 }2、剩余运算符
function(...arg){ ...arg就相当于剩余运算符,可以把传递的所有参数都获取到,而且获取到的是一个数组 } 3、展开运算符 function fn1(){ } function fn2(){ fn1(...arguments) ...arguments:这里的...就相当于展开运算符,把arguments展开,把里面的每一项分别传递给fn1当作参数,然后让fn1执行; }两种写法:1、表达式 2、函数体 表达式:
1.let fn=p=>p; 等价于 var fn=function(p){return p}; 2.let fn=()=>n; 等价于 var fn=funciton(){return n}; 3.let fn=(n,m)=>n+m;等价于 var fn=function(n,m){return n+m}; 函数体: let fn=(n,m)=>{ var total=n+m; return total; } 1、箭头函数中不支持arguments,但是用 剩余运算…arg 代替了arguments,arg是一个数组,可以直接使用数组方法
let obj={ name:'obj', fn(){ //此方法的属性名为fn,属性值为一个函数,和下面的sum写法是一样的; }, sum:function () { } }; let fn = (...arg)=> { /console.log(arguments);//=>Uncaught ReferenceError: arguments is not defined /=>不支持arguments,我们使用ES6中的剩余运算符...来获取传递的进来的所有参数值(优势:使用剩余运算符接收到的结果本身就是一个数组,不需要再转换了) /console.log(arg instanceof Array);//=>true return eval(arg.join('+')); }; //=>也可以把FN简写成以下方式 //let fn = (...arg)=> eval(arg.join('+')); console.log(fn(10, 20, 30, 40));2、箭头函数中的this问题,可以默认为箭头函数中没有this,在箭头函数中出现的this都是宿主环境中(即上级作用域中)的this,与箭头函数点之前的执行主体没有任何关系;
ES6中的类和继承 ES6中创建类和实例用class,创建出来的类不存在变量提升; ES5中创建类和实例,以及如何禁止用户把类当做普通函数执行:new.target
if (typeof new.target === 'undefined') { throw new SyntaxError(`当前Person不能作为一个普通函数执行,请使用new Person来执行~~`); } class Father {//定义一个类; constructor(name, age) {//构造函数定义实例的私有属性 this.name = name; this.age = age; } getName() {//公有的函数和方法 console.log(this.name + "的年龄是" + this.age + "岁了"); } static like() {//static后面写的是把Father当做对象时的私有属性 console.log("我是Father函数的私有属性") } } class Son extends Father {//子类Son继承父类Father constructor(name, age, color) { super(name, age);//继承父类的私有属性,必须写 //下面为子类的私有属性 this.color = color; super当作对象调用时,super就相当于父类的原型 } //下面为子类公有的方法 getColor() { console.log(this.color) } }模版字符串,也是字符串,可以直接使用字符串中的方法; 模版字符串的空格和换行,都是被保留的,如果想要消除空格可以使用trim方法;
$('#list').html(` <ul> <li>first</li> <li>second</li> </ul> `.trim());模版字符串中可以嵌入变量,需要将变量写在${}中,大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
let x = 1; let y = 2; `${x} + ${y} = ${x + y}` // "1 + 2 = 3" `${x} + ${y * 2} = ${x + y * 2}` // "1 + 4 = 5" let obj = {x: 1, y: 2}; `${obj.x + obj.y}` // "3"模板字符串之中还能调用函数。
<span style="color:#333333">function fn() { return "Hello World"; } `foo ${fn()} bar` // foo Hello World bar</span>forEach,for,for in,for of的区别 forEach:不支持返回值,只是普通的循环遍历 for in:key输出的值为字符串类型,包括把数组当成对象添加的属性也可以遍历出来 for of:只返回具有数字索引的属性。这一点跟for…in循环也不一样。(不能遍历对象)
let arr = [3, 5, 7]; arr.foo = 'hello'; for (let i in arr) { //for in是把arr当成对象遍历,i是属性名,包括arr的私有属性 console.log(i); // "0", "1", "2", "foo" } for (let i of arr) { //for of是把arr当成数组遍历,i是数组中的每一项 console.log(i); // "3", "5", "7" } for of循环不会返回数组arr的foo属性 如果只想拿到索引,可用keys()方法 for (let index of arr.keys()) { console.log(index); } // 0 // 1 // 2 如果两个都想拿到,可用entries()方法 for (let (index, elem) of arr.entries['ɛntrɪs]()) { console.log(index, elem); } // 0 "3" // 1 "5" // 2 "7"Array.from 负责将两类对象转化为数组
类数组可遍历的数据类型也可将Set结构转化为数组
//类数组 let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; Array.from(arrayLike)//=>['a', 'b', 'c'] Array.from('hello') // ['h', 'e', 'l', 'l', 'o'] //set结构 const items = new Set([1, 2, 3, 4, 5]); const array = Array.from(items); ({}).toString.call(array);//"[object Array]" ({}).toString.call(items);//"[object Set]"Array.of方法用于将一组值,转换为数组。 Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。
Array.of(3, 11, 8) // [3,11,8] Array.of(3) // [3] Array.of(3).length // 1 Array.of()//[]ES6中的模块导入和导出
//=>A模块(在A模块中导入B模块) import Temp,{lib} from "./B";//=>把导入的Temp中的部分属性方法进行解构赋值 new Temp().init(); lib();//=>Temp.lib() //=>B模块(导出) export default class Temp { init() { console.log(`hello world`); } static lib(){//=>Temp.lib } }特点
该方法实现了浅拷贝属性名相同时替换原属性数组也可当作对象处理,属性名为‘0’,‘1’。。。Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。