ES6基础(一)

ECMAScript(简称ECMA或ES)和JavaScript(简称JS)的关系是什么呢?

ES是标准,JS是实现。

变量声明

ES5中var有什么缺陷呢?

var可以重复声明变量,带来的问题是会覆盖掉别人已经声明的变量。
无法限制var声明变量的修改
变量作用域

JS的作用域只有全局作用域global scope和函数作用域function scope两种,并没有块级作用域。所以,在JS中的代码块中使用var声明的变量的作用域都是隶属于全局作用域的。

var price = 100;
var count = 5;
if(count > 3){
    var discount = price * 0.5;
    console.log(discount);//50
}
console.log(discount);//50
函数内声明的局部变量的作用域只在函数内有效

function fn(){
    var cnt = 5;
    console.log(cnt);
}
fn();//5
console.log(cnt);//Uncaught ReferenceError: cnt is not defined

ES6中有两种定义变量的方式,分别是const和let关键字。

使用关键字let声明变量

let声明的变量是可以被修改的
let声明的变量不能被重复声明
let discount = 10;//作用域在全局
let discount = 100;//Uncaught SyntaxError: Identifier 'discount' has already been declared
let声明的变量拥有块级作用域block scope
let count = 5;
let discount = 10;//作用域在全局
if(count > 3){
let discount = 100;//作用域在块级
}
console.log(discount);//10
使用关键字const声明常量

const声明的常量是不可以被修改的
const pi = 3.14;
pi = 3.1415;//Uncaught TypeError: Assignment to constant variable.
如果使用const声明的是对象(引用),那么是可以改变对象的成员属性的,不变的是引用指针所指向的地址。

const obj = {id:1, name:"alice"};
obj.id = 2;
console.log(obj);//{id: 2, name: "alice"}

如果不允许改变对象的属性值,可使用Object.freeze(object)方法来冻结。

const obj = {id:1, name:"alpha"};

const o = Object.freeze(obj);
console.log(o);//{id: 1, name: "alpha"}

obj.id = 2;
console.log(obj);//{id: 1, name: "alpha"}

o.id = 3;//Attempt to assign to const or readonly variable
console.log(o);//{id: 1, name: "alpha"}

const声明的常量不能重复声明
const声明的常量拥有块级作用域
变量与常量

ES6中使用let声明变量的值是允许修改的,使用const声明的常量的值是禁止修改的。

let i = 1;
i = 10;
console.log(i);//10

const PI = 3.14;
PI = 3.14159;//Uncaught TypeError: Assignment to constant variable.
变量重复声明

ES5中使用var声明的变量是可以被重复赋值的

var i = 1;
console.log(i);//1
var i = 10;
console.log(i);//10

ES6中使用let声明的变量禁止重复声明

let i = 1;
let i = 10;//Uncaught SyntaxError: Identifier 'i' has already been declared

ES6中使用const声明的常量禁止重复声明

const PI = 3.14;
const PI = 3.14;//es6.js:2 Uncaught SyntaxError: Identifier 'PI' has already been declared

块级作用域

ES5中没有块级作用域,只有函数作用域。

使用ES5中的var声明变量,由于缺乏块级作用域,带来了问题。




    
    js


    
    
    
    


问题:每次都会输出3

使用函数闭包的方式解决块级作用域问题




    
    js


    
    
    
    


使用ES6中的let声明的变量具有块级作用域




    
    es6


    
    
    
    


IIFE 立即执行函数表达式

使用let和const替代立即执行函数表达式(IIFE, Immediately-Invoked Function Expression),立即执行函数表达式用于生成一个私有变量。

由于ES5中使用var声明的变量,很容易就会污染全局作用域。例如JS的window对象具有一个name的属性,如果直接使用var定义一个全局变量name则会直接覆盖window对象的name属性。

console.log(name, window.name);
var name = "junchow";
console.log(name, window.name);//junchow junchow

使用立即执行函数表达式可以有效地避免污染全局变量,使变量私有化。

