silencehvk / silencehvk.github.io Goto Github PK
View Code? Open in Web Editor NEW:books: :octocat: 个人博客,博客地址:https://blog.hvkcoder.me
Home Page: https://silencehvk-github-io.vercel.app
License: MIT License
:books: :octocat: 个人博客,博客地址:https://blog.hvkcoder.me
Home Page: https://silencehvk-github-io.vercel.app
License: MIT License
ES6新增了 let 命令,用来声明变量。它的用法类似于 var,但是所声明的变量,只能在 let 命令所在的代码块内有效。
{
var a = 10;
let b = 1;
}
console.log(a);//10
console.log(b);//ReferenceError: b is not defined.
let 不像 var 那样会发生 “变量提升” 现象。所以,变量一定要在声明后使用,否则会报错。
console.log(foo);// undefined
var foo = 2;
console.log(bar);//ReferenceError: bar is not defined
let bar = 2;
ES6 明确规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量从一开始就形成了封闭作用域,这些变量将不受外界影响,凡是在声明前就使用这些变量,就会报错。这种语法我们称为 “暂时性死区(temporal dead zone 简称 TDZ)”
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError: tmp is not defined
let tmp;
}
TDZ 也就意味着 typeof 不再是一个百分百安全的操作。
console.log(typeof testType); //ReferenceError: testType is not defined
let testType;
TDZ 的本质就是:只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
let 不允许在同一个作用域中,重复声明相同的变量
//报错
function func(parm){
let parm = 'Hello';//SyntaxError: Identifier 'parm' has already been declared
};
//不报错
function func2(parm){
{
let parm = 'Hello';//Hello
}
};
为什么需要块级作用域?
ES5 只有全局作用域和函数作用域,没有块级作用域,这样会带来很多不合理的场景
var scop_one = new Date();
function showScopOne(){
console.log(scop_one);
if(false){
var scop_one = 'Hello World';
}
};
showScopOne(); // undefined
上面代码中,执行 showScopOne 函数输出结果为 undefined,原因在于变量提升,导致内层的 scop_one 变量覆盖了外层的 scop_one 变量。
var scop_two = 'Hello';
for(var i = 0; i< scop_two.length; i++);
console.log(i); //5
变量 i 只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
ES6 let 命令为 javascript 新增了块级作用域
//IIFE 写法
(function(){
var temp = ....
})();
//块级作用域写法
{
let temp = ....
};
'use strict';
if(true){
function f(){};
};
function foo() { console.log('I am outside!'); }
(function(){
if(false){
function foo(){console.log('I am inside!'); };
}
foo(); //I am outside!
});
const 命令声明了一个只读的常量,一旦声明,常量的值不能改变。这也就意味着,const 一旦声明,就必须立即初始化赋值。
const PI = 3.1415;
PI = 3; //TypeError: Assignment to constant variable.
const 的作用域与 let 命令相同,只在声明所在的块级作用域内有效。
{
const SECRET = 'Hello Const';
};
console.log(SECRET); //SECRET is not defined
const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用,同样也不能重复声明。
const 命令声明的对象是可以更改其属性值的。
const USER = {
name:'H_VK'
}
USER.password = '123456';
console.log(USER);// {name: "H_VK", password: "123456"}
这是因为对象是引用类型,const 只针对其引用的内存地址不可更改,而不针对其属性值更改。
let 用来声明块级变量,当一个变量已经用let声明了,当我们再次用let或var进行声明就会报错。块级{}中的let只在快中有效。在es6 中 var,let可以一次性声明多个变量,对象或数组的格式为多个变量赋值。
关于常量的声明const,可以一次性声明多个常量,const声明一个只读的常量。一旦声明,常量的值就不能改变。但对于声明的常量是一个字面量的对象时,是可以修改常量的属性值。
Promise 用于异步计算,可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。
可以在对象之间传递和操作 Promise,帮助我们处理队列。
new Promise(function(resolve,reject){
resolve(); // 数据处理完成
reject(); //数据处理出错
}).then(function(res){
// 成功数据 res
},function(error){
// 处理错误 error
});
一个 Promise 可能有三种状态:
一个 Promise 状态只可能从“等待”转到“完成”或“拒绝”,不能逆向转换,同时“完成”和“拒绝”不能相互转换。
当 Promise 状态发生改变,就会触发 then
函数。
then
函数接受两个参数,第一个参数是成功时的回调,在 Promise 由“等待“状态转换到”完成“状态时调用;第二个参数是失败时回调,在 Promise 由“等待”状态转换为“拒绝”状态时调用。
then
可以接受另加一个 Promise 传入,也接受一个 “类then” 的对象或方法,即 thenable
对象。
同一个 Promise 的 then
可以调用多次,并且回调的执行顺序跟它们被定义的顺序一致。
Promise.then()
接受两个函数作为参数,分别代表 fulfilled
状态下的响应函数 和 rejected
状态下的响应函数。Promise.then()
返回一个新的 Promise
实例,所以支持链式调用。Promise
状态发生改变时,Promise.then()
会根据其返回的最终状态,调用相应的响应函数。Promise.then()
中可以返回一个新的 Promise
或其他值。Promise
时,那么下一级 Promise.then()
会在新的 Promise
状态改变后执行。Promise.then()
会立即执行。在嵌套 Promise.then()
时 ,由于 Promise.then()
返回的还是一个 Promise
,所以下一级的 Promise.then()
会等到里面的 Promise.then()
执行完后再执行。
Promise.catch()
是 Promise.then(resolve,reject)
中 reject
的别名,用于指定发生错误的回调函数。用法如下:
new Promise((resolve,reject)=>{
}).then(res=>{
}).catch(error=>{
});
Promise.catch()
也会返回一个 Promise
,并且其状态也为 pending
。
reject
的作用等同于抛出一个异常。如果 Promise
状态已经变成 resolved
,再抛出错误是无效的
Promise.finally()
是用于指定无论 Promise
最终状态如何,都会执行的操作,是在 ES2018 中引入的。用法如下:
new Promise((resolve,reject)=>{
}).then(res=>{
}).catch(error=>{
}).finally(()=>{
});
Promise.finally()
方法的回调函数不接受任何参数,因此Promise.finally()
方法里面的操作,与Promise
的状态无关。
Promise.finally()
本质上是 Promise.then()
的特例,Promise.finally()
方法总是会返回原来的值。
Promise.all
方法用于将多个 Promise
实例,包装成一个新的 Promise
实例。使用方法如下:
new Promise.all([p1,p2,p3]);
Promise.all
的参数可以不是数组,但参数必须具有 Iterator 接口,且返回的每个成员都是 Promise
实例。
Promise.all
的状态由传入的参数决定,分为两种情况:
Promise
状态完成,该 Promise
才算完成,其返回结果为全部值的数组。Promise
则失败,此时第一个被 reject
的实例的返回值。 Promise.race
方法同样是将多个 Promise
实例,包装成一个新的 Promise
实例。使用方法如下:
new Promise.race([p1,p2,p3]);
只要参数中的任何一个状态更改,其返回结果则为率先改变的 Promise
实例。
Promise.resolve
方法可以将现有对象转为 Promise
对象,如下:
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
Promise.resolve
方法的参数分为四种结果:
参数是一个 Promise
实例
Promise.resolve
将不做任何修改,原封不懂的返回。
参数是一个 thenable
对象
thenable
对象指的是具有 then
方法的对象,如下:
const thenable = {
then: function(resolve,reject){
resolve();
}
};
Promise.resolve
会将这个方法转为 Promise
对象然后立即执行 thenable
对象中的 then
方法。
参数不是具有 then
方法的对象,或根本就不是对象
Promise.resolve
会返回一个新的 Promise
对象的实例,其状态为 fulfilled
。
不带有任何参数
Promise.resolve
方法允许调用时不带参数,它回直接返回一个状态为 fulfilled
的 Promise
实例。
Promise.reject
也会返回一个 Promise
实例,状态为 rejected
。
const jsPromise = Promise.reject('Error');
Promise.try
就是模拟 try
代码块。
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为 解构(Destructuring)
var [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
以上代码表示,可以从数组中直接提取值,按照对应的位置,对应变量赋值。只要两边等号的模式相同,左边的变量就会被赋予对应的值,我们称为模式匹配。如果解构不成功,变量的值就等于 undefind
等号左边模式,只要匹配一部分的等号右边的数组。这种情况下,解构依然成功,我们称为不完全解构
var [x, y] = [1, 2, 3];
console.log(x, y); // 1 2
如果等号右边不是数组(或者严格地说,不是可遍历的结构)。这种情况,结构将会报错
var [foo] = 1;
结构赋值不仅适用于 var 命令,也适用于 let 和 const 命令
let [x ,...y] = ['Hello' ,'ES6'];
console.log(x, y); // Hello ['ES6']
const [APPID,SECRET] = ['Destructuring','ESCMAScript6'];
console.log(APPID, SECRET); // Destructuring ESCMAScript6
对于 Set 结构,也可以使用数组解构赋值
let [x, y, z] = new Set(['Hello' , 'ESCMAScript6','World']);
console.log(x, y, z); // Hello ESCMAScript6 World
事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式写解构赋值,如 Generator函数 :
function* fibs(){
let a = 0;
let b = 1;
while(true){
yield a;
[a, b] = [b , a + b];
}
}
var [first, second, third, fourth, fifth, sixth] = fibs();
console.log(sixth); // 5
解构赋值允许指定默认值
var [defaultValue = 10] = [];
ES6 内部使用严格相等运算符( === ),判断一个位置是否有值。如果一个数组成员不严格等于 undefined,默认值是不会生效的
var [defaultValue = 10] = [null];
console.log(defaultValue); // null
如果默认值是一个表达式,那么这个表达式是惰性求值,即只有在用到的时候,才会求值
var f = function(){
return 20;
}
//没有用到 表达式
var [defaultValue3 = f()] =[1];
console.log(defaultValue3); // 1
//用到 表达式
var [defaultValue4 = f()] =[];
console.log(defaultValue4); // 20
默认值可以引用解构赋值的其他变量,但是这个变量必须已经声明
var [defaultValue5 = 1, defaultValue6 = defaultValue5] = [];
console.log(defaultValue5,defaultValue6);// 1 1
解构不仅可以用于数组,还可以用于对象
var {foo , bar} = {foo : 'aaa', bar : 'bbb' };
console.log(foo, bar);// aaa bbb
对象解构与数组解构不同,数值解构是按照数组次序进行取值;对象解构是按照属性名取值,即变量名与属性名相同。
如果变量名与属性名不相同时,必须写成以下方式
var {foo : baz} = { foo :'Hello'};
console.log(baz);// Hello
对象的解构赋值的内部机制,是先找到同名的属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
变量的声明与赋值是一体的。对于let和const来说,变量不能重新声明,所以一旦赋值的变量以前声明过,就会报错。
let foo;
let {foo} = {foo:1}; // SyntaxError: Duplicate declaration "foo"
解构也可以用于嵌套解构的对象
var obj = {
p:[
"Hello",
{ world : "World" }
]
};
var { p :[hello,{world}]} = obj;
console.log(hello,world); // Hello World
这时 p 是模式,不是变量,因此不会被赋值
字符串也可以解构赋值。这是因为此时字符串被转换成了一个类似数组的对象
const [H, E, L, L2, O] = 'hello';
console.log(H,E,L,L2,O);// h e l l o
类似数组的对象都有一个 length 属性,因此还可以对这个属性解构赋值
let { length } = 'hello';
console.log(length); // 5
[x, y] = [y, x];
var example = function(){
return ['hvkcoder', 18, 'coder'];
};
var [name, age, job] = example();
//有次序的值
function func([firstParm,secondParm]){
console.log(firstParm,secondParm); // Hello World
}
func(['Hello','World']);
//无次序的值
function funcNo({userName,passWorld}){
console.log(userName,passWorld); // hvkcoder 1234
}
funcNo({userName:'hvkcoder',passWorld:'1234'});
var jsonData = {
id: 1,
data: [1,2]
};
let { id,data} = jsonData;// 1 [ 1, 2 ]
var map = new Map();
map.set('first','hello');
map.set('second','world');
for(let [key, value] of map){
console.log(key + ':' + value); // first : hello second : world
};
//获取键
for(let [key] of map){};
//获取值
for(let [,value] of map){}
利用var,let结合数组解构,可以一次声明多个变量。特别是json数据的提取和变量的转换上,以及函数的默认参数传递上可以给默认值。解构赋值允许指定默认的值,有效的解决了函数返回多个变量的赋值问题,同时也解决了函数参数默认值的问题。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.