初识ES6

一、ES6概念

  • ES6,全称为ECMAScript 6.0 ;是 JavaScript 的下一个版本标准,2015.06 发版
  • ES6 主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念
  • 但是目前浏览器的 JavaScript 是 ES5 版本,大多数高版本的浏览器也支持 ES6,不过只实现了 ES6 的部分特性和功能。

二、ES6语法

1.let和const

letconst是ES6新增加的js关键字

(1)let与var
  • let是在代码块内有效,而var是在全局范围内有效(可以理解为本该在代码块生效的代码,却在外面也生效,说明“红杏出墙”)
{
  let a = 0;
  var b = 1;
}
console.log(a); // ReferenceError: a is not defined
console.log(b);  // 1
  • let只能声明一次,var可以声明多次;
    • let声明多次时,会报错,告诉你已经定义了此变量。避免了项目中存在变量覆盖(理解为套牌车,其是违法的)的问题
    • 同一个项目中,发生变量覆盖可能会导致数据丢失以及各种不可预知的bug,原则上来说:变量不能重名
let a = 1;
let a = 2;
var b = 3;
var b = 4;
console.log(a); // Identifier 'a' has already been declared,
console.log(b); // 4
  • let不存在变量提升,var 会变量提升
    • 变量 a 用 let 声明不存在变量提升,在声明变量 a 之前,a不存在,所以会报错;
    • 而变量 b 用 var 声明存在变量提升,所以当脚本开始运行的时候,b 已经存在了,但是还没有赋值,所以会输出 undefined。
console.log(a);  //ReferenceError: a is not defined
let a = "abc";
 
console.log(b);  //undefined
var b = "edg";
  • let适合于循环计数器
for (var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    })
}
// 输出十个 10
for (let j = 0; j < 10; j++) {
    setTimeout(function() {
        console.log(j);
    })
}
// 输出 0123456789
  • var声明的变量i是在全局范围内有效的,所以全局中只有一个变量i,, 每次循环时,setTimeout 定时器里面的i指的是全局变量 i,而循环里的十个 setTimeout是在循环结束后才执行,所以此时的i都是 10。
  • 变量 j是用 let 声明的,当前的 j只在本轮循环中有效,每次循环的j其实都是一个新的变量,所以 setTimeout定时器里面的 j 其实是不同的变量,即最后输出0123456789
(2)const
  • const声明一个只读变量,声明之后不允许改变

const其实保证的不是变量的值不变,而是保证变量指向的内存地址所保存的数据不允许改动,因此const 声明的简单类型变量等同于常量

  • 一般用于全局变量,变量名通常全部大写
const PI = "3.1415926"

2.解构赋值

  • 解构赋值是对赋值运算符的扩展
  • 针对数组或者对象进行模式匹配,然后对其中的变量进行赋值
  • 解构中,解构的源是赋值表达式的右边;解构的目标是赋值表达式的左边
  • 在代码上更加简洁易读,语义更清晰,方便复杂对象中数据字段的获取
(1)数组模型的解构

基本语法

let [a, b, c] = [1, 2, 3];
// a = 1
// b = 2
// c = 3

可嵌套

let [a, [[b], c]] = [1, [[2], 3]];
// a = 1
// b = 2
// c = 3

可忽略,相当于,=一个占位符

let [a, , b] = [1, 2, 3];
// a = 1
// b = 3

剩余运算符

let [a, ...b] = [1, 2, 3];
//a = 1
//b = [2, 3]

若解构的源是字符串

let [a, b, c, d, e] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'o'

不完全解构

let [a = 1, b] = []; // a = 1, b = undefined

解构默认值,当解构模式有匹配结果,且匹配结果是 undefined时,会触发默认值作为返回结果。

let [a = 3, b = a] = [];     // a = 3, b = 3
let [a = 3, b = a] = [1];    // a = 1, b = 1
let [a = 3, b = a] = [1, 2]; // a = 1, b = 2
  • a 与 b 匹配结果为 undefined ,触发默认值:a = 3; b = a =3
  • a 正常解构赋值,匹配结果:a = 1,b 匹配结果 undefined ,触发默认值:b = a =1
  • a 与 b 正常解构赋值,匹配结果:a = 1,b = 2
(2)对象模型的解构

跟数组模型的结构差不多
基本语法

let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
 
let { baz : foo } = { baz : 'ddd' };
// foo = 'ddd'