console.log(name, window.name);//"" ""
(function(){
    var name = "junchow";
    console.log(name, window.name);//junchow ""
})();
console.log(name, window.name);//"" ""
使用立即执行函数表达式,虽然使变量私有化了,但并不利用代码的可读性。

const name = "junchow";
console.log(name, window.name);//junchow ""
let name = "junchow";
console.log(name, window.name);//junchow ""
{
    const name = "junchow";
    console.log(name, window.name);//junchow ""
}

怪异的for循环

例如:在for循环中经常会遇到的问题

for(var i=0; i<3; i++){
    console.log(i);// 0 1 2
}
console.log(i);//3
for(var i=0; i<3; i++){
    console.log(i);//0 1 2
    setTimeout(function(){
        console.log(i);// 3 3 3
    },1000);
}
console.log(i);//3

使用ES6的let声明循环变量

for(let i=0; i<3; i++){
    console.log(i);//0 1 2
    setTimeout(function(){
        console.log(i);// 0 1 2
    },1000);
}
console.log(i);//Uncaught ReferenceError: i is not defined

临时性死区

ES6中,在代码块内使用let或const声明变量前,变量都是不可用的。在语法上,称之为临时性死区(TDZ, Temporal Dead Zone)。

使用var声明的变量时存在着变量的提升

console.log(color);//undefined
var color = "red";

为什么是undefined呢?实际上上述代码相当于:

var color;
console.log(color);//undefined
color = "red";

JS中函数以及变量的声明都将被提升到函数的最顶部,JS中变量可以在使用后声明,也就是变量可以先使用再声明。

console.log(color);//Uncaught ReferenceError: Cannot access 'color' before initialization
let color = "red";

变量赋值

解构赋值

表达式左右两边结构必须一模一样
表达式右侧必须是值
声明和赋值不能分开
数组解构赋值

//ES5解构赋值

var arr = [1,2,3];
var x = arr[0];
var y = arr[1];
var z = arr[2];
console.log(x, y, z);//1 2 3

//ES6数组解构赋值

let [x, y, z] = [1, 3, 5];
console.log(x, y, z);//1 3 5

JSON解构赋值

let {id, name} = {id:1, name:"alpha"};
console.log(id, name);//1 "alpha"

字符串

ES6新增方法startsWith和endsWith
ES6新增字符串模板
String.startsWith

startsWith表示参数字符串是否在原字符串的头部,返回布尔值。

string.startsWith(substring[, searchPos]):boolean
例如:验证URL地址的合法性

let url = "http://www.baidu.com";
let bool = url.startsWith("http://");
console.log(bool);//true

startsWith第二个参数为起始位置
例如:验证身份证号码

const identify = "51030019800730366x";
//判断是否为四川省
console.log(identify.startsWith("51"));//true
//判断是否为1980年出生的,startsWith第二个参数为从第几个位置开始
console.log(identify.startsWith("1980", 6));//true
startsWith对大小写敏感
const str = "jack love mary";
console.log(str.startsWith("jack"));//true
console.log(str.startsWith("Jack"));//false
String.endsWith

endsWith表示参数字符串是否在原字符串的尾部,返回布尔值。

let url = "[email protected]";
let bool = url.endsWith("@hotmail.com");
console.log(bool);//true
String.repeat 重复

repeat(count)方法会返回一个新字符串表示将原字符串重复count次后的结果
repeat(count)方法的参数count如果是小数则会被向下取整
repeat(count)方法的参数count如果是负数或Infinity则会报错
repeat(count)方法的参数count如果是NaN则等于0
repeat(count)方法的参数count如果是字符串则会先转换为数字
console.log(`${'='.repeat(10)}`);//==========
console.log(`${'='.repeat(10.9)}`);//==========
console.log(`${'='.repeat(0)}`);//
console.log(`${'='.repeat(NaN)}`);//
console.log(`${'='.repeat("10")}`);//==========
console.log(`${'='.repeat(-10)}`);//Uncaught RangeError: Invalid count value
console.log(`${'='.repeat(Infinity)}`);//Uncaught RangeError: Invalid count value

