ES6常见的新语法

1. 三个连续的点 (...) 表示的展开运算符,使你能够将字面量对象展开为多个元素

const persons = ["Rose", "Lily", "Daisy", "Jasmine", "Poppy"];
console.log(...persons);
  • WechatIMG207.jpeg
  • 1.1. 结合数组:
    前: 如果你需要结合多个数组,在有展开运算符之前,必须使用 Array的 concat() 方法
const man = ["man1", "man2", "man3"];
const male = ["male1", "male2", "male3"];
const gather = man.concat(male);
console.log(gather);
  • WechatIMG208.jpeg

    现:使用展开符来结合数组

const man = ["man1", "man2", "man3"];
const male = ["male1", "male2", "male3"];
const gather = [...man,...male];
console.log(gather);
  • image.png
  • 1.2. 剩余参数(可变参数):
    使用展开运算符将数组展开为多个元素,使用剩余参数可以将多个元素绑定到一个数组中,剩余参数也用到三个连续的点(...)表示,使你能够将不定量的元素表示为数组。
  • 1.2.1 将变量赋数组值时:
const order = [20.17, 18.67, 1.50, "cheese", "eggs", "milk", "bread"];
const [total, subtotal, tax, ...items] = order;
console.log(total, subtotal, tax, items);
  • WechatIMG210.jpeg
  • 1.2.2. 可变参数函数:
    前:对于参数不固定的函数,ES6之前是使用参数对象(arguments)处理:
function sum() {
  let total = 0;  
  for(const argument of arguments) {
    total += argument;
  }
  return total;
}

现:在ES6中使用剩余参数运算符则更为简洁,可读性提高:

function sum(...nums) {
  let total = 0;  
  for(const num of nums) {
    total += num;
  }
  return total;
}

2. const和let命令

  • 2.1. var 前:写js变量的时候,就是定义的变量有时候会变成为全局变量
for(var i = 0; i < 5; i++){
    console.log(i);
}
console.log("循环外:" + i);
  • WechatIMG211.jpeg

    可以看出,再循环外部也可以获取到变量i的值,显然变量i的作用域范围大了,在做复杂的页面时,会带来很大的
  • 2.2. 现:let所声明的变量,只在let所在的代码块内有效,且不能重复。
for(let i = 0; i < 5; i++){
    console.log(i);
}
console.log("循环外:" + i);
  • WechatIMG212.jpeg

    这样,就把变量的i的作用域控制在循环内部
  • 2.2. const:声明的变量是常量,不能修改,也不能重复定义(如果const定义一个对象,对象的属性可以改变)。
  • WechatIMG213.jpeg

    可以看到,变量a的值是不能修改的

3. ES6箭头函数

  • 3.1.1. 前:使用普通函数把其中每个名字转换为大写形式:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { 
  return name.toUpperCase();
});
  • 现:箭头函数表示
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(
  name => name.toUpperCase()
);
  • 3.2.1 普通函数可以是函数声明或者函数表达式,但是箭头函数始终都是表达式,全程是箭头函数表达式,因此仅在表达式有效时才能使用,包括:
  • 存储在变量中,
  • 当做参数传递函数,
  • 存储在对象的属性中
const greet = name => `Hello ${name}!`;
//调用时
greet('Asser');
  • 3.3.1 如果函数的参数只有一个,不需要使用()包起来,但是只有一个或者多个,则必须需要将参数列表放在圆括号内:
// 空参数列表需要括号
const sayHi = () => console.log('Hello Udacity Student!');
// 多个参数需要括号
const orderIceCream = (flavor, cone) => console.log(`Here's your ${flavor} ice cream in a ${cone} cone.`);
orderIceCream('chocolate', 'waffle');
  • 3.4.1一般箭头函数只有一个表达式作为函数主题
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(
  name => name.toUpperCase()
);

