ECMAScript基础
ECMAScript介绍
- 什么是ECMAScript
为了防止各大浏览器厂家“各自为政”而提出的统一的脚本语言设计标准。
- JavaScript与ECMAScript的不同
一个完整的JavaScript实现由三部分组成:文档对象模型(DOM)、浏览器对象模型(BOM)、核心(ECMAScript)。
(1) DOM:把整个网页映射为一个多层节点结构。通过DOM属性图,可以获得控制页面内容和结构的主动权。借助DOM提供的API可以轻松自如地删除、添加、替换或修改任何节点。
(2)BOM:提供与浏览器交互地方法和接口,目前BOM已经正式纳入HTML5标准。
(3)ECMAScript:在设计实现JavaScript脚本语言地语法和基本对象地核心内容时所遵循地标准规范。
let命令
- let命令的作用域仅局限于当前代码块
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>let命令作用域</title>
<script>
{
var name='lb';
let age=25;
}
console.log(name); //输出:lb
console.log(age); //输出:ageis not define
</script>
</head>
<body>
</body>
</html>
- let命令的使用
(1)变量提升。var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。这种现象多少有些奇怪,按照一般地逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let命令改变了语法行为,所声明地变量一定要在声明后使用,否则报错。
//var情况
console.log(foo);//输出undefined
var foo=2;
//let情况
console.log(bar);//报错ReferenceError
let bar=2;
(2)变量不允许重复声明。let命令不允许在相同作用域内,重复声明同一个变量参数。
//报错
function func(){
let a=10;
var a=1;
}
//报错
function func(){
let a=10;
let a=1;
}
声明的参数也不能与形参同名,如果声明的参数是在另外一个作用域下,则是可以进行重复声明的。
function func(arg){
let arg; //报错,两个arg参数在用一个作用域内
}
function func(arg){
{
let arg; //不报错,因为两个arg参数不在用一个作用域中
}
}
(3)for循环中Var变量和let变量的父子作用域的对比。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>for循环中的var与let</title>
<script>
window.onload=function(){
var myVar=document.getElementById('varCount')
var myLet=document.getElementById('letCount')
//输出10个10
for(var i=0;i<10;i++){
setTimeout(function(){
myVar.innerHTML+=i+' ';
})
}
//输出0123456789
for (let j=0;j<10;j++){
setTimeout(function(){
myLet.innerHTML+=j+' ';
})
}
}
</script>
</head>
<body>
<div id="varCount">var变量循环:</div>
<div id="letCount">let计数循环:</div>
</body>
</html>
const命令
用const命令声明一个常量,其值一旦声明就不可以改变。const命令一旦声明就必须初始化,不复制就报错。
const PI=3.14;//正确
PI=3.1415926;//报错,不能改
const foo;//报错,没赋值
const命令与let命令作用域相同。
const命令实际上保证的并不是变量的值不变,而是变量指的内存地址不变。
const obj={};//定义const对象
obj.name='lb';//向对象中输入属性值
obj.age=25;
console.log(obj);//上述代码都没问题,可以对对象进行属性添加操作
obj={};//报错,因为不能将obj指向另外一个对象
下面定义一个常量数组names;数组本身可以写入数据,但是如果将另一个数组赋值该常量数组是不允许的。
const names=[];//定义const数组
names.push('lb');//把lb压入数组
console.log(names.length);//上述代码都没有问题,因为数组是可读写的,可以添加新元素。
names=['jisoo'];//报错,因为不能将另一个数组赋值给names常量数组。
变量的解构赋值
解构数据与构造数据截然相反,不是构造一个新的对象或数组,而是逐个拆分现有的对象或数组来提取所需数据。
数组的解构赋值
ECMAScript语法规范中的数组解构赋值基本是按照等号左边与等号右边的匹配进行的,其语法结构如下。
let [var1,var2,...varN]=array//其中,varN表示一个变量,array表示一个数组
数组解构时数组的元素是按次序排列的,变量的取值由其位置决定。下面说明几种数组解构赋值的基本方式。
(1)模式匹配。这种方式的数组解构是等号两边的模式相同,左边的变量就会被赋予对应的值。
let[a,b,c]=[1,2,3];//解构后:a=1,b=2,c=3
(2)嵌套模式。在数组解构方式中,除了正常的模式匹配,还可以使用嵌套数组进行解构,这种数组解构复制的嵌套方式支持任意深度的嵌套。
let [foo,[[bar],baz]]=[1,[[2],3]];//结构后,foo=1,bar=2,baz=3
(3)不完全解构。当等号左边的模式只匹配等号右边的数组的一部分时,这种情况叫做不完全解构。这种情况下,解构依然可以成功。
let[x,,y] = [1,2,3];//结构后:x=1,y=3
(4)使用省略号解构。在ECMAScript语法中,和可以使用省略号的方式进行相应的匹配操作,但这种结构方式有格式要求,也就是说,带有省略号修饰符的变量必须放到最后,否则是无效的结构方式。
let[head,...tail]=[1,2,3,4];//解构后:head=1,tail=[2,3,4]
如果解构不成功,变量的值就等于undefined。下面实例中变量y属于解构不成功,y的值就等于undefined。
let[x,y] = ['a'];//解构后:x='a',y为undefined
(5)含有默认值的解构。在ECMAScript中,左侧数组中可以是默认值。当右侧数组中是undefined或没有左侧对应的值时,左侧就会用默认值给变量进行赋值。即右侧数组中是undefined或没有左侧对应的值时默认生效,否则默认值不生效,左侧就用右侧数组的值。
let[a=0,b=1,c=2]=[1,undefined];//解构后:a=1,b=1,c=2.b和c使用默认值
(6)字符串解构的处理。在ECMAScript中,右侧还可以是字符串,把字符串的每一个字符解构到相对应等号左边的变量中。
var[a,b,c]='hello';//解构后:a='h',b='e',c='l'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数组的解构赋值</title>
<script>
window.onload=function(){
let[a,b,c]=[1,2,3];
console.log('a='+a);
console.log('b='+b);
console.log('c='+c);
let [foo,[[bar],baz]]=[1,[[2],3]];
console.log('foo='+foo);
console.log('bar='+bar);
console.log('baz='+baz);
let[x,,y] = [1,2,3];
console.log('x='+x);
console.log('y='+y);
let[head,...tail]=[1,2,3,4];
console.log('head='+head);
console.log('tail='+tail);
let[x1,y1] = ['a'];
console.log('x1='+x1);
console.log('y1='+y1);
let[d=0,e=1,f=2]=[1,undefined];
console.log('d='+d);
console.log('e='+e);
console.log('f='+f);
let [g,h,i]='hello';
console.log('g='+g);
console.log('h='+h);
console.log('i='+i);
}
</script>
</head>
<body>
</body>
</html>
对象的解构赋值
ECMAScript中的对象解构赋值同样是按章等号左边与右边的匹配进行的。对象的解构赋值与数组的解构赋值区别是:数组是按照位置次序及逆行匹配的,而对象是按照属性的名称进行匹配的,不一定按照出现的次序。
(1)基本形式。左边变量只用key的形式,其实是key与value相同的简写。
let{foo,bar} ={foo:'aaa',bar:'bbb'};//解构后foo='aaa',bar='bbb'
let{bar,foo} ={foo:'aaa',bar:'bbb'};//解构后foo='aaa',bar='bbb'
let{foo}={bar:'baz'};//解构后foo的值是undefined
(2)左边变量是key:value的形式。
let{foo:baz}={foo:'aaa',bar:'bbb'};//解构后baz的值是'aaa'
let obj={first:'hello',last:'world'};
let {first:f,last:l}=obj;//解构后f='hello',l='world'
(3)解构的正常情况。
let{foo:foo,bar:bar}={foo:'aaa',bar:'bbb'};
可以简化成
let{foo,bar}={foo:'aaa',bar:'bbb'};
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>对象的解构赋值</title>
<script>
window.onload=function(){
let {foo,bar}={foo:'aaa',bar:'bbb'};
console.log('foo='+foo);
console.log('bar='+bar);
let{bar1,foo1}={foo1:'aaa',bar1:'bbb'};
console.log('foo1'+foo1);
console.log('bar1'+bar1);
let{foo2}={bar:'baz'};
console.log('foo2='+foo2);
let{foo3:baz3}={foo3:'aaa',bar:'bbb'};
console.log('baz3='+baz3);
let obj={first:'hello',last:'world'};
let{first:f,last:l}=obj;
console.log('f='+f);
console.log('l='+l);
let{foo4,bar4}={foo4:'aaa',bar4:'bbb'};
console.log('foo4='+foo4);
console.log('bar4='+bar4);
}
</script>
</head>
<body>
</body>
</html>
解构赋值的主要用途
- 从函数返回多个值
函数只能返回一个值,如果需要返回多个值,只能将返回的多个值放在数组或多项中,然后通过数组或对象的解构赋值,可以非常方便的取出这些值。
function example(){
return [1,2,3]; //函数返回一个数组
}
let[a,b,c]=example();
console.log(a,b,c)
function example1(){
return{
foo:1,
bar:2
};
}
let{foo,bar}=example1();//对函数的返回值进行解构
console.log(foo,bar) //解构后:foo=1,bar=2
2. 函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来。
定义两个求和函数,一个函数的入口是由三个变量组成的数组;另一个函数的入口是对象,分别利用结构方法给这两个函数传递入口参数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script>
window.onload=function(){
let myDisplay=document.getElementById("display");
myDisplay.innerHTML=arraySum([1,2,3])+"<br>";
myDisplay.innerHTML +=objectSum({z:4,y:5,x:6})
function arraySum([x,y,z]){
return x+y+z
}
function objectSum({x,y,z}){
return x+y+z
}
}
</script>
</head>
<body>
<div id="display"></div>
</body>
</html>
- 提取JSON数据
解构赋值对提取JSON对象中的数据非常有用。
定义一个JSON对象,然后对其进行解构赋值,最后把相关数据显示在浏览器。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON数据解构</title>
<script>
window.onload=function(){
let jsonData={
name:'刘兵',
age:25,
like:['羽毛球','足球']
};
//对JSON数据进行解构
let{name,age,like:mylike}=jsonData;
let myDisplay=document.getElementById("display");
myDisplay.innerHTML="姓名:"+name+"<br>";
myDisplay.innerHTML+="年龄:"+age+"<br>";
myDisplay.innerHTML+="爱好:";
for(var i=0;i<mylike.length;i++){
myDisplay.innerHTML +=mylike[i]+",";
}
}
</script>
</head>
<body>
<div id="display"></div>
</body>
</html>
- 遍历Map结构
任何部署了Iterator接口的对象,都可以使用for...of循环遍历。Map解构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>遍历Map解构</title>
<script>
window.onload=function(){
const map=new Map();
map.set('name','刘兵');
map.set('age',25);
const myDisplay=document.getElementById("display");
for (let [key,value] of map){
myDisplay.innerHTML+="键名:"+key+", ";
myDisplay.innerHTML+="键值:"+value+"<br>";
}
//如果只想获取键名,获知只想获取键值,可以写成下面这样
myDisplay.innerHTML+="<br><br>所有键名包括:<br>";
//获取键名并显示所有键名:
for(let [key] of map){
myDisplay.innerHTML+=key+", "
}
myDisplay.innerHTML +="<br><br>所有键值包括:<br>"
//获取键值并显示所有键值
for(let [,value] of map){
myDisplay.innerHTML+=value+", "
}
}
</script>
</head>
<body>
<div id="display"></div>
</body>
</html>
箭头函数
箭头函数的定义
- 定义
通用函数的定义语法
function 函数体(形参[,形参]){
//函数体
}
例如
function fn1(a,b){
return a+b;
}
或者
var fn2=function(a,b){
return a+b
}
使用ES6箭头函数语法定义函数,将原函数的function关键字和函数名都删掉,并使用箭头"=>"链接参数列表和函数体。
(a,b)=>{
return a+b
}
或者
var fn1=(a,b)=>{
return a+b
}
2. 箭头函数的简化
(1)当函数参数只用一个,括号可以省略,但是当没有参数时,括号不可以省略。
var fn1=()=>{}//无参数
var fn2=a=>{}//单个参数a
var fn3=(a,b)=>{}//多个参数a,b
var fn4=(a,b,...,args)=>{}//可变参数
(2)如果函数体只有一条return语句时,可以省略掉{}和return关键字,但当函数体包含多条语句时,不能省略{}和return关键字。
()=>'hello'
(a,b)=>a+b
(a)=>{
a=a+1
return a
}
定义一个普通函数,然后定义了两种简化的箭头函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>箭头函数</title>
<script>
window.onload=()=>{
var myDisplay=document.getElementById("display");
//1普通函数
let show1=function(a){
return a*2
}
myDisplay.innerHTML="普通函数返回值:"+show1(8)+"<br>";
//简化1如果只有一个参数,则“()”可以省略
let show2=a=>{
return a*3
}
myDisplay.innerHTML+="简化1箭头函数返回值:"+show2(8)+"<br>";
//简化2如果只有一条return语句,则“{}”可以省略
let show3=a=>a*3
myDisplay.innerHTML+="简化2箭头函数返回值:"+show3(8)+"<br>";
}
</script>
</head>
<body>
<div id="display"></div>
</body>
</html>
- 箭头函数与解构赋值
求余数、求最大值、求最小值的方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>箭头函数与解构赋值</title>
<script>
arrow_remainder=([i,j])=>i%j;
console.log('8%3='+arrow_remainder([8,3]));
arrow_max=(...args)=>Math.max(...args);
max=arrow_max(...[12,87,3])
console.log('[12,87,3]的最大值为:'+max)
arrow_min=(...args)=>Math.min(...args);
min=arrow_min(...[12,87,3]);
console.log('[12,87,3]的最小值是:'+min)
</script>
</head>
<body>
</body>
</html>
数组方法
map()方法
map()方法用于遍历数组中的每个元素,让其作为参数执行一个指定的函数,然后将每个返回值形成一个新数组,map()方法不改变原数组的值。
let 新数组名 =数组名.map(function(参数){
//函数体
})
或者简化成以下格式:
let 新数组名 = 数组名.map((参数)=>{
//函数体
})
定义一个数组,让该数组中的每一个数字乘以2生成一个新数组;另一个是定义一个成绩数组,然后根据成绩生成一个含有对应值的新数组。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数组map()方法</title>
<script>
let arr=[1,2,3]
let newArr=arr.map(item=>item*2)
console.log('原数组:'+arr)
console.log('新数组:'+newArr)
let arrScore=[90,34,76]
let score=arrScore.map(item=>item>=60?item>=90?'优秀':'及格':'不及格')
console.log('成绩数组:'+arrScore)
console.log('转换数组:'+score)
</script>
</head>
<body>
</body>
</html>
forEach()方法
forEach()方法是从头到尾遍历数组,为每个元素调用指定函数。该方法将改变原数组本身,并且指定调用函数的参数依次是:数组元素、元素的索引、数组本身。其语法格式如下。
数组名.forEach(function(数组元数,元素的索引,数组本身)){
//函数体
}
或简写成
数组名.forEach((数组元素,元素索引,数组本身)=>{
//函数体
})
定义一个数组,然后把每个数组中的每个数加1,并分别显示修改前和修改后的数组的值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>forEach()方法</title>
<script>
let arr=[1,2,3,4]
console.log('原数组:'+arr)
arr.forEach(function(element,index,arr){
arr[index]=element+1;
})
console.log('新数组:'+arr)
</script>
</head>
<body>
</body>
</html>
filter()方法
filter()方法对数组元素执行特定函数后返回一个子集,也称为过渡方法。该方法的入口参数是执行逻辑判断的函数,该函数返回值是true或false,filter()方法的结果是所执行逻辑判断函数返回为true的元素,换句话说,就是用filter()方法过滤掉数组中不满足条件的值,返回一个新数组,不改变原数组的值。调用filter()方法的语法格式如下。
数组名.filter((参数列表)=>{//函数体})
使用数组的filter()方法过滤掉不能被3整除的元素形成数组
let arr=[60,70,80,87,90]
let result=arr.filter(tmp=>tmp%3==0)//新数组result=[60,87,90]
定义一个对象,对象的属性有language和price,实现将price大于65的值过滤出来,形成一个新数组。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>filter()方法</title>
<script>
let arrJson=[
{language:'web',price:54},
{language:'C++',price:87},
{language:'json',price:63},
{language:'ES6',price:99},
]
let arrResult=arrJson.filter(item=>item.price>=65)
for(var key in arrResult){
console.log(key+":语言"+arrResult[key].language+",价格"+arrResult[key].price);
}
</script>S
</head>
<body>
</body>
</html>
every()方法和some()方法
如果该函数对每个元素运行的结果都返回true,则every()方法最后返回true,也就是说一假即假;some()方法是将数组中的每个元素作为入口指定函数的参数,如果该函数只要有一个元素运行的结果返回true,则some()方法返回true,一真即真。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>every()方法和some()方法</title>
<script>
var people=[
{name:'lb',sex:'male'},
{name:'wq',sex:'female'},
{name:'lyd',sex:'femele'},
];
console.log(people)
/*
var result=people.every(function(people){
return people.sex === 'female'
})
可以简写成以下箭头函数
*/
var result=people.every(people=>people.sex === 'female')
console.log('该对象数组所有人都是女性'+result)//返回值是false
var some=people.some(people=>people.sex === 'female')
console.log('该对象数组包含有女性'+some)//返回值是true
</script>
</head>
<body>
</body>
</html>
reduce()方法
reduce()方法接受一个函数作为累加器,使用数组中的每个元素一次执行回调函数,不包括数组中被删除或从未被赋值的元素,回调函数接收4个参数,调用reduce()方法的语法格式如下:
arr.reduce((prev,cur,index,arr)=>{
//操作语句
},init);
其中,arr表示原数组;prev表示上一次调用回调时的返回值或初始值init;cur表示当前正在处理的数组元素;index表示当前正在处理的数组元素的索引,若提供init,则索引为0,否则索引为1;init表示初始值。下面说明reduce()方法的几个典型应用。
(1)数组求和
const arr=[1,2,3,4,5]
const sum=arr.reduce((pre,item) =>{
return pre+item
},0)
| 调用次数 | 上一次值 | 当前值 | 索引 | 原数组 | 返回值 |
|---|---|---|---|---|---|
| 第1次 | 0 | 1 | 0 | [1,2,3,4,5] | 1 |
| 第2次 | 1 | 2 | 1 | [1,2,3,4,5] | 3 |
| 第3次 | 3 | 3 | 2 | [1,2,3,4,5] | 6 |
| 第4次 | 6 | 4 | 3 | [1,2,3,4,5] | 10 |
| 第5次 | 10 | 5 | 4 | [1,2,3,4,5] | 15 |
(2)求数组项最大值
var max=arr.reduce(function(prev,cur){
return Math.max(prev,cur);
});
(3)数组去重
var newArr=arr.reduce(function (prev,cur){
prev.indexOf(cur) === -1 && prev.push(cur);
return prev;
},[])//此处[]初始值是空数组
数组去重实现的基本原理: A.初始化一个空数组 B.在初始化数组中查找需要去重处理的数组中的第一个元素,如果找不到(空数组肯定找不到),就将该项添加到初始化数组中。 C.在初始化数组中查找需要去重处理的数组中的第二个元素,如果找不到,就将该项继续添加到初始化数组中。 D.重复C。 E.返回这个初始化数组。
计算一个字符串中每个字符出现的次数,在浏览器中显示出来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>reduce()方法</title>
<script>
const str='jshdjsdhhsdkjfskfds';
const obj=str.split('').reduce((pre,item)=>{
pre[item] ? pre[item] ++:pre[item] =1
return pre
},{}) //此处{}表示初值是空对象
console.log(obj)
</script>
</head>
<body>
</body>
</html>
字符串的扩展
模板字符串
- 模板字符串的定义
字符串输出时,如果其中有变量,则需要使用字符串拼接方法进行。
myDisplay.innerHTML = "姓名:"+name+"<br>"
这样写繁琐,ES6引入了字符串模板。用反引号(`)标识,既可以当作普通字符使用,也可定义多行字符串,或者在字符串中嵌入变量。当引入变量时可以使用"${变量}"将变量括起来。
myDisplay.innerHTML = `姓名:${name} <bar>`;
由于反引号是模板字符串的标识,如果需要在字符串中使用反引号,需要转译
var str = ` \`Yo\` World! `
2. 模板字符串的使用
如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保存到输出中。
console.log(`How old are you?
I am 25.`);
输出结果将用两行显示。
How old are you?
I am 25.
另外在“${}”中大括号可以放入任意JavaScript表达式。
var x=88;
var y=100;
console.log(`x=${++x},y=${x+y}`);
输出结果
x=89,y=189
还可以调用函数,如果函数结果不是字符串,则将按照一般规则转换为字符串。
function string(){
return 25;
}
console.log(`How old are you?
I am ${string()}.`);
输入结果:
HOw old are you?
I am 25.
在这里数字25被转化为字符串。
ES6字符串的新增方法
- 查找方法
ES6中有三种方法。
(1)includes(String,index):返回布尔值。String表示要查找的字符串,index表示在源字符串的什么位置开始。该方法表示从index位置后往后查找是否包含String字符串,如果找到返回true,否则返回false。如果没有index参数,表示找整个源字符串。
(2)startsWith(String,index):返回布尔值。表示参数字符串String是否在源字符串头部,index表示从源字符串什么位置开始查找。
(3)endsWith(String,index):返回布尔值。表示参数字符串String是否在源字符串的尾部,index表示从源字符串后面的什么位置开始找。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6字符串的新增方法</title>
<script>
let str='http://www.whpu.edu.cn';
if(str.startsWith('http://')){
console.log(str+"这是普通网址")
}else if(str.startsWith('https://')){
console.log(str+"这是加密网站")
}
let fileName="1.jpg"
if(fileName.endsWith('.txt')){
console.log(fileName+"是文本文件!")
}else if(fileName.endsWith('.jpg')){
console.log(fileName+"是图片文件!")
}
</script>
</head>
<body>
</body>
</html>
- 字符串重复方法
repeat()方法能将源字符串重复几次,并返回一个新的字符串。注意:如果输入的是小数,则向下取整;如果输入NaN,则会被当作0;如果输入其他值则会报错。
let str="lb";
console.log(str.repeat(3));//控制台显示:lblblb
console.log(str.repeat(2.7));//控制台显示:lblb
console.log(str.repeat(0.8));//控制台无显示
console.log(str.repeat(NaN));//控制台无显示
3. 字符串补全方法
padStart()和padEnd()是字符串补全长度的方法。如果某个字符串不够指定长度,会在头部或尾部补全。这两个方法有两个参数:第一个参数是补全后的字符串的最大长度;第二个参数是要补的字符串,返回的是补全后的字符串。
如果源字符串长度大于第一个参数,则返回源字符串;如果不写第二个参数,则用空格补全到指定长度。
console.log('7'.padStart(2,'0'));//控制台显示:07,可用于日期时间的两位显示
console.log('7'.padEnd(2,'0');//控制台显示:70
console.log('hello'.padStart(4,'h'));//控制台显示:hello
console.log('hello'.padEnd(9,'lb'));//控制台显示:hellolblb
console.log('hi'.padStart(5));//控制台显示: hi
如果补全字符串与源字符串超出了补全后的字符串长度,那么补全字符串超出的部分将会被截取。
console.log('hello'.padEnd(9,'world'));//控制台显示:helloworl
Module的语法
Modeule概述
ES6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
import{ reactive, toRefs, computed } from 'vue'
该例是从Vue模块加载三个方法,其他方法不加载,这种加载称为“编译时加载”或静态加载,即ES6可以在编译时就能完成模块加载。
export命令
模块功能主要由两个命令构成:export和import。其中,export命令用于规定模块的对外接口;import命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件,该文件内部的所有变量从外部无法获取。如果希望外部能够读取模块内部的某个变量,就必须使用export命令输出该变量。
export var m=1;
使用大括号指定要输出的一组变量,与直接放置在var语句前是等价的,但是应该优先考虑使用大括号指定这种写法。因为这样可以在脚本尾部看清楚输出了哪些变量。
var m=1;
export {m};
通常情况下,用export命令输出的变量就是原本的名字,但可以使用as重命名。export命令规定的是对外的接口,必须与模块内部的变量建立一一对应。
var n=1;
export {n as m};//变量n的别名m
export命令可以出现在模块顶部的任何位置。如果处于块级作用域内,就会报错,这是因为处于条件代码块中就没法做静态优化,违背了ES6模块的设计初衷。
import命令
使用export命令定义了模块的对外接口之后,其他JavaScript文件可以通过import命令加载这个模块
//main.js
import (firstName,lastName,year) from "./profile";
function setName9element) {
element.textContent = firstName + " " + lastname;
}
import命令用于加载profile.js文件并从中导入变量。import命令接受一个对象(用大括号表示),其中指定要从其他模块导入变量名,大括号中的变量名必须与被导入模块(profile.js)对外接口的名称相同。如果向为输入的变量重新取一个名字,import命令要用as关键字将输入的变量重命名。
import {lastName as surName} from "./profile";
import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,".js"后缀可以省略;如果只是模块名不带有路径,那么必须有配置文件,告诉JavaScript引擎该模块的位置。
import {myMethod} from 'util';
上面代码中util是模块文件名,由于不带路径,必须通过配置文件告诉JavaScript引擎该模块的位置。
由于import是静态执行,所以不能使用表达式和变量,这些是只有在运行时才能得到结果的语法结构。import命令会执行所加载的模块,但不会输入任何值,并且即使多次重复执行同一import语句,也就会执行一次。
import "loadsh";
import 'lodash';
//只会执行一次
import { foo } from "my_module";
import { bar } from "my_module";
//等同于
import {for, bar} from 'my_module';
export default命令
使用import命令时,为了给用户快速上手,可以使用export default,为模块指定默认输出。如,定义一个模块文件export-default.js.
//export-default.js
export default function(){
console.log('foo');
}
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
//import-default.js
import customName from './export-default';
customName(); //输出‘foo’
上面代码中的import命令可以用任意名称指向export-default.js输出的方法,这时就不需要知道原模块输出的函数名。此时import命令后面不需要使用大括号。
export default命令用于指定模块的默认输出,一个模块只能有一个默认输出,因此export default命令只能使用一次。
JSON与Map
JSON概述
JSON就是一个字符串,只不过元素会使用特定的符号标注。
- 大括号({}):表示对象
- 中括号([]):表示数组
- 双引号(""):其中的值是属性或值
- 冒号(:):表示后者是前者的值。
JSON语法的规则中把数据放在“键/值”对中,并且多个数据之间用逗号隔开。其中,对象用大括号括起来,并且有逗号分隔的成员构成;成员由冒号分隔的键值对构成。
JSON有对象和数组两种组织方式。所以需要遵循基本的对象和数组的书写方式。
(1)数组方式。数组是由中括号括起来的一组值构成。
[3,1,4,1,5,9,2,6]
(2)对象方式。
{
"name":"Wang QIong",
"age":18,
"address":{
"country":"China",
"zip-code":"430022"
}
}
JSON是JavaScript对象的字符串表示法,在书写JSON数组或对象时应注意一些问题。
(1)数组或对象中的字符串必须使用双引号,不能使用单引号。
{'name' : 'WangQIong'}//不合法
{"name":'WangeQIong'}//不合法
{"name":"WangeQIong"}//合法
(2)对象的成员名称必须使用双引号。
{"user" : "LiuBing"} //合法
(3)数组或对象最后一个成员的后面不能加逗号。
[
{
"city" : "BeiJing",
"num" : 5 //合法
},
{
"city" : "ShenZhen",
"num" : 5, //不合法
}
]
(4)数组或对象的每个成员的值可以是简单值,也可以是复合值。简单值分为4种:字符串、数值(必须以十进制表示)、布尔值和null(NaN\Infinity、-Infinity和undefined都会被转为null)。复合值分为两种:符合JSON格式的对象和符合JSON格式的数组。下面是错误的JSON定义:
{"age" : 0x16} //不合法,数值必须是十进制的
{"city" : undefined} //使用undefined,不合法
{
"city" : null,
"getcity" : function(){
console.log("错误用法");
}
} //JSON种不能使用自定义函数或系统内置函数,如Date()
JSON的使用
在Ajax中使用时,如果需要用到数组传递值,这时就需要使用JSON将数组转化为字符串。获取JSON数据的语法格式如下:
JSON对象.键名
JSON对象["键名"]
数组对象[索引]
JSON使用JavaScript语法,所以在JavaScript中可以直接处理JSON数据。
{
"name":"Wang QIong",
"age":18,
"address":{
"country":"China",
"zip-code":"430022"
}
}
student.name//返回字符串“Wang QI哦那个”
student.address.country //返回字符串“China”
也可以直接修改数据:
student.name="Liu Bing"
另外,要实现JSON字符串转换为JavaScript对象可以使用JSON.parse()方法。
var obj =JSON.parse('{"a": "Hello", "b": "World"}')
//结果是{a:'Hello',b:'World'}
要实现从JavaScript对象转换为JSON字符串可以使用JSON.stringify()方法:
var json =JSON.stringify({a:'Hello',b:'World'});
//结果是'{"a":"Hello","b":"World"}'
对JSON对象和JSON数组进行遍历。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON</title>
<script>
//定义JSON对象
var myJson ={ 'name' : '刘兵' , 'age' : 18};
//遍历JSON对象
for( var key in myJson){
document.write( key+': '+myJson[key]+"<br>");
}
//定义JSON数组,其成员JSON对象
var wqJson =[ {'name' :'张三','age':19},
{'name':'李四','age':20},
{'name':'王五','age':21}
]
//遍历JSO你数组
for(var i=0;i<wqJson.length;i++){
for(var j in wqJson[i]){
document.write(j+": "+wqJson[i][j]+"<br>")
}
}
</script>
</head>
<body>
</body>
</html>
Map数据结构
- Map数据结构的特点
Map的“键”的范围不仅限于字符串,而各种类型的值都可以做键——“值-值”。Map是一种字典数据类型。字典就是用来存储不重复键的Hash结构。创建Map及其设置方法所使用语句如下:
const myMap = new Map() //定义Map
myMap.set('age',18) //通过set方法设置Map属性
console.log(myMap.get('age')) //通过get方法获取Map属性值,此处返回18
2. Map的常用属性和发给发
(1)size属性。size属性用于返回Map结构的成员总数
const map= new Map();
map.set('foo', true);
map.set('bar',false);
map.size //返回值是2
(2)set(key,value)方法。set()方法用于设置键名key对应的键值为value,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。
const m= new Map();
m.set('edition',6) //键是字符串
m.set(262,'standard') //键是数值
m.set(undefined,'nah') //键是undefined
set()方法返回的是当前的Map对象,因此可以采用链式写法。
let map=new Map().set(1,'a').set(2,'b').set(3,'c')
(3)get(key)方法。get()方法用于读取key对应的键值,如果找不到key,则返回undefined.
const m= new Map();
const hello = function(){console.log('hello');};
m.set(hello,'ES6 world')//键是函数
m.set(hello)//输出:ES6 world!
(4)has(key)方法。has()方法返回一个布尔值,表示某个键是否在当前Map对象中。
const m= new Map();
m.set('edition',6);
m.set(262,'standed');
m.set(undefined,'nah');
m.has('edition')//返回值:true
m.has('years')//返回值:false
m.has(262)//返回值:true
m.has(undefined)//返回值:true
(5)delete(key)方法。delete()方法用于删除某个键,如果删除成功,则返回true,否则返回false。
const m=new Map();
m.set(undefined,'nah');
m.has(undefined) //返回值:true
m.delete(undefined)
m.has(undefined)//返回值:false
(6)clear()方法。clear()方法用于清除数据,没有返回值。
let map =new Map(0;
map.set('foo',true);
map.set('bar',false);
map.size//输出:2
map.clear(0
map.size//输出:0
(7)Map循环遍历。Map结构原生提供以下三个遍历器生成函数和一个遍历方法。
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回所有成员的遍历器
- forEach():遍历Map的所有成员
let map2=new Map([[1,'one'],[2,'two'],[3,'tree']]);
[...map2.keys()];//返回[1,2,3]
[...map2.values()];//返回:['one','two','three']
[...map.entries()];//返回:[[1,'one'],[2,'two'],[3,'three']]
//遍历输出
// 1:one
// 2:two
// 3:three
map2.forEach((key,value) => console.log(key+":"+value))
3. Map与JSON互相转换
可以使用以下函数将Map结构转换为JSON格式
function mapToJson(map){
return JSON.stringify([...map]);
}
可以使用以下函数将JSON格式转换为Map结构
function jsonToMap(jsonStr){
return new Map(JSON.parse(jsonStr));
}
Promise对象
Promise对象的含义
Promise是异步编程的一种解决方法,从语法上说,Promise是一个对象,可以获取异步操作的信息。Promise对象用于一个异步操作的最终完成(或失败)及其结果值的表示。
Promise的一般表现形式:
new promise(
/* executor */
function(resolve, reject){
if(条件){ //条件为真
//执行代码
}else{//条件为假
reject();//执行代码
}
}
)
其中,参数executor是一个用于实现异步操作的执行器函数,其有两个参数:resolve函数和reject函数。如果异步操作成功,则调用resolve函数将该实例的状态设置为fulfilled,即已完成的状态;如果失败,则调用reject函数将该实例的状态设置为rejected,即失败的状态。
Promise对象有三种状态。
(1)pending:初识状态,也称为未定状态,就是初始化Promise时,调用executor执行器函数后的状态。
(2)fulfilled:完成状态,意味着异步操作成功。
(3)rejected:失败状态,意味着异步操作失败。
Promise对象只有两种状态可以转化。
(1)操作成功:将pending状态转化为fulfilled状态。
(2)操作失败:将pending状态转化为rejected状态。
这个状态转化是单向的且不可逆转,已经确定的状态(fulfilled/rejected)无法转回初始状态(pending)。
Promise.prototype.then()
- Promise.prototype.then()
Promise对象含有then()方法,调用then()方法后返回一个Promise对象,意味着实例化后的Promise对象可以进行链式调用,而且这个then()方法可以接收两个函数:一个是处理成功后的函数;另一个是处理错误结果的函数。
var promise1 = new Promise(function(resolve,reject){
//2秒后置为接收完成状态
setTimeout(function(){
resolve('success');
},2000); //转为完成状态,并传入数据success
});
promise1.then(function(data){
console.log(data); //异步操作成功,调用第一个回调函数
},function(err){
console.log(err); //异步操作失败,调用第二个回调函数
}).then(function(data){
//上一步的then()方法没有返回值
console.log('链式调用:'+data); //链式调用:undefined
// ....
})
2. Promise.prototype.catch()
catch()方法和then(0方法一样,都会返回一个新的Promise对象,主要用于捕获异步操作时出现的异常。因此通过省略then()方法的第二个参数,把错误处理控制权转交给其后面的catch()方法。
var promise2 = new Promise(function(resolve,reject){
setTimeout(function(){ //2秒后置为拒绝状态
reject('reject');
},2000);
});
Promise2.then(function(data){
console.log('这里是fulfilled状态'); //已转为拒绝状态,接收状态函数不会触发
// ...
}).catch(function(err){
//使用最后的catch()方法可以捕获在着一条Promise链上的异常
console.log('出错:'+err);//err中的数据是reject,输出结果为出错:reject
});