例如:实现字符串右对齐

//右对齐

const pad = (string, length=0)=> `${' '.repeat(Math.max(length - string.length, 0))}${string}`;

console.log(pad("hello", 20));//               hello
console.log(pad("world", 20));//               world

模板字符串

传统字符串拼接无法正常换行
传统字符串拼接无法友好的插入变量
传统字符串拼接无法友好的处理单引号和双引号相互嵌套的问题
ES6模板字符串使用一对反引号来定义一个模板字符串

let obj = {id:1, title:"test"};
console.log(`id = ${id} title = ${title}`);

模板字符串的应用

const User = {
    id:1,
    name:"junchow",
    date:"2019-08-28",
    todos:[
        {todo:"go to store", status:false},
        {todo:"watch movie", status:true},
        {todo:"running", status:true}
    ]
};

//模板字符串可以进行嵌套

const template = `
    ${User.todos.map(item=>`
  • ${item.todo}
  • `).join("")}
`; console.log(template); document.querySelector("#app").innerHTML = template; const User = { id:1, name:"junchow", date:"2019-08-28", todos:[ {todo:"go to store", status:false}, {todo:"watch movie", status:true}, {todo:"running", status:true} ] };

//模板字符串可以进行嵌套

const template = `
    ${User.todos.map(item=>`
  • ${item.todo} ${item.status===true?"done":"undo"}
  • `).join("")}
`; console.log(template); document.querySelector("#app").innerHTML = template;

标签模板字符串

function tag(template, ...args){
    const html = args.map(arg=>`${arg}`);
    let ret = "";
    template.forEach((item, index) => ret +=`${item} ${html[index]}`);
    return ret;
}

const id = 1;
const name = "junchow";
const sentence = tag`${id} ${name}`;
console.log(sentence);

数组

数组解构Array Destructuring

ES6允许按照一定模式,从数组中提取值,同时定义变量并对其赋值,这也就是解构(Destructureing)。

const result = [1, "success"];

//const [code, message, data] = result;
//console.log(code, message, data);//1 "success" undefined

//const [code, ,data] = result;
//console.log(code, data);//1 undefined

//const [code, ...args] = result;
//console.log(code, args);//1 ["success"]

//const [code=0, message="", data={}] = result;
//console.log(code, message, data);//1 "success" {}

例如:交换变量值

let x = 10, y = 20;
[x, y] = [y, x];
console.log(x, y);//20 10
Array.protype.includes() 包含

ES5数组提供Array.indexOf()方法用来查找某个元素在数组中的索引位置,若不存在则返回-1。

indexOf方法判断数组中是否包含元素是存在两点不足之处

返回-1和元素的索引位置表示是否包含不够语义化
不能判断是否含有NaN元素

const arr = ["alice", "card", 1, 2, NaN];
console.log("%s", arr.indexOf("alice"));//0
console.log("%s", arr.indexOf(0));//-1
console.log("%s", arr.indexOf(NaN));//-1

ES6提供Array.includes()方法返回布尔值可用于判断数组中是否包含指定元素,对NaN同样有效,其不足之处就是无法进行定位。

includes方法第1个参数表示查询的目标字符串
includes方法第2个参数表示判断的起始索引位置
includes方法第2个参数可以是负数,表示从右倒数第几个,但不会改变搜索方向,搜索方向仍然会从左至右。

const arr = ["alice", "card", 1, 2, NaN, "alice"];
console.log("%s", arr.indexOf("alice"));//0
console.log("%s", arr.indexOf(0));//-1
console.log("%s", arr.indexOf(NaN));//-1

console.log("%s", arr.includes("junchow"));//false
console.log("%s", arr.includes("alice"));//true
console.log("%s", arr.includes("alice", 4));//true
console.log("%s", arr.includes("alice", -5));//true

ES6中新增了四个函数,分别是映射map、汇总reduce、过滤filter、循环forEach

