ES6新语法

278 阅读9分钟

块级作用域

先说说没有块级作用域,可能产生的问题。

1、内层变量覆盖外层变量

var temp=1;

function f(){
    console.log(temp);
    if(false){
        var temp='字符串变量';
    }
}
f()

运行结果:

undefined

因为变量提升,导致 if 语句体中的变量 temp 覆盖了外层变量 temp。

2、用于循环的计数变量,其实是全局变量

var s = 'es6';
for (var i = 0; i < s.length; i++) {
    s[i];
}
console.log('i=' + i);

运行结果:

i=3

块级作用域

  • 使用 {...} 结构,就可以标注出一个块级作用域。
  • 块级作用域里面的用let 命令声明的变量和 const 命令声明的常量的作用域只在这个块里面,不会出现内层变量覆盖外层变量和变量泄露为全局变量的现象
  • 块级作用域对var命令无效
//块级作用域对var命令无效,a变量泄露到外层作用域了
if (true) {
    var a = 'apple';
}
console.log(a); //apple

//let由于块级作用域的作用,不会泄露为全局变量
if (true) {
    let b = 'banana';
}
console.log(b); //Error: b is not defined

//const由于块级作用域的作用,也不会泄露为全局变量
if (true) {
    const o = 'orange';
}
console.log(o); //o is not defined

//每一对“{}”都是一个块级作用域,而且互不干扰。
{
    let a = 'apple';

    {
        let a = 'aaa';

        {
            let a = 'AAA';
        }
    }
}

函数默认参数

(一)概念

在ES6中,可以为函数的参数指定默认值。函数默认参数允许在没有值或undefined被传入时使用默认形参。

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

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

(二)默认参数使用注意点

  1. 参数变量是默认声明的,所以不能用let或const再次声明。
function foo(x = 5) {
  let x = 1; // error
  const x = 2; // error
}
  1. 使用参数默认值时,函数不能有同名参数。
// 不报错
function foo(x, x, y) {
  // ...
}

// 报错
function foo(x, x, y = 1) {
  // ...
}
// SyntaxError: Duplicate parameter name not allowed in this context
  1. 显式传入undefined或不传值时使用函数默认参数值;传入''或null时使用传入的参数值。
function test(num = 1) {
  console.log(typeof num);
}

test();          // 'number' (num is set to 1)
test(undefined); // 'number' (num is set to 1 too)

// test with other falsy values:
test('');        // 'string' (num is set to '')
test(null);      // 'object' (num is set to null)
  1. 参数默认值不是传值的,而是在函数被调用时,参数默认值才会被解析。
function append(value, array = []) {
  array.push(value);
  return array;
}

append(1); //[1]
append(2); //[2], not [1, 2]
  1. 位置在前的默认参数可用于后面的默认参数。
function greet(name, greeting, message = greeting + ' ' + name) {
    return [name, greeting, message];
}

greet('David', 'Hi');  // ["David", "Hi", "Hi David"]
greet('David', 'Hi', 'Happy Birthday!');  // ["David", "Hi", "Happy Birthday!"]
  1. 通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。
// 例一
function f(x = 1, y) {
  return [x, y];
}

f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]

// 例二
function f(x, y = 5, z) {
  return [x, y, z];
}

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
  1. 指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。后文的 rest 参数也不会计入length属性。
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2

(function(...args) {}).length // 0