这种函数表达式形式称为简写主体语法:1.在函数主体周围没有花括号,2.自动返回表达式

  • 3.5.1 但是如果箭头函数的主体内需要多行代码, 则需要使用常规主体语法:1.它将函数主体放在花括号内;2.需要使用 return 语句来返回内容
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map( name => {
  name = name.toUpperCase();
  return `${name} has ${name.length} characters in their name`;
});
  • 3.5. javascript标准函数this
    3.5.1. new 对象
const mySundae = new Sundae('Chocolate', ['Sprinkles', 'Hot Fudge']);

sundae这个构造函数内的this的值是实例对象, 因为他使用new被调用.
3.5.2. 指定的对象

const result = obj1.printName.call(obj2);

函数使用call/apply被调用,this的值指向指定的obj2,因为call()第一个参数明确设置this的指向
3.5.3. 上下`文对象

data.teleport();

函数是对象的方法, this指向就是那个对象,此处this就是指向data.
3.5.3. 全局对象或 undefined

teleport();

此处是this指向全局对象,在严格模式下,指向undefined.

javascript中this是很复杂的概念, 要详细判断this,请参考this豁然开朗

  • 3.6. 箭头函数和this
    对于普通函数, this的值基于函数如何被调用, 对于箭头函数,this的值基于函数周围的上下文, 换句话说,this的值和函数外面的this的值是一样的.
function IceCream() {
    this.scoops = 0;
}

// 为 IceCream 添加 addScoop 方法
IceCream.prototype.addScoop = function() {
    setTimeout(function() {
        this.scoops++;
        console.log('scoop added!');
        console.log(this.scoops); // undefined+1=NaN
        console.log(dessert.scoops); //0
    }, 500);
};


----------

标题

const dessert = new IceCream();
dessert.addScoop();

传递给 setTimeout() 的函数被调用时没用到 new、call() 或 apply(),也没用到上下文对象。意味着函数内的 this 的值是全局对象,不是 dessert 对象。实际上发生的情况是,创建了新的 scoops 变量(默认值为 undefined),然后递增(undefined + 1 结果为 NaN);解决此问题的方式之一是使用闭包(closure)

// 构造函数
function IceCream() {
  this.scoops = 0;
}

// 为 IceCream 添加 addScoop 方法
IceCream.prototype.addScoop = function() {
  const cone = this; // 设置 `this` 给 `cone`变量
  setTimeout(function() {
    cone.scoops++; // 引用`cone`变量
    console.log('scoop added!'); 
    console.log(dessert.scoops);//1
  }, 0.5);
};

const dessert = new IceCream();
dessert.addScoop();

箭头函数的作用正是如此, 将setTimeOut()的函数改为剪头函数:

/ 构造函数
function IceCream() {
  this.scoops = 0;
}

// 为 IceCream 添加 addScoop 方法
IceCream.prototype.addScoop = function() {
  setTimeout(() => { // 一个箭头函数被传递给setTimeout
    this.scoops++;
    console.log('scoop added!');
    console.log(dessert.scoops);//1
  }, 0.5);
};

const dessert = new IceCream();
dessert.addScoop();

4. 默认参数函数

function greet(name, greeting) {
  name = (typeof name !== 'undefined') ?  name : 'Student';
  greeting = (typeof greeting !== 'undefined') ?  greeting : 'Welcome';

  return `${greeting} ${name}!`;
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

greet() 函数中混乱的前两行的作用是什么?它们的作用是当所需的参数未提供时,为函数提供默认的值。但是看起来很麻烦, ES6引入一种新的方式创建默认值, 他叫默认函数参数:

function greet(name = 'Student', greeting = 'Welcome') {
  return `${greeting} ${name}!`;
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

5. 默认值与解构

  • 5.1. 默认值与解构数组
    前:
function createGrid([width = 5, height = 5]) {
  return `Generates a ${width} x ${height} grid`;
}

createGrid([]); // Generates a 5 x 5 grid
createGrid([2]); // Generates a 2 x 5 grid
createGrid([2, 3]); // Generates a 2 x 3 grid
createGrid([undefined, 3]); // Generates a 5 x 3 grid

createGrid() 函数预期传入的是数组。它通过解构将数组中的第一项设为 width,第二项设为 height。如果数组为空,或者只有一项,那么就会使用默认参数,并将缺失的参数设为默认值 5。但是存在一个问题:

createGrid(); // throws an error

Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined

现:出现错误,因为 createGrid() 预期传入的是数组,然后对其进行解构。因为函数被调用时没有传入数组,所以出现问题。但是,我们可以使用默认的函数参数!

function createGrid([width = 5, height = 5] = []) {
  return `Generating a grid of ${width} by ${height}`;
}
createGrid(); // Generates a 5 x 5 grid
  • WechatIMG218.jpeg
  • 5.2. 默认值与解构函数:就像使用数组默认值解构数组一样,函数可以让对象成为一个默认参数,并使用对象解构:
function createSundae({scoops = 1, toppings = ['Hot Fudge']}={}) {
  const scoopText = scoops === 1 ? 'scoop' : 'scoops';
  return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`;
}

