十二:以理论结合实践方式梳理前端 ES 6+ ——— ES 6+ 新特性

变量定义

在 ES6 之前,定义变量只能使用 var 关键字,而在 ES6 中新增 letconst 关键字,它们之间的区别如下:

关键字作用域变量是否提升能否重复定义
var函数作用域
letconst块级作用域
function function_scope() {
    console.log(result); // undefined
    var result = 0;
    for (var count = 1; count <= 5; count++) { result += count; }
    console.log(count); // 5
    return result;
}

function block_scope() {
    // console.log(result) -> ReferenceError: result is not defined
    let result = 0;
    for (let count = 1; count <= 5; count++) { result += count; }
    // console.log(count) -> ReferenceError: count is not defined
    return result;
}

letconst 之间的区别如下:

  • 使用 const 定义的变量在声明时必须赋值,而 let 不用
  • 使用 const 定义的变量声明之后不能修改,而 let 不会
// const a -> Uncaught SyntaxError: Missing initializer in const declaration
const a = 0;
// a = 1 -> Uncaught TypeError: Assignment to constant variable.

注意哦,这里所说的不能修改,并不是说变量的值不可修改,而是变量的标识符不能重新分配

准确而言,const 声明的变量是一个值的只读引用,它意味着栈空间的地址不可修改,而非堆空间中的值不可修改

因此对于引用类型,我们还是可以修改它的值的

const a = [1, 3, 5];
a[0] = 2;
console.log(a); // (3) [2, 3, 5]

变量作用域

var、let、const 都是 JavaScript 中声明变量的方式,使用 var 声明的变量具有函数作用域

  • 如果变量是在函数内声明的,那么这个变量在这个函数内可用

  • 如果变量是在函数外声明的,那么这个变量就会成为全局变量,在全局环境中可用

    并且在浏览器环境中将会挂载在 window 对象下,而在 Node 环境中将会挂载在 global 对象下

var a = 0;
function func() {
    for (var i = 1; i <= 5; i++) { a = a + 1; }
    console.log('a inside the function: ' + a);
    console.log('i inside the function: ' + i);
}
func();
console.log('a outside the function: ' + a);
// console.log('i outside the function: ' + i) -> i is not defined

/*
 * 执行结果:
 * a inside the function: 5
 * i inside the function: 6
 * a outside the function: 5
**/

使用 let 和 const 声明的变量具有块作用域

  • 如果变量是在块内声明,那么仅在块内可用
  • 如果变量是在块外声明,那么这个变量也会成为全局变量,在全局环境中可用,但是不会挂载
let a = 0;
function func() {
    for (let i = 1; i <= 5; i++) { a = a + 1; }
    console.log('a inside the function: ' + a);
    // console.log('i inside the function: ' + i) -> i is not defined
}
func();
console.log('a outside the function: ' + a);
// console.log('i outside the function: ' + i) -> i is not defined

/*
 * 执行结果:
 * a inside the function: 5
 * a outside the function: 5
**/

补充一点,如果在声明变量的时候没有使用关键字(var、let、const),无论位置如何,都会成为全局变量

function declare() {
    a = 'Hello';
}

function use() {
    console.log(a);
}

declare();
use();				// 执行结果:Hello

变量提升

使用 var 声明的变量会将声明提前(注意赋值不会一起提前),但是使用 let 和 const 声明的变量不会

console.log(a);
var a = 1;

console.log(b);
let b = 1;

/*
 * 执行结果:
 * undefined
 * Uncaught ReferenceError: a is not defined
**/

同名变量

使用 var 声明的变量可以多次声明,但是使用 let 和 const 声明的变量不能

var a = 0;
var a = 1;

let b = 0;
let b = 1;

/*
 * 执行结果:
 * Uncaught SyntaxError: Identifier 'b' has already been declared
**/

只读引用

从上面的三组对比可以发现,let 和 const 具有一样的特点,那么它们之间又有什么区别呢?

事实上,除了它们共有的特点外,const 还具有以下两个特点:

  • 一旦声明,必须赋值
  • 一旦声明,不能修改
// const a -> Uncaught SyntaxError: Missing initializer in const declaration
const a = 0;
// a = 1 -> Uncaught TypeError: Assignment to constant variable.

注意哦,这里所说的不能修改,并不是说变量的值不可修改,而是变量的标识符不能重新分配

准确而言,const 声明的变量是一个值的只读引用,它意味着栈空间的地址不可修改,而非堆空间中的值不可修改

因此对于引用类型,我们还是可以修改它的值的

const a = [1, 3, 5];
a[0] = 2; // 修改其值
console.log(a);				// 执行结果:(3) [2, 3, 5]

数组迭代

在 ES6 之前,使用 for 循环迭代数组有两种方式,分别是传统 for 循环和 for...in 循环

let array = ['a', 'b', 'c'];
// 传统 for 循环
for (let index = 0; index < array.length; index++) {
    console.log(index + ': ' + array[index]);
}
// for...in 循环
for (let index in array) {
    console.log(index + ': ' + array[index]);
}

/*
 * 执行结果:
 * 0: a
 * 1: b
 * 2: c
**/

而在 ES6 中新增 for...of 循环,可以直接遍历数组元素,而非数组索引

let array = ['a', 'b', 'c'];
// for...of 循环
for (let item of array) {
    console.log(item);			// 执行结果:a b c
}

for...of 循环中还可以使用 continuebreak 语句