3.字符串

(1)子串的识别

在ES6之前,字符串用indexOf方法判断字符串是否包含子串
在ES6中,提供新的方法:

  • includes():判断是否找到参数字符串。
  • startsWith():判断参数字符串是否在原字符串的头部。
  • endsWith():判断参数字符串是否在原字符串的尾部。
    这三种方法都是返回布尔值,可以接受两个参数:搜索的字符串和搜索起始位置
let string = "apple,banana,orange";
console.log(string.startsWith("banana", 6));
string.includes("banana"); // true
string.startsWith("apple"); // true
string.endsWith("apple"); // false
string.startsWith("banana", 6) // true

注意:

  • 如果需要知道子串的位置,还是得用 indexOf(返回子字符串第一次出现字符位置。没有找到,则返回 -1)和 lastIndexOf(返回子字符串最后出现的位置。没有找到,则返回 -1)
  • 这三个方法如果传入了正则表达式而不是字符串,会抛出错误
(2)字符串重复

str.repeat()方法,将字符串以重复指定次数返回

let str = "hello,";
console.log(str.repeat(2)); //hello,hello,
  • 如果参数是小数,则向下取整
let str = "hello,"
console.log(str.repeat(3.2)); //hello,hello,hello,
  • 如果参数是-1到0之间的小数,会进行取整运算,0 至 -1 之间的小数取整得到 -0 ,等同于 repeat 零次
console.log(str.repeat(-0.5)); //''
  • 如果参数是NaN,等同于 repeat 零次
console.log(str.repeat(NaN));//''
  • 如果参数是负数或Infinity(无穷),则会报错
console.log("Hello,".repeat(-1));  
// RangeError: Invalid count value

console.log("Hello,".repeat(Infinity));  
// RangeError: Invalid count value
(3)字符串补全
  • padStart():返回新的字符串,表示用参数字符串从头部(左侧)补全原字符串。
  • padEnd:返回新的字符串,表示用参数字符串从尾部(右侧)补全原字符串。
  • 这两个方法也是接收两个参数,第一个是生成的新的字符串的总长度,第二个是用来补全的字符串;如果没有指定第二个参数,默认用空格填充
console.log("h".padStart(5,"o"));  // "ooooh"
console.log("h".padEnd(5,"o"));    // "hoooo"
console.log("h".padStart(5));      // "    h"
  • 如果指定的长度小于等于原字符串的长度,则返回原字符串
console.log("hello".padStart(5,"A"));  // "hello"
  • 如果原字符串加上补全字符串长度大于指定长度,则截去超出位数的补全字符串:
console.log("hello".padEnd(10,",world!"));  // "hello,worl"
  • 常用于补全位数:
console.log("123".padStart(10,"0"));  // "0000000123"
(4)模板字符串

用反引号来创建,${}里面放入变量名或者js表达式,模板字符串中的换行和空格会被保留

4.ES6函数

(1)箭头函数

箭头函数简化了函数的书写方式

  • 基本语法参数 => 函数体
var f = v => v;
//等价于
var f = function(a){
 return a;
}
f(1);  //1
  • 当箭头函数没有参数或者有多个参数时,要用()括起来;当函数体有多行语句时,用{}括起来,只有一行时可以省略
var f = (a,b) => a+b;
f(6,2);  //8
  • 当箭头函数返回对象时,要用()将对象包裹起来,否则会报错
// 报错
var f = (id,name) => {id: id, name: name};
f(6,2);  // SyntaxError: Unexpected token :
 
// 不报错
var f = (id,name) => ({id: id, name: name});
f(6,2);  // {id: 6, name: 2}
  • 注意箭头函数中没有this、super、arguments 和 new.target绑定
var func = () => {
    // 箭头函数里面没有 this 对象,
    // 此时的 this 是外层的 this 对象,即 Window 
    console.log(this)
}
console.log(func(55)); // Window 

var func = () => {
    console.log(arguments)
}
console.log(func(55));; // ReferenceError: arguments is not defined

在ES5中:在全局函数中,this指向的是window;当函数被作为某个对象的方法调用时,this就等于那个对象

var name = "window";
var obj = {
    name: 'object',
    getName: function() {
        return function() {//匿名函数
            return this.name;
        }
    }
}
console.log(obj.getName()());//window