createSundae({}); // Your sundae has 1 scoop with Hot Fudge toppings.
createSundae({scoops: 2}); // Your sundae has 2 scoops with Hot Fudge toppings.
createSundae({scoops: 2, toppings: ['Sprinkles']}); // Your sundae has 2 scoops with Sprinkles toppings.
createSundae({toppings: ['Cookie Dough']}); // Your sundae has 1 scoop with Cookie Dough toppings.
createSundae(); // Your sundae has 1 scoop with Hot Fudge toppings.
  • 5.3. 数组默认值与对象默认值:默认函数参数只是个简单的添加内容,但是却带来很多便利!与数组默认值相比,对象默认值具备的一个优势是能够处理跳过的选项。看看下面的代码:

现:

function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) { … }

在 createSundae() 函数使用对象默认值进行解构时,如果你想使用 scoops 的默认值,但是更改 toppings,那么只需使用 toppings 传入一个对象

createSundae({toppings: ['Hot Fudge', 'Sprinkles', 'Caramel']});

将上述示例与使用数组默认值进行解构的同一函数相对比。

前:

function createSundae([scoops = 1, toppings = ['Hot Fudge']] = []) { … }

对于这个函数,如果想使用 scoops 的默认数量,但是更改 toppings,则必须以这种奇怪的方式调用你的函数:

createSundae([undefined, ['Hot Fudge', 'Sprinkles', 'Caramel']]);

因为数组是基于位置的,我们需要传入 undefined 以跳过第一个参数(并使用默认值)来到达第二个参数。

6. 解构:在ES6中,可以使用解构从数组和对象提取值并赋值给独特的变量

  • 6.1. 前:
const point = [10, 25, -34];
const [x, y, z] = point;
console.log(x, y, z);
  • WechatIMG219.jpeg

    []表示被解构的数组, x,y,z表示要将数组中的值存储在其中的变量, 在解构数组时, 还可以忽略值, 例如const[x,,z]=point,忽略y坐标.
    现:
const gemstone = {
  type: 'quartz',
  color: 'rose',
  karat: 21.29
};
const {type, color, karat} = gemstone;
console.log(type, color, karat);

花括号 { } 表示被解构的对象,type、color 和 karat 表示要将对象中的属性存储到其中的变量

  • 6.2. 对象字面量简写法
    前:
let type = 'quartz';
let color = 'rose';
let carat = 21.29;
const gemstone = {
  type: type,
  color: color,
  carat: carat
};
console.log(gemstone);

现:使用和所分配的变量名称相同的名称初始化对象时如果属性名称和所分配的变量名称一样,那么就可以从对象属性中删掉这些重复的变量名称。

let type = 'quartz';
let color = 'rose';
let carat = 21.29;
const gemstone = {type,color,carat};
console.log(gemstone);

//简写
const gemstone = {
  type,
  color,
  carat,
  calculateWorth: function() {
    // 将根据类型(type),颜色(color)和克拉(carat)计算宝石(gemstone)的价值
  }
};

匿名函数被分配给属性 calculateWorth,但是真的需要 function 关键字吗?在 ES6 中不需要!

let gemstone = {
  type,
  color,
  carat,
  calculateWorth() { ... }
};

