定义变量
在ES6之前,通过var
关键字来定义变量,ES6中引入了另外两个声明变量的关键字:const
和 let
。
const {#const}
被 const 声明的变量不能被重新赋值或重新声明。换句话说,它将不能再被改变。你可以使用它创建不可变数据结构,一旦数据结构被定义好,你就不能再改变它了。
// 这种写法是不可行的
const helloWorld = 'hello,world';
helloWorld = 'Bye Bye';
使用 const
声明的变量不能被改变,但是如果这个变量是数组或者对象的话,它里面持有的内容可以被更新。
// 这种写法是可行的
const helloWorld = {
text: 'hello,world'
};
helloWorld.text = 'Bye Bye';
阅读更多关于 ES6 const 的内容
let {#let}
被关键字 let 声明的变量可以被改变。
// 这种写法是可行的
let helloWorld = 'hello,world';
helloWorld = 'Bye Bye';
当一个变量需要被重新赋值的话,应该使用 let
去声明它。
阅读更多关于 ES6 let 的内容
解构赋值 {#jie_gou_fu_zhi}
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
数组解构 {#shu_zu_jie_gou}
// ES5
var a = 1;
var b = 2;
var c = 3;
`// ES6
let [a, b, c] = [1, 2, 3];
`
对象解构 {#dui_xiang_jie_gou}
const user = {
firstname: 'Robin',
lastname: 'Wieruch',
};
// ES5
var firstname = user.firstname;
var lastname = user.lastname;
console.log(firstname + ' ' + lastname);
// output: Robin Wieruch
`// ES6
const { firstname, lastname } = user;
console.log(firstname + ' ' + lastname);
// output: Robin Wieruch
`
注:对象解构要求属性名和变量名必须一致。
如果属性名与前面的变量名冲突,可以重新改名,例如:
const uname = '张三'
const {uname:username,age} = {uname:'李四',age:18}
console.log(username + ' ' + age);
// output: 李四 18
数组对象解构 {#shu_zu_dui_xiang_jie_gou}
const pig = [
{
uname:'佩奇',
age:6
}
]
const [{uname,age}] = pig
console.log(uname + ' ' + age);
// output: 佩奇 6
多级对象解构 {#duo_ji_dui_xiang_jie_gou}
const pig = {
name:'佩奇',
family:{
mother:'猪妈妈',
father:'猪爸爸',
sister:'乔治'
},
age:6
}
const {name,family:{mother,father,sister}} = pig
console.log(name + ' ' + mother + ' ' + father + ' ' + sister);
// output: 佩奇 猪妈妈 猪爸爸 乔治
作用域和作用域链 {#zuo_yong_yu_he_zuo_yong_yu_lian}
局部作用域 {#ju_bu_zuo_yong_yu}
函数作用域 {#han_shu_zuo_yong_yu}
在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。
function getSum() {
const num = 10
}
console.log(num) //此处报错:Uncaught ReferenceError: num is not defined
块作用域 {#kuai_zuo_yong_yu}
使用{}
包裹的代码称为代码块,代码块内部声明的变量外部将【有可能】无法被访问。
1.let
声明的变量会产生块作用域,var
不会产生块作用域
2.const
声明的常量也会产生快作用域
3.不同代码块之间的变量无法互相访问
4.推荐使用let或const
for (let i = 1; i<=3; i++) {
//块作用域
console.log(i)
}
console.log(i) //此处报错:Uncaught ReferenceError: i is not defined
for (var i = 1; i<=3; i++) {
//块作用域
console.log(i)
}
console.log(i) //输出4
全局作用域 {#quan_ju_zuo_yong_yu}
<script>
标签和.js
文件的【最外层】就是所谓的全局作用域,在此声明的变量在函数内部也可以被访问。
全局作用域中声明的变量,任何其它作用域都可以被访问。
<script>
//全局作用域下声明了num变量
const num = 10
function fn() {
cosole.log(num) //输出10
}
</script>
注意:
1.为window对象动态添加的属性默认也是全局的,不推荐这样使用
2.函数中未使用任何关键字声明的变量也是全局变量,不推荐这样使用
3.尽可能少的声明全局变量,防止全局变量被污染
作用域链 {#zuo_yong_yu_lian}
作用域链本质上是底层的变量查找机制 。
在函数被执行时,会优先查找当前函数作用域 中查找变量
如果当前作用域查找不到则会逐级查找父级作用域直到全局作用域
闭包 {#bi_bao}
概念 {#gai_nian}
一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
简单理解:闭包=内层函数+外层函数的变量
作用 {#zuo_yong}
封闭数据,提供操作,外部也可以访问函数内部的变量
可能引起的问题 {#ke_neng_yin_qi_de_wen_ti}
内存泄漏
闭包的简单写法 {#bi_bao_de_jian_dan_xie_fa}
function outer() {
const a = 1
function f() {
console.log(a)
}
f()
}
outer()
通过打断点观察:
闭包的常见写法 {#bi_bao_de_chang_jian_xie_fa}
function outer() {
let i = 10
return function() {
console.log(i)
}
}
const fun = outer()
fun()
函数参数 {#han_shu_can_shu}
动态参数 {#dong_tai_can_shu}
arguments
是函数内部内置的【伪数组】变量,它包含了调用函数时传入的所有实参。
function getSum() {
let sum = 0;
for(let i = 0;i<arguments.length;i++){
sum += arguments[i]
}
console.log(sum)
}
getSum(1,2)
getSum(1,2,3)
getSum(1,2,3,4,6,6)
剩余参数 {#sheng_yu_can_shu}
1....
是语法符号,置于最末函数形参之前,用于获取多余的实参
2.借助...
获取的剩余实参,是个【真数组】
3.只存在于函数里
function getSum(...arr) {
let sum = 0;
for(let i = 0;i<arr.length;i++){
sum += arr[i]
}
console.log(sum)
}
getSum(1,2)
getSum(1,2,3)
getSum(1,2,3,4,6,6)
实际开发中,提倡多使用剩余参数。
展开运算符 {#zhan_kai_yun_suan_fu}
也叫展开语法,三点运算符。与函数剩余参数的区别是,剩余参数在函数参数中使用。而展开运算符适用于数组、对象。
典型使用场景 {#dian_xing_shi_yong_chang_jing}
求数组各元素的和,参数固定 {#qiu_shu_zu_ge_yuan_su_de_he_can_shu_gu_ding}
function sum(a, b, c) {
return a + b + c
}
let a = [1, 2, 3]
let result = sum(...a) //等同于sum(a[0]+a[1]+a[2])
console.log(result) //6
求数组最大值 {#qiu_shu_zu_zui_da_zhi}
# 老方法
console.log(Math.max(1,2,3)) //3
# 通过展开运算符
let arr = [1,2,3]
console.log(Math.max(...arr)) //3
合并数组 {#he_bing_shu_zu}
const arr1 = [1,2,3]
const arr2 = [4,5,6]
const arr = [...arr1,...arr2]
console.log(arr); //[1, 2, 3, 4, 5, 6]
复制对象 {#fu_zhi_dui_xiang}
let obj = {name: '周杰伦', age: 30, songs: {name: 'Mojito'}}
let objClone = {...obj}
console.log(objClone)
console.log(objClone === obj) //false,浅拷贝
objClone.age = 20
objClone.songs.name = '听妈妈的话'
console.log(objClone)
console.log(obj)
箭头函数 {#jian_tou_han_shu}
JavaScript ES6 引入了箭头函数。箭头函数表达式比普通的函数表达式更加简洁。箭头函数更适用于那些本来需要匿名函数的地方。
// function expression
function () { ... }
// arrow function expression
() => { ... }
基本语法 {#ji_ben_yu_fa}
函数表达式(老写法) {#han_shu_biao_da_shi_lao_xie_fa}
const fn = function () {
console.log(123)
}
fn()
箭头函数 {#jian_tou_han_shu1}
const fn = () => {
console.log(123)
}
fn()
函数的形参只有一个时 {#han_shu_de_xing_can_zhi_you_yi_ge_shi}
如果箭头函数只有一个参数时,可以移除掉参数的括号,但是如果有多个参数或者没有参数,就必须保留这个括号。
const fn = (x) => {
console.log(x)
}
fn(1)
等同于:
const fn = x => {
console.log(x)
}
fn(1)
简洁函数体 {#jian_jie_han_shu_ti}
函数体只有一行代码时,可以省略大括号{}
。
const fn = (x) => {
console.log(x)
}
fn(1)
等同于:
const fn = x =>console.log(x)
fn(1)
函数体只有一行代码时(有返回值时),可以省略大括号{}
及return
。
const fn = function (x) {
return x + 1
}
const sum = fn(1)
console.log(sum) //2
等同于:
const fn = x => x + 1
const sum = fn(1)
console.log(sum) //2
可以直接返回一个对象 {#ke_yi_zhi_jie_fan_hui_yi_ge_dui_xiang}
const fn = function (uname) {
return {uname:uname}
}
const obj = fn('周杰伦')
console.log(obj) //{uname: '周杰伦'}
等同于:
const fn = uname => ({uname:uname}) //对象外面用小括号括起来
const obj = fn('周杰伦')
console.log(obj) //{uname: '周杰伦'}
进一步简化:
const fn = uname => ({uname})
const obj = fn('周杰伦')
console.log(obj) //{uname: '周杰伦'}
箭头函数的this {#jian_tou_han_shu_dethis}
普通函数的this指向函数的调用者
箭头函数没有自己的this指向,它的this指向上一级作用域的this
const btn = document.querySelector('.btn')
//箭头函数 此时this指向了window
btn.addEventListener('click',() =\> {
console.log(this)
})
`//普通函数 此时this指向了DOM对象
btn.addEventListener('click', function () {
console.log(this)
})
`
下面举例比较说明ES5和ES6。
例如循环一个数组,ES5的写法如下:
<div id="root"></div>
<script>
var list = [
{
title:'MySQL常用语句',
url:'http://www.884358.com/mysql-sqls/',
},
{
title:'JavaScript ES6 语法学习',
url:'http://www.884358.com/javascript-es6/',
}
];
`var html = '<ul>';
list.map(function(item){
html += '<li><a href="'+item.url+'">'+item.title+'</a></li>';
});
html += '<ul>';
document.getElementById('root').innerHTML = html;
`
ES6的写法如下:
<div id="root"></div>
<script>
const list = [
{
title:'MySQL常用语句',
url:'http://www.884358.com/mysql-sqls/',
},
{
title:'JavaScript ES6 语法学习',
url:'http://www.884358.com/javascript-es6/',
}
];
`let html = '<ul>';
list.map(item => {
html += '<li><a href="'+item.url+'">'+item.title+'</a></li>';
});
html += '<ul>';
document.getElementById('root').innerHTML = html;
</script>
`
箭头函数的this指向 {#jian_tou_han_shu_dethis_zhi_xiang}
一个普通的函数表达式总会定义它自己的this对象。但是箭头函数表达式仍然会使用包含它的语境下的this对象。箭头函数中的this继承自外围父作用域。
以下示例中,两个按钮执行点击事件后,打印的this不一样,btn1打印的this是其本身,而btn2打印的this是window
<input type="button" value="按钮1" id="btn1">
<input type="button" value="按钮2" id="btn2">
<script>
let btn1 = document.getElementById('btn1');
let btn2 = document.getElementById('btn2');
btn1.onclick = function(){
console.log(this);
}
btn2.onclick = () => {
console.log(this);
}
</script>
阅读更多关于箭头函数的内容
深入对象 {#shen_ru_dui_xiang}
创建对象的三种方式 {#chuang_jian_dui_xiang_de_san_zhong_fang_shi}
利用对象字面量创建对象 {#li_yong_dui_xiang_zi_mian_liang_chuang_jian_dui_xiang}
在 ES6
中,可以通过简写属性更加简洁地初始化对象。当对象中的属性名与变量名相同时,可以省略变量名:
const name = 'Robin';
const user = {
name: name,
};
以上代码可以简写为:
const name = 'Robin';
const user = {
name,
};
另一个简洁的辅助办法是简写方法名。在 ES6 中,你能更简洁地初始化一个对象的方法。
// ES5
var userService = {
getUserName: function (user) {
return user.firstname + ' ' + user.lastname;
},
};
// ES6
const userService = {
getUserName(user) {
return user.firstname + ' ' + user.lastname;
},
};
最后值得一提的是可以在 ES6 中使用计算属性名。当为一个对象动态地根据 key 分配值时便会涉及到。
// ES5
var user = {
name: 'Robin',
};
// ES6
const key = 'name';
const user = {
[key]: 'Robin',
};
利用new Object创建对象 {#li_yongnew_Object_chuang_jian_dui_xiang}
const obj = new Object({ name: '佩奇' })
console.log(obj) // {name: '佩奇'}
通过构造函数创建对象 {#tong_guo_gou_zao_han_shu_chuang_jian_dui_xiang}
构造函数 {#gou_zao_han_shu}
构造函数:是一种特殊的函数,主要用来初始化对象。通过构造函数来快速创建多个类似的对象。
function Pig(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
}
//创建佩奇对象
const Peppa = new Pig('佩奇',6,'女')
//双肩乔治对象
const George = new Pig('乔治',3,'男')
原型 {#yuan_xing}
原型对象 {#yuan_xing_dui_xiang}
构造函数通过原型分配的函数是所有对象所共享的 。
JavaScript规定,每一个构造函数都有一个prototype
属性,指向另一个对象,所以我们也称为原型对象
这个对象可以挂载函数,对象实例化不会多次创建原型上的函数,节约内存
可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法
构造函数和原型对象中的this都指向实例化的对象。
DEMO1:没有使用原型
没有使用原型时,在创建对象实例时,会多次创建构造函数中的sing方法,通过打印singer1.sing === singer2.sing
结果为false
可以知道创建了多次,因为这两个方法指向的内存地址不相等。造成了内存浪费。如果sing方法对于所有对象实例来说,都是一样的功能,那么可以建立在Star的原型链上,这样就可以共享,避免多次创建而浪费内存。
function Star(name, age) {
this.name = name;
this.age = age;
this.sing = function () {
console.log("唱歌");
};
}
const singer1 = new Star("周杰伦", 30);
const singer2 = new Star("蔡依林", 28);
console.log(singer1.sing === singer2.sing); //false
DEMO2:使用原型
function Star(name, age) {
this.name = name;
this.age = age;
}
Star.prototype.sing = function () {
console.log(this.name + "唱歌");
};
const singer1 = new Star("周杰伦", 30);
const singer2 = new Star("蔡依林", 28);
console.log(singer1.sing === singer2.sing); //true
singer1.sing(); //周杰伦唱歌
singer2.sing(); //蔡依林唱歌
原型应用实例 {#yuan_xing_ying_yong_shi_li}
给数组增加求最大值的方法 {#gei_shu_zu_zeng_jia_qiu_zui_da_zhi_de_fang_fa}
Array.prototype.max = function () {
return Math.max(...this);
};
console.log([24, 52, 12].max()); //52
给数组增加求和方法 {#gei_shu_zu_zeng_jia_qiu_he_fang_fa}
Array.prototype.sum = function () {
return this.reduce((prev, current) => prev + current);
};
console.log([1,2,3].sum()); //6
对象原型 {#dui_xiang_yuan_xing}
对象都会有一个属性__proto__
指向构造函数的prototype原型对象,之所以对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有proto 原型的存在。
__proto__
是js非标准属性
[[prototype]]
和__proto__
意义相同
function Star() {}
const s = new Star();
//对象原型__proto__指向该构造函数的原型对象
console.log(s.__proto__ === Star.prototype); //true
高阶函数与柯里化 {#gao_jie_han_shu_yu_ke_li_hua}
高阶函数 {#gao_jie_han_shu}
高阶函数满足下面的条件之一:
函数作为参数被传递或者
函数可以作为返回值被返回
let addFun = (x,y,f) => f(x) + f(y)
console.log(addFun(-1,5,Math.abs))
//结果为:6
柯里化 {#ke_li_hua}
把接受多个参数的函数变换成接受一个单一参数的函数,并且返回(接受余下参数而且返回结果的)新函数的技术。
例如要求两个数字的和,我们写了一个常规的函数:
let addFun = (a,b) => a + b
console.log(addFun(1,2))
以上addFun
函数需要传入两个参数。
改为传一个参数:
let addFun = a => b => a + b
console.log(addFun(1)(2))
以上例子就是柯里化写法,将参数变换成一个,延迟函数参数的传入。
柯里化特点 {#ke_li_hua_te_dian}
延迟参数传递,参数复用
代码短小,优雅,函数化,有点不好理解
扩展操作符(展开语法) {#kuo_zhan_cao_zuo_fu_zhan_kai_yu_fa}
展开语法(Spread syntax), 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。(注: 字面量一般指 [1, 2, 3] 或者 {name: "mdn"} 这种简洁的构造方式)
在函数调用时使用展开语法 {#zai_han_shu_diao_yong_shi_shi_yong_zhan_kai_yu_fa}
function myFunction(x, y, z) {
console.log(x+y+z);
}
var args = [0, 1, 2];
myFunction(...args); //3
构造字面量数组时使用展开语法 {#gou_zao_zi_mian_liang_shu_zu_shi_shi_yong_zhan_kai_yu_fa}
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];
console.log(arr3); //[0, 1, 2, 3, 4, 5]
构造字面量对象时使用展开语法 {#gou_zao_zi_mian_liang_dui_xiang_shi_shi_yong_zhan_kai_yu_fa}
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }
`var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }
`
更多关于展开语法的内容
立即执行函数 {#li_ji_zhi_xing_han_shu}
概念 {#gai_nian1}
声明一个函数,并马上调用这个匿名函数就叫做立即执行函数;也可以说立即执行函数是一种语法,让你的函数在定义以后立即执行;
立即执行函数的创建步骤,看下图:
写法 {#xie_fa}
//写法一:
(function(){
//code
}())
`//写法二:
(function (){
//code
})()
`
作用 {#zuo_yong1}
-
不必为函数命名,避免了污染全局变量
-
立即执行函数内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量
-
封装变量
立即执行函数的参数 {#li_ji_zhi_xing_han_shu_de_can_shu}
(function(j){
//代码中可以使用j
})(i)
如果立即执行函数中需要全局变量,全局变量会被作为一个参数传递给立即执行函数(上例中的i就是一个全局变量,i代表的是实参,j是i在立即执行函数中的形参)。
更多关于立即执行函数:https://www.jianshu.com/p/b10b6e93ddec
深浅拷贝 {#shen_qian_kao_bei}
浅拷贝和深拷贝针对的是引用类型。
直接赋值 {#zhi_jie_fu_zhi}
对于对象来说,直接赋值是复制的地址。复制的对象改变其内容时,原对象的值也被修改。
const obj1 = {
uname: "张三",
age: 18,
}
const obj2 = obj1
obj2.age = 20
console.log(obj2) //{uname: '张三', age: 20}
console.log(obj1) //{uname: '张三', age: 20}
浅拷贝 {#qian_kao_bei}
浅拷贝
拷贝的是地址。拷贝对象后,里面的属性值是简单数据类型则直接拷贝值(见DEMO1和DEMO2),如果属性值是引用数据类型则拷贝的是地址(见DEMO3)。
浅拷贝示例 {#qian_kao_bei_shi_li}
浅拷贝DEMO1:
const obj1 = {
uname: "张三",
age: 18,
}
const obj2 = { ...obj1 }
obj2.age = 20
console.log(obj2) //{uname: '张三', age: 20}
console.log(obj1) //{uname: '张三', age: 18}
浅拷贝DEMO2:
const obj1 = {
uname: "张三",
age: 18,
}
const obj2 = {}
Object.assign(obj2, obj1)
obj2.age = 20
console.log(obj2) //{uname: '张三', age: 20}
console.log(obj1) //{uname: '张三', age: 18}
浅拷贝DEMO3:
对象里如果还有对象,那么浅拷贝只拷贝最外面的一层。
const obj1 = {
uname: "张三",
age: 18,
family: {
uname: "李四",
}
}
const obj2 = {}
Object.assign(obj2, obj1)
obj2.age = 20
obj2.family.uname = "王五";
console.log(obj2) //{uname: '张三', age: 20, family: {uname: '王五'}}
console.log(obj1) //{uname: '张三', age: 18, family: {uname: '王五'}}
深拷贝 {#shen_kao_bei}
拷贝的是对象,不是地址。
常用方法:
1.通过递归实现深拷贝
2.lodash/cloneDeep
3.通过JSON.stringify()实现
通过lodash的cloneDeep方法
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
const obj1 = {
uname: "张三",
age: 18,
family: {
uname: "李四"
}
};
const obj2 = _.cloneDeep(obj1)
obj2.family.uname = "王五"
console.log(obj2) //{uname: '张三', age: 20, family: {uname: '王五'}}
console.log(obj1) //{uname: '张三', age: 20, family: {uname: '李四'}}
</script>
通过JSON.stringify()
const obj1 = {
uname: "张三",
age: 18,
family: {
uname: "李四",
},
};
//将obj1转为json字符串(简单数据类型)
const jsonStr = JSON.stringify(obj1);
//将json字符串转为json对象
const obj2 = JSON.parse(jsonStr);
obj2.family.uname = "王五";
console.log(obj2);
console.log(obj1);
Promise 对象 {#Promise_dui_xiang}
概念 {#gai_nian2}
Promise 对象:代表了未来某个时间将要发生的事件(通常是一个异步操作)
有了promise对象,可以将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(俗称"回调地狱")
ES6的Promise是一个构造函数,用来生成promise实例
promise对象的3个状态 {#promise_dui_xiang_de3ge_zhuang_tai}
-
pending:初始化状态
-
fullfilled:成功状态
-
rejected:失败状态
基本用法 {#ji_ben_yong_fa}
下面代码创造了一个promise实例。
let promise = new Promise((resolve, reject)=> {
// ... some code
`if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
`
resolve
函数的作用是,将promise对象的状态从"未完成"变为"成功"(即从 pending
变为 fullfilled
),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject
函数的作用是,将promise对象的状态从"未完成"变为"失败"(即从 pending
变为 rejected
),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise实例生成以后,可以用then
方法分别指定fullfilled
状态和rejected
状态的回调函数。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
DEMO:
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, '执行成功');
// setTimeout(reject, ms, '执行失败');
});
}
`timeout(0).then((msg) => {
//调用resolve时执行
console.log(msg);
}).catch((msg)=>{
//调用reject时执行
console.log(msg);
})
`
async 函数 {#async_han_shu}
ES2017 标准引入了 async
函数,使得异步操作变得更加方便。真正意义上解决异步回调的问题,同步流程表达异步操作
语法:
async function foo(){
await 异步操作;
await 异步操作;
}
特点:
1、返回的总是Promise对象,可以用then方法进行下一步操作
2、语义上更为明确,使用简单
DEMO:
写法一:
function promiseFunc()
{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('2秒后执行')
let data = '异步执行结果'
resolve(data)
},2000)
});
}
`(async ()=>{
console.log('开始执行')
let result = await promiseFunc()
console.log('result:',result)
console.log('执行结束')
})()
`
写法二:
let promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('2秒后执行')
let data = '异步执行结果'
resolve(data)
},2000)
});
`(async ()=>{
console.log('开始执行')
let result = await promise
console.log('result:',result)
console.log('执行结束')
})()
`
当程序执行到await
时会阻塞,等待后面函数执行结果,这个函数返回的是Promise对象,Promise对象有三种状态,只有当状态变为成功或失败这两种状态中的一个时,程序才会执行下一步。
Array {#Array}
| 方法 | 作用 | 说明 | |---------|------|--------------------------------| | forEach | 遍历数组 | 不返回数组,经常用于查找遍历数组元素 | | filter | 过滤数组 | 返回新数组,返回的是筛选满足条件的数组元素 | | map | 迭代数组 | 返回新数组,返回的是处理之后的数组元素,想要使用返回的新数组 | | reduce | 累计器 | 返回累计处理的结果,经常用于求和等 |
forEach {#forEach}
数组的forEach方法用于调用数组的每个元素,并将元素传递给回调函数
主要使用场景:遍历数组的每个元素
const arr = ['张三','李四','王五']
arr.forEach(function (item,index) {
console.log(item) //数组元素 张三 李四 王五
console.log(index) //索引号 0 1 2
})
filter {#filter}
filter()
方法创建给定数组一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。
const filtered = [12, 5, 8, 130, 44].filter((item) => item > 10)
console.log(filtered) //[12, 130, 44]
map {#map}
map()
方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。
const result = [1, 4, 9, 16].map(x => x * 2)
console.log(result) //[2, 8, 18, 32]
reduce {#reduce}
reduce返回累计出来的结果,经常用于求和等。reduce方法最终返回的是最后一次调用累加器的结果。
基本语法:
arr.reduce(function(上一次值,当前值){},初始值)
const arr = [1, 5, 8]
const total = arr.reduce(function (prev, current) {
return prev + current
});
console.log(total) //14
find {#find}
find()
方法返回数组中满足提供的测试函数的第一个 元素的值。否则返回undefined
。
const arr = ["red", "blue", "green"]
const result = arr.find((item) => item === "blue")
console.log(result) //blue
every {#every}
every()
方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值。
const result1 = [12, 5, 8, 130, 44].every((item) => item >= 10)
const result2 = [12, 54, 18, 130, 44].every((item) => item >= 10)
console.log(result1) //false
console.log(result2) //true
some {#some}
some()
方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。
//检测在数组中是否有元素大于 10。
[2, 5, 8, 1, 4].some(x => x > 10); // false
[12, 5, 8, 1, 4].some(x => x > 10); // true
Array.from {#Arrayfrom}
Array.from()
静态方法从可迭代或类数组对象创建一个新的浅拷贝的数组实例。
简而言之就是把伪数组转为真数组
// 根据 DOM 元素的属性创建一个数组
const images = document.querySelectorAll("img")
const sources = Array.from(images, (image) => image.src)
const insecureSources = sources.filter((link) => link.startsWith("http://"))
Object {#Object}
Object.keys {#Objectkeys}
Object.keys 静态方法获取对象中所有属性(键)
const obj = { name: '佩奇', age: 6 }
const arr = Object.keys(obj)
console.log(arr) // ['name', 'age']
Object.values {#Objectvalues}
Object.values 静态方法获取对象中所有属性值(键值)
const obj = { name: '佩奇', age: 6 }
const arr = Object.values(obj)
console.log(arr) // ['佩奇', 6]
Object.assign {#Objectassign}
用于对象拷贝。
使用场景:给对象添加属性
//拷贝对象 把obj拷贝给objClone
const obj = { name: '佩奇', age: 6 }
const objClone = {}
Object.assign(objClone, obj)
console.log(objClone) //{name: '佩奇', age: 6}
//给对象obj添加genger属性
Object.assign(obj,{ genger: '女'})
console.log(obj) //{name: '佩奇', age: 6, genger: '女'} //{name: '佩奇', age: 6, genger: '女'}
//合并对象
const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
const objMerge = Object.assign(o1, o2, o3);
console.log(objMerge); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
`//合并具有相同属性的对象
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
const objMerge2 = Object.assign({}, o1, o2, o3);
console.log(objMerge2); // { a: 1, b: 2, c: 3 }
`
String {#String}
在JavaScript中的字符串、数值、布尔具有对象的使用特征,如具有属性和方法
//统计字符串长度
const str = 'hello world!'
console.log(str.length)
`//保留
const price = 12.345
price.toFixed(2)
`
之所以具有对象特征的原因是字符串、数字、布尔类型数据是JavaScript底层使用Object构造函数"包装"起来的,被称为包装类型。
split {#split}
split()
方法用于将字符串按照指定的模式将字符串分割为数组。
const str = "red,blue,yellow"
const arr = str.split(",")
console.log(arr) //['red', 'blue', 'yellow']
substring {#substring}
substring()
方法返回该字符串从起始索引到结束索引(不包括)的部分,如果未提供结束索引,则返回到字符串末尾的部分。
const str = "hello";
const newstr1 = str.substring(2);
const newstr2 = str.substring(2,4);
console.log(newstr1); //llo
console.log(newstr2); //ll
startswith {#startswith}
startsWith()
方法用来判断当前字符串是否以另外一个给定的子字符串开头,并根据判断结果返回 true 或 false。
const str = "hello world!";
const result = str.startsWith("hello");
console.log(result); //true
includes {#includes}
includes()
方法执行区分大小写的搜索,以确定是否可以在一个字符串中找到另一个字符串,并根据情况返回 true 或 false。
"Blue Whale".includes("blue"); // false
"Blue Whale".toLowerCase().includes("blue"); // true
Number {#Number}
Number是内置的构造函数,用于创建数值
toFixed {#toFixed}
toFixed()
方法返回一个表示 numObj 的字符串,但不使用指数计数法,并且小数点后有精确到 digits 位的数字。如果需要截断,则将数字四舍五入;如果小数位数不足,则小数部分用零填充,以使其具有指定长度。
const price = 12.345
console.log(price.toFixed(2)) //12.35
更多关于ES6的资料:
《阮一峰:ECMAScript 6 入门》