Array.map 映射

// 将数组中所有元素增加2倍

let arr = [11, 23, 43, 90];
let result = arr.map((x)=>x*2);
console.log(result);//[22, 46, 86, 180]
let arr = [89, 23, 31, 78];
let result = arr.map((x)=>{
    if(x>=90){
        return "A"
    }else if(x>=80){
        return "B";
    }else if(x>=60){
        return "C";
    }else{
        return "D";
    }
});
console.log(result);//["B", "D", "D", "C"]
Array.prototype.reduce() 汇总

reduce方法接受一个函数作为累加器并指定初始值(可选),数组中的每个值(从左至右)开始缩减,最终计算为一个值。

array.reduce(callback, [initialValue])
reduce方法的累加器函数callback接受四个参数

function callback(preValue, curValue, index, array)
preValue初始值或上一次回调函数的返回值
curValue当前元素值
index当前索引
array调用reduce方法的数组
例如:数组求和与平均数

let arr = [100, 200, 300];

//求和 tmp为中间结果 item为每次迭代的对象 index为索引
let total = arr.reduce((tmp, item)=>{
    //100 200 1
    //300 300 2
    //console.log(tmp, item, index);
    return tmp + item;
});
//console.log(total);//600

例如:求平均值

let arr = [100, 200, 300];
//求平均数
let average = arr.reduce((tmp, item, index, arr)=>{
    if(arr.length === index+1){
        return (tmp+item)/index;
    }else{
        return tmp + item;
    }

});
console.log(average);//300

例如:求阶乘

let arr = [100, 200, 300];
//求阶乘
let result = arr.reduce((preval, curval)=>{
    return preval * curval;
});
console.log(result);//6000000

例如:二维数组转化为一维数组

let arr = [
    [1, 3, 5],
    [2, 4, 6],
    [10, 20, 30]
];
let result = arr.reduce((retval, current, index, arr)=>{
    return retval.concat(current);
});
console.log(result);//[1, 3, 5, 2, 4, 6, 10, 20, 30]

例如:计算数组中元素出现的次数

let arr = ["alice", "bob", "carl", "bob", "carl", "bob"];

let result = arr.reduce((retval, current, index, arr)=>{
   if(current in retval){
       retval[current]++;
   } else{
       retval[current] = 1;
   }
   return retval;
},{});

console.log(result);//{alice: 1, bob: 3, carl: 2}

例如:计算数组中某个元素出现的次数

let arr = ["alice", "bob", "carl", "bob", "carl", "bob"];

let times = (arr, val)=>arr.reduce((retval, current)=>{
    return current===val ? retval+1 : retval+0;
},0);

console.log(times(arr, "bob"));//3

例如:获取数组对象中某个指定字段的值

let arr = [
    {id:11, name:"alpha", status:1},
    {id:20, name:"alice", status:0},
    {id:34, name:"bob", status:1}
];
//获取数组中所有的id
let getField = (arr, field) => arr.reduce((preval, curval)=>{
    preval.push(curval[field]);
    return preval;
}, []);
console.log(getField(arr, "id"));//[11, 20, 34]

例如:数组去重

let arr = ["alice", "bob", "carl", "bob", "carl", "bob"];

let dedupe = (arr)=>arr.sort().reduce((retval, current)=>{
    if(retval.length===0 || retval[retval.length-1]!==current){
        retval.push(current);
    }
    return retval;
},[]);

console.log(dedupe(arr));// ["alice", "bob", "carl"]

例如:求某用户的单科成绩根据权重比例汇总后的权重值

//单科成绩
let arr = [
    {subject:"math", score:89},
    {subject:"chinese", score:89},
    {subject:"english", score:89},
];
//权重比例
let percent = {math:0.5, chinese:0.3, english:0.2};
//求权重值
let result = arr.reduce((preval, curval)=>{
   return preval + curval.score *percent[curval.subject];
}, 0);
console.log(result);//89

你可能感兴趣的:(ES6基础(一))