7. 模版字面量

  • 前:将字符串连接到一起的方法是+或者concat()方法,如
const student = {
  name: 'Richard Kalehoff',
  guardian: 'Mr. Kalehoff'
};

const teacher = {
  name: 'Mrs. Wilson',
  room: 'N231'
}

let message = student.name + ' please see ' + teacher.name + ' in ' + teacher.room + ' to pick up your report card.';
  • WechatIMG223.jpeg
  • 现:模板字面量本质上是包含嵌入式表达式的字符串字面量.
    模板字面量用倒引号 ( `` )(而不是单引号 ( '' ) 或双引号( "" ))表示,可以包含用 ${expression} 表示的占位符
const student = {
  name: 'Richard Kalehoff',
  guardian: 'Mr. Kalehoff'
};

const teacher = {
  name: 'Mrs. Wilson',
  room: 'N231'
}
let message = `${student.name} please see ${teacher.name} in ${teacher.room} to pick up your report card.`;
  • WechatIMG224.jpeg

7. for...of循环

for...of循环是最新添加到javaScript循环系列中的循环。
它结合了其兄弟循环形式for循环和for...in循环的优势,可以循环任何可迭代(也就是遵守可迭代协议)类型的数据。默认情况下,包含以下数据类型:String、Array、Map、Set,注意不包含Object数据类型(即{})。

默认情况下,对象是不可迭代的

  • 7.1. for循环:
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (let i = 0; i < digits.length; i++) {
  console.log(digits[i]);
}
  • WechatIMG225.jpeg

    for 循环的最大缺点是需要跟踪计数器和退出条件。
    虽然 for 循环在循环数组时的确具有优势,但是某些数据结构不是数组,因此并非始终适合使用 loop 循环。
  • 7.2. for...in循环
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const index in digits) {
  console.log(digits[index]);
}
  • WechatIMG226.jpeg

    依然需要使用 index 来访问数组的值
    当你需要向数组中添加额外的方法(或另一个对象)时,for...in 循环会带来很大的麻烦。因为 for...in 循环循环访问所有可枚举的属性,意味着如果向数组的原型中添加任何其他属性,这些属性也会出现在循环中。
Array.prototype.decimalfy = function() {
  for (let i = 0; i < this.length; i++) {
    this[i] = this[i].toFixed(2);
  }
};

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const index in digits) {
  console.log(digits[index]);
}
  • WechatIMG227.jpeg

forEach 循环 是另一种形式的 JavaScript 循环。但是,forEach() 实际上是数组方法,因此只能用在数组中。也无法停止或退出 forEach 循环。如果希望你的循环中出现这种行为,则需要使用基本的 for 循环。

  • 6.3. for...of循环
    for...of 循环用于循环访问任何可迭代的数据类型。
    for...of 循环的编写方式和 for...in 循环的基本一样,只是将 in 替换为 of,可以忽略索引。
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  console.log(digit);
}

建议使用复数对象名称来表示多个值集合。这样,循环该集合时,可以使用名称的单数版本来表示集合中的单个值。例如,for (const button of buttons) {…}。

for...of 循环还具有其他优势,解决了 for 和 for...in 循环的不足之处。你可以随时停止或退出 for...of 循环。

for (const digit of digits) {
  if (digit % 2 === 0) {
    continue;
  }
  console.log(digit);
}

不用担心向对象中添加新的属性。for...of 循环将只循环访问对象中的值。

Array.prototype.decimalfy = function() {
  for (i = 0; i < this.length; i++) {
    this[i] = this[i].toFixed(2);
  }
};

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  console.log(digit);
}

8. Javascript类

  • 前:ES5创建类:
function Plane(numEngines) {
  this.numEngines = numEngines;
  this.enginesActive = false;
}

// 由所有实例 "继承" 的方法
Plane.prototype.startEngines = function () {
  console.log('starting engines...');
  this.enginesActive = true;
};
  • 后:ES6类只是语法糖,原型继续实际上在底层隐藏起来,与传统类机制语言有些区别。