由于匿名函数的执行环境是全局的,且this只在函数内部起作用,而在匿名函数function中找不到this.name是什么,所以就从全局中找,所以是window,无法找到object
在没有ES6前,解决匿名函数中tihs的指向问题是先用一个变量存储起来,var that = this

var name = "window";
var obj = {
    name: 'object',
    getName: function() {
        var that = this;
        return function() { //匿名函数
            return that.name;
        }
    }
}
console.log(obj.getName()()); //object

我们在getName函数内将this赋给that,此时that指向的是调用的对象,即obj,此时在匿名函数中调用that.name会在object上查找相应的数据,而不是在全局上查找,最终打印object

但是在ES6中,箭头函数在定义时,this就继承了定义函数的对象:

var name = "window";
var obj = {
    name: 'object',
    getName: function() {
        return () => {
            console.log(this.name);
        }; //object
    }
}
obj.getName()();//object

用箭头函数定义getName函数里面的匿名函数function时,this就继承了obj对象,所以在调用时会打印出object

总结来讲,普通函数中的this:谁调用就指向谁;箭头函数中:一层一层网上找,找离得最近的this,就指向它。
箭头函数常用于setTimeout()、回调函数中,不适合用于动态this

// 回调函数
var Person = {
    'age': 18,
    'sayHello': function () {
      setTimeout(function () {
        console.log(this.age);
      });
    }
};
var age = 20;
Person.sayHello();  // 20
//非箭头函数,在函数中,指向全局对象window,所以打印出的age=20
 
var Person1 = {
    'age': 18,
    'sayHello': function () {
      setTimeout(()=>{
        console.log(this.age);
      });
    }
};
var age = 20;
Person1.sayHello();  // 18
//箭头函数,所以在定义sayHello这个函数时,this就指向了sayHello的对象Person1,所以打印出的age=18
(2)函数参数的扩展

默认参数

function fn(name,age=17){
 console.log(name+","+age);
}
fn("Amy",18);  // Amy,18
fn("Amy","");  // Amy,
fn("Amy");     // Amy,17
  • 使用函数默认参数时,不允许有同名参数
  • 只有在未传递参数,或者参数为 undefined 时,才会使用默认参数,null 值被认为是有效的值传递。
function fn(name,age=17){
    console.log(name+","+age);
}
fn("Amy",null); // Amy,null
  • 函数参数默认值存在暂时性死区,在函数参数默认值表达式中,还未初始化赋值的参数值无法作为其他参数的默认值。
function f(x=y){
    console.log(x);
}
f();  // ReferenceError: y is not defined

不定参数
不定参数用来表示不确定参数个数,...变量名

function f(...values){
    console.log(values.length);
}
f(1,2);      //2
f(1,2,3,4);  //4

5.数组

数组新特性

6.ES6 类

面向过程编程是分析出解决问题所需要的的步骤,通过函数一步一步实现这些步骤

面向对象思想:面向对象是以对象来划分问题,每一个对象都是功能中心,具有明确的分工;

思维特点:

  • 抽取对象共用的属性和行为封装成一个类(模板)
  • 对类进行实例化,获取类的对象
(1)对象

对象是一个具体的事物,由属性(事物的特征)和方法(事物的行为)组成

(2)类的定义
  • class (类)作为对象的模板被引入,可以通过 class 关键字定义类
  • class 的本质是 function,同样可以看成一个块
  • 可以看作一个语法糖,让对象原型的写法更加清晰
  • 更加标准的面向对象编程语法

类是泛指的某一大类,是抽象的;对象是特指某一个,通过类实例化一个具体的对象

a.创建类
//用关键字class创建类
class Star {
    
}
//通过new创建对象
new Star();
b.类中的构造函数constructor
  • constructor()方法是类的构造函数(即默认方法),用于传递参数,返回实例对象
  • 通过new命令生成对象时,自动调用该方法
  • 如果没有显示定义,类内部会自动给我们创建一个 constructor()
class Star {
    constructor(name) {//函数
        this.name = name;
    }

}
//通过new创建对象
var uname = new Star('易烊千玺');
console.log(uname.name);

this指向的是实例化对象

c.类中添加方法
class Star {
    constructor(name) {
        this.name = name;
    }
    sing(song) { //创建sing这个方法 不需要加function
        console.log(this.name + song);
    }

}
//通过new创建对象
var uname = new Star('易烊千玺');
console.log(uname.name);
uname.sing('精彩才刚刚开始')
  • 类中方法不需要function关键字
  • 方法间不能加分号