let array = [1, 2, 3, 4, 5, 6, 7, 8];
let sum = 0;
for (let item of array) {
    if (item % 2 === 0) continue;
    sum += item;
}
console.log(sum); // 16

模板字符串

模板字符串在多行字符串和字符串拼接等场景下十分方便

// 多行字符串
let html = '<ul>' + 
    '<li>Apple</li>' +
    '<li>Banana</li>' +
    '<li>Cherry</li>' +
    '</ul>';
console.log(html);
// 字符串拼接
let protocol = 'https';
let host = '127.0.0.1';
let port = '80';
let path = 'index.html';
let url = protocol + '://' + host + ':' + port + '/' + path;
console.log(url); /* http://127.0.0.1:80/index.html */
--------------------------------------------------------------------------------------------------------------------------------
// 多行字符串,保留原有格式
let html = `
<ul>
    <li>Apple</li>
    <li>Banana</li>
    <li>Cherry</li>
</ul>
`;
console.log(html);
// 字符串拼接,可以使用变量
let protocol = 'https';
let host = '127.0.0.1';
let port = '80';
let path = 'index.html';
let url = `${protocol}://${host}:${port}/${path}`;
console.log(url); /* http://127.0.0.1:80/index.html */

解构语法

解构语法可以将数组和对象中的值提取出来并赋值给新的变量

// 数组解构
let array = ['a', 'b', 'c']
let x = array[0];
let y = array[1];
let z = array[2];
console.log(x, y ,z); // a b c
// 对象解构
let object = { name: 'Steve', age: 18 };
let name = object.name;
let age = object.age;
console.log(name, age); // Steve 18
--------------------------------------------------------------------------------------------------------------------------------
// 数组解构
let array = ['a', 'b', 'c'];
let [x, y, z] = array;
console.log(x, y, z); // a b c
// 对象解构,变量名要与属性名相同
let object = { name: 'Steve', age: 18 };
let { name, age } = object;
console.log(name, age); // Steve 18
--------------------------------------------------------------------------------------------------------------------------------
// 设置默认值
let array = ['a', 'b'];
let [x = 'x', y = 'y', z = 'z'] = array;
console.log(x, y, z); // a b z
// 重命名变量
let object = { name: 'Steve', age: 18 };
let { name: nickName, age: nominalAge } = object;
console.log(nickName, nominalAge); // Steve 18

扩展运算符

// 数组复制
let array = ['a', 'b', 'c'];
let array_copy = array.concat();
console.log(array_copy); // (3) ["a", "b", "c"]
// 数组合并
let array_one = ['a', 'b', 'c'];
let array_two = ['d', 'e', 'f'];
let array_merge = array_one.concat(array_two);
console.log(array_merge); // (6) ["a", "b", "c", "d", "e", "f"]
// 接收函数参数,所有传入的参数都会保存在 arguments 中
function add() {
    let result = 0;
    Array.prototype.forEach.call(arguments, function(item) { result += item; });
    return result;
}
let result = add(1, 2, 3);
console.log(result); // 6
--------------------------------------------------------------------------------------------------------------------------------
// 数组复制
let array = ['a', 'b', 'c'];
let array_copy = [...array];
console.log(array_copy); // (3) ["a", "b", "c"]
// 合并数组
let array_one = ['a', 'b', 'c'];
let array_two = ['d', 'e', 'f'];
let array_merge = [...array_one, ...array_two];
console.log(array_merge); // (6) ["a", "b", "c", "d", "e", "f"]
// 接收函数参数,剩余参数作为函数的最后一个参数,将传入的参数以数组的形式储存起来
function add(...array) {
    let result = 0;
    array.forEach(function(item) { result += item; });
    return result;
}
let result = add(1, 2, 3);
console.log(result); // 6

默认参数

在定义函数的时候,可以直接为函数参数设置默认值

function greet(somebody) {
    var somebody = somebody || 'stranger';
    console.log('Hello, ' + somebody);
}
greet('Amy'); // Hello, Amy
greet(); // Hello, stranger
--------------------------------------------------------------------------------------------------------------------------------
function greet(somebody = 'stranger') {
    console.log('Hello, ' + somebody);
}
greet('Amy'); // Hello, Amy
greet(); // Hello, stranger

箭头函数

使用箭头函数不仅可以更加方便的定义函数,而且 this 的值将会继承父级执行上下文 this 的值

// 过滤奇数,元素累加
let sum = 0;
let arr = [1, 2, 3, 4, 5];
let even = arr.filter(function(item) { return item % 2 === 0; });
even.forEach(function(item) { sum = sum + item; });
console.log(sum); // 6
// this 取值
let object = {
    value: 'hello',
    print: function() {
        // 使用 bind 函数将 this 的值绑定好
        setTimeout(function() { console.log(this.value); }.bind(this), 1000);
    }
}
object.print(); // hello
--------------------------------------------------------------------------------------------------------------------------------
// 过滤奇数,元素累加
let sum = 0;
let arr = [1, 2, 3, 4, 5];
let even = arr.filter((item) => (item % 2 === 0));
even.forEach((item) => { sum = sum + item });
console.log(sum); // 6
// this 取值
let object = {
    value: 'hello',
    print: function() {
        // 使用箭头函数,this 的值将会继承父级执行上下文(在这里是 print 函数)this 的值
        setTimeout(() => { console.log(this.value); }, 1000);
    }
}
object.print(); // hello
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值