class Plane {
 //constructor方法虽然在类中,但不是原型上的方法,只是用来生成实例的.
 constructor(numEngines) {
   this.numEngines = numEngines;
   this.enginesActive = false;
 }
 //原型上的方法, 由所有实例对象共享.
 startEngines() {
   console.log('starting engines…');
   this.enginesActive = true;
 }
}

console.log(typeof Plane); //function

javascript中类其实只是function, 方法之间不能使用,,不用逗号区分属性和方法.

  • 7.1. 静态方法:要添加静态方法,需要在方法名称前面旧加上关键词 static
class Plane {
  constructor(numEngines) {
    this.numEngines = numEngines;
    this.enginesActive = false;
  }
  static badWeather(planes) {
    for (plane of planes) {
      plane.enginesActive = false;
    }
  }
  startEngines() {
    console.log('starting engines…');
    this.enginesActive = true;
  }
}

1.关键字class带来其他基于类的语言的很多思想,但是没有向javascript中添加此功能
2.javascript类实际上还是原型继承
3.创建javascript类的新实例时必须使用new关键字

  • 7.2. super 和 extends:使用新的super和extends 关键字扩展类:
  • 现:
class Tree {
  constructor(size = '10', leaves = {spring: 'green', summer: 'green', fall: 'orange', winter: null}) {
    this.size = size;
    this.leaves = leaves;
    this.leafColor = null;
  }

  changeSeason(season) {
    this.leafColor = this.leaves[season];
    if (season === 'spring') {
      this.size += 1;
    }
  }
}

class Maple extends Tree {
  constructor(syrupQty = 15, size, leaves) {
    super(size, leaves); //super用作函数
    this.syrupQty = syrupQty;
  }

  changeSeason(season) {
    super.changeSeason(season);//super用作对象
    if (season === 'spring') {
      this.syrupQty += 1;
    }
  }

  gatherSyrup() {
    this.syrupQty -= 3;
  }
}
  • 后:使用ES5编写同样功能的类:
function Tree(size, leaves) {
  this.size = size || 10;
  this.leaves = leaves || {spring: 'green', summer: 'green', fall: 'orange', winter: null};
  this.leafColor;
}

Tree.prototype.changeSeason = function(season) {
  this.leafColor = this.leaves[season];
  if (season === 'spring') {
    this.size += 1;
  }
}

function Maple (syrupQty, size, leaves) {
  Tree.call(this, size, leaves);
  this.syrupQty = syrupQty || 15;
}

Maple.prototype = Object.create(Tree.prototype);
Maple.prototype.constructor = Maple;

Maple.prototype.changeSeason = function(season) {
  Tree.prototype.changeSeason.call(this, season);
  if (season === 'spring') {
    this.syrupQty += 1;
  }
}

Maple.prototype.gatherSyrup = function() {
  this.syrupQty -= 3;
}

super必须在this之前被调用
在子类构造函数中,在使用this之前,必须先调用超级类。

class Apple {}
class GrannySmith extends Apple {
  constructor(tartnessLevel, energy) {
    this.tartnessLevel = tartnessLevel; // 在 'super' 之前会抛出一个错误!
    super(energy); 
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容

  • 学习vue的语法之前,首先要掌握一些ES6的新语法,以便更容易理解vue中的一些编程风格。 1. 变量与常量的声明...
    yangsg阅读 799评论 0 3
  • let const 声明变量 1. let变量声明 let的特点是不会变量提升, 2. const 变量声明 c...
    点_ba7a阅读 297评论 0 0
  • 最常用的ES6特性 let, const, class, extends, super, arrow functi...
    心至靜行至遠阅读 1,717评论 0 0
  • 1.变量声明const和let 我们都是知道在ES6以前,var关键字声明变量。无论声明在何处,都会被视为声明在函...
    喵呜Yuri阅读 358评论 0 1
  • 对象字面量的简写属性和计算的属性名不可同时使用,原因是简写属性是一种在编译阶段的就会生效的语法糖,而计算的属性名则...
    亚讯阅读 498评论 0 0