(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1

转自虹猫1992

剩余(rest)参数

(一)概念

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function add(...values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

add(2, 5, 3) // 10

(二)rest 参数使用注意点

  1. rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
// 报错
function f(a, ...b, c) {
  // ...
}
  1. 函数的length属性,不包括 rest 参数。
(function(a) {}).length  // 1
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1
  1. rest参数可以被解构,这意味着他们的数据可以被解包到不同的变量中。
function f(...[a, b, c]) {
  return a + b + c;
}

f(1)          // NaN (b and c are undefined)
f(1, 2, 3)    // 6
f(1, 2, 3, 4) // 6 (the fourth parameter is not destructured)

(三)rest参数和 arguments对象的区别

  1. rest参数只包含那些没有对应形参的实参,而arguments对象包含了传给函数的所有实参。
  2. arguments对象不是一个真正的数组,而rest参数是真正的Array实例,也就是说你能够在它上面直接使用所有的数组方法,比如 sort,map,forEach或pop。
  3. arguments对象还有一些附加的属性 (如callee属性)。

展开运算符...xxx

(一)概念

展开运算符,将一个数组转为用逗号分隔的参数序列

(二)使用

  1. 合并数组
let a = [1,2,3];
let b = [4,5,6];
let c = [...a,...b]; // [1,2,3,4,5,6]
  1. 替代apply
function f(a,b,c){
  console.log(a,b,c)
}
let args = [1,2,3];
// 以下三种方法结果相同
f.apply(null,args)
f(...args)
f(1,2,3)

function f2(...args){
  console.log(args)
}
f2(1,2,3) // [1,2,3]

function f3(){
  console.log(Array.from(arguments))
}
f3(1,2,3) // [1,2,3]
  1. Array.from() 可以通过以下方式来创建数组对象:

伪数组对象(拥有一个 length 属性和若干索引属性的任意对象) 可迭代对象(可以获取对象中的元素,如 Map和 Set 等)

let a = [1,2,3];
let b = [4,5,6];

Array.prototype.push.apply(a,b);
// 或
a.push(...b)
// 两种方法取其一
  1. 解构赋值
let a = [1,2,3,4,5,6]
let [c,...d] = a
console.log(c); // 1
console.log(d); // [2,3,4,5,6]
//展开运算符必须放在最后一位
  1. 字符串转为数组,正确识别 32 位的 Unicode 字符
[...'siva'] // ['s','i','v','a']
[...'x\uD83D\uDE80y'].length // 3
  1. 具有 Iterator 接口的对象,转换成数组
var nodelist = document.querySelectorAll('div');
console.log([...nodelist]) // 转化成数组

var map = new Map([[1,11],[2,22],[3,33]]);
console.log([...map.keys()]); // [1,2,3]
  1. 浅拷贝
//数组
var a = [1,2,4]
var b = [...a]
a.push(6)
console.log(b) // [1,2,4]

//对象
var a = {a:1}
var b = {...a}
a.a = 5
console.log(b.a) // 1

作者:一二三kkxx 链接:www.jianshu.com/p/3935a8034… 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

模板字符串

(一)概念

  • 模板字面量 是允许嵌入表达式的字符串字面量。你可以使用多行字符串和字符串插值功能。
  • 模板字符串使用反引号 () 来代替普通字符串中的用双引号和单引号。模板字符串可以包含特定语法(${expression})的占位符。
  • 所有模板字符串的空格和换行,都是被保留的,如果你不想要前后换行,可以使用trim方法消除它。
  • ${expression}你可以写任意JavaScript表达式,包括调用函数
var x = 1;
var y = 2;
 
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
 
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
 
var obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"
function fn() {
 return "Hello World";
}
 
`foo ${fn()} bar`
// foo Hello World bar

(二)使用

  1. 多行字符串

所有模板字符串的空格和换行,都是被保留的。要获得多行字符串直接换行就行。

console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
  1. 在反引号里使用${expression}插入表达式
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."
  1. 嵌套模板

在某些时候,嵌套模板是具有可配置字符串的最简单也是更可读的方法。 在模板中,只需在模板内的占位符 ${expression} 内使用它们,就可以轻松地使用内部反引号。 例如,如果条件 a 是真的,那么返回这个模板化的文字。

const classes = `header ${ isLargeScreen() ? '' :
    (item.isCollapsed ? 'icon-expander' : 'icon-collapser') }`;
  1. 带标签的模板字符串

更高级的形式的模板字符串是带标签的模板字符串。标签使您可以用函数解析模板字符串。标签函数的第一个参数包含一个字符串值的数组。其余的参数与表达式相关。最后,你的函数可以返回处理好的的字符串(或者它可以返回完全不同的东西 , 如下个例子所述)。用于该标签的函数的名称可以被命名为任何名字。

var person = 'Mike';
var age = 28;

function myTag(strings, personExp, ageExp) {

  var str0 = strings[0]; // "that "
  var str1 = strings[1]; // " is a "

  // There is technically a string after
  // the final expression (in our example),
  // but it is empty (""), so disregard.
  // var str2 = strings[2];

  var ageStr;
  if (ageExp > 99){
    ageStr = 'centenarian';
  } else {
    ageStr = 'youngster';
  }

  return str0 + personExp + str1 + ageStr;

}

var output = myTag`that ${ person } is a ${ age }`;

console.log(output);
// that Mike is a youngster

对象属性增强

  1. 属性初始化语法简写

给一个属性赋一个变量值,如果变量名和属性名相同,可以省略变量名和冒号,直接写属性名,js引擎在执行代码的时候,自动查找 和属性命名相同的变量并赋值。

let x = 1, y = 2;
let object = { 
&emsp;&emsp;x, // 属性名是x,变量名也是x, 两者一致,可以简写
&emsp;&emsp;y 
};
console.log(object.x); //output "1"
  1. 更为简洁的方法属性定义

ES5的时候,把一个函数赋值给属性的时候,函数必须是一个完整的函数定义

let object = {
    myFunction: function(){
        console.log("Hello World")  
    }  
}

  但是在ES6中,可以把:function 这一部分去掉了,写法如下

let object = {
    myFunction(){
        console.log("Hello World")  
    }  
}

  语法确实简洁多了,不过要注意一个特殊情况,只有给属性赋值的是匿名函数的时候,才可以使用简洁语法,如果赋值的是一个有名字的函数,那么就不能使用匿名函数了。如下情况就不能

let object = {
    myFunction: function hello(){
        console.log("Hello World")  
    }  
}

  函数hello 赋值给属性myFunction, 你可能会问,为什么要给函数取一个hello 名字,最常见的一种情况是递归,自己调用自己,如果没有名字,怎么调用?还有就是程序debugger 的时候,有函数名字可以直接定位, you don't know js 的作者就强烈建议书写有名字的函数。   

  1. 计算属性名

ES5 的时候,对象字面量中的属性都是事先定义好的, 不能使用变量,从而在程序运行的时候动态生成属性

但在ES6中,这种情况改变了,对象字面量中可以存在动态生成的属性,不过语法就要稍微变一下了,需要把动态属性用[] 包括起来,这样在程序运行的时候可以对[] 中的内容进行计算

let object = {
&emsp;&emsp;["first" + "Name"]: "Eden",
};

//extract
console.log(object["first" + "Name"]); //Output "Eden"
  1. 对重复属性名的处理

在ES5 的时候,如果给一个对象赋值为相同的属性,它就会报错。但在ES6 下,它不会报错了,它会取最后一个相同属性的值。

let obj = {
    name: 'Sam',
    name: 'Jason'
};
console.log(obj.name) // 'jason'

解构赋值

通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20


// Stage 4(已完成)提案中的特性
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}

模块

看我的这篇博客