(3)类的继承
extends关键字

子类继承父类的一些属性和方法,同时子类可以保留自己特有的方法

class Father {
    constructor() {

    }
    money() {
        console.log(1000);
    }
}
class Son extends Father {

}
// 实例化Son
var son = new Son();
son.money();
super关键字

super关键字可以用于访问和调用对象父类上的函数(可以调用父类的构造函数,也可以是普通函数)

//super关键字,调用父类的构造函数
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
}
class Son extends Father {
    constructor(x, y) {
        super(x, y); //调用了父类中的构造函数
    }
}
var son = new Son(1, 2);
son.sum();
// 调用父类的普通函数
class Father {
    say() {
        return '爸爸';
    }
}
class Son extends Father {
    say() {
        console.log('儿子');
        console.log(super.say() + '的儿子');
    }
}
var son = new Son();
son.say();

继承中,如果实例化子类输出一个方法,先看子类自己有没有这个方法,如果有就执行子类的;如果没有,则去父类里找有没有这个方法,如果有则执行父类的方法(就近原则

// 调用父类的方法,同时保留子类特有的方法
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
}
class Son extends Father {
    constructor(x, y) {
        super(x, y); //调用了父类中的构造函数
        //super 必须在子类this之前调用
        this.x = x;
        this.y = y;

    }
    subtract() {
        console.log(this.x - this.y);
    }
}
var son = new Son(5, 3);
son.sum();
son.subtract();

ps:super 必须在子类this之前调用,即必须先调用父类的构造方法,再使用子类的构造方法

总结

  • 在ES6中,类没有变量提升,所以必须先定义类,然后才能通过类实例化对象
  • 类里面的共有的属性和方法要加this使用
(4)类中this的指向问题
  • constructor里面的this指向的是创建的实例对象
  • 方法中的this是谁调用this就指向谁

三、ES6模块化

  • ES6依赖模块需要编译打包处理
  • 由于浏览器兼容性问题,目前部分浏览器不支持ES6语法,通常开发完项目后,要将ES6语法转换为ES5,这样浏览器才能识别

1.ES6模块化语法

  • 导出模块:即规定模块的对外接口,用export
  • 引入模块:即输入其他模块提供的功能,用import,语法:import xxx from '路径'

2.ES6在浏览器端的实现

(1)用Babel将ES6编译成ES5代码

Babel

(2)使用Browserify编译打包js
a.定义package.json文件
{
    "name":"es6_browserify",//下载browserify,不能直接起名为browserify
    "version": "1.0.0"
}
b.安装babel-cli, babel-preset-es2015browserify
  • cli的全称为:command line interface,命令行接口,需要下载babel-cli库去调用babel的命令
  • babel-preset-es2015,将es6转换成es5的所有插件打包(preset,预设)
  • 步骤
npm install babel-cli browserify -g
npm install babel-preset-es2015 --save-dev
c.定义.babelrc文件

rc文件:全称为run control,运行时控制文件

package.json在同一目录下,其是用来转换ES6语法的

{
    "presets": ["es2015"]
  }
d.定义模块代码
  • module1.js
//暴露模块(即导出模块)    分别暴露
export function foo() {
    console.log('foo() module1'); //调用foo函数
}

export function bar() {
    console.log('bar() module1');
}

// 暴露数组
export let arr = [1, 2, 3, 4, 5]
  • module2.js
// 统一暴露,将数据打包在一个对象里面统一暴露
function fun() {
    console.log('fun() module2');
}


function fun2() {
    console.log('fun2() module2');
}


//暴露对象里面有两个函数
export {
    fun,
    fun2
};
  • main.js:引入其他模块
//引入 其他的模块
//语法:import xxx from '路径',引入的时候要用对象解构赋值,不能直接定义一个变量取接收模块

import {
    foo,
    bar
} from './module1';
import {
    fun,
    fun2
} from './module2';
foo();
bar();
fun();
fun2();

// console.log(module1, module2);
e.编译
  • 使用Babel将ES6编译为ES5代码:babel js/src -d js/build

js/src:要编译的文件目录;js/bulid:编译为ES5后放入的文件目录

可能会遇到babel无法加载文件,参考

  • 使用Browserify编译js:browserify js/build/main.js -o js/dist/bundle.js
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值