ES发展历程
1998年6月,ECMAScript 2.0版发布。
1999年12月,ECMAScript 3.0版发布.
2007年10月,ECMAScript 4.0发布(最后不存在)
2009年12月,ECMAScript 5.0版正式发布。
2011年6月,ECMAscript 5.1
2015年6月17日,ECMAScript 6发布
2016年ES7发布
2017年ES8发布
ECMAScript 运算ES代码 有两个环境 1.浏览器 2.Node 也就是说 JS代码 在浏览器里面能跑 在node也能跑 node是后端 对于有些浏览器来说 对ES6及以后的版本支持并不是很友好 目前来说 对ES6支持的 就是谷歌浏览器 我们去写ES6代码的时候 如果说 其他浏览器不支持 我们需要通过某个工具 把ES6代码 转换成更为低级的ES代码(优雅降级) 目的:让我们其他浏览器更好的支持
<script>
var a=()=>{
console.log(123);
}
function a(){
console.log(123);
}
</script>
ES6都干了什么? 这也是你面试的时候 面试官问的最多的问题之一 或者就是笔试题
ES6和ES5的区别 ES6都新增了什么 ES6都有哪些新的语法 (ES6是什么 那么首先你得解释ES6是什么 再说ES6和ES5的区别)
1.多了很多语法糖
什么是语法糖 就是一些很简便的写法 比如你的箭头函数 解构赋值 展开运算符 比如class类
2.let 和const
这两个也是es6新增的变量修饰词 let声明的变量不会提升 不能重复声明 const声明一个常量 不能改变
3.新增了很多的API
API说白了就是别人提供好的方法 或者说具有一定功能的函数 我们可以去调用
学完后端后 后端需要给前端提供API接口,那么这里的API接口 说白了
也是具有一定功能的请求地址
比如我后端写了一个增加用户的接口 那么前端调用这个接口把数据传过去
后端就可以把传过来的数据添加到数据里里面
API接口就是 别人给你准备好的具有一定功能的方法或者地址
主要是数值的 对象的 字符串的
ES6对字符串提供的新的这个操作
新增的方法
startsWith
字面意思了解的话 就是以什么开头,实际的方法的解释
1.当startsWith只有一个参数的时候 判断 一个字符串是否以某个子串开头
let url="www.baidu.com"
console.log(url.startsWith("s"));
console.log(url.startsWith("w"));
console.log(url.startsWith("ww"));
console.log(url.startsWith("www"));
console.log(url.startsWith("www."));
2.当startsWith有两个参数 查找从第二个参数为索引的位置开头的字符串 是否以第一个参数开头
let url="www.baidu.com"
console.log(url.startsWith("b",4));
console.log(url.startsWith("w",4));
endsWith
1.当只有一个参数的时候 判断字符串是否以某个子串结尾
let url="www.baidu.com"
console.log(url.endsWith("com"));
console.log(url.endsWith("om"));
console.log(url.endsWith("m"));
console.log(url.endsWith("o"));
2.当startsWith有两个参数 查找从第二个参数为索引的位置开头的字符串 是否以第一个参数开头
let url="www.baidu.com"
console.log(url.startsWith("b",4));
console.log(url.startsWith("w",4));
includes
1.当只有一个参数的时候 判断一个字符串中是否有某个子串
let url="www.baidu.com"
console.log(url.includes("www"));
console.log(url.includes("baidu"));
console.log(url.includes("com"));
console.log(url.includes("xxx"));
2.当有两个参数的时候 判断从第二个参数为索引开始的字符串是否包含第一个参数
let url="www.baidu.com"
console.log(url.includes("www",4));
console.log(url.includes("baidu",4));
console.log(url.includes("com",4));
repeat 重复某个字符串
str.repact(n) 整体的值就是重复了n次的str
let str="What"
console.log(str.repeat(10));
遍历字符串
for of
for (let char of url) {
console.log(char);
}
模板字符串
let name="wangcai"
let age="100"
console.log(name+"今年"+age+"岁");
console.log(`${name}今年${age}岁`);
对数值的操作
新的整形字面量
let num=10;
let num1=0x10
let num2=0b100
let num3=0o17
新的Number方法
isNaN
判断一个数字是否是NaN
let a=1;
let b=undefined;
console.log(Number.isNaN(a));
console.log(Number.isNaN(a+b));
isFinite
用于检测其参数是否为最大值 如果是NaN 或者是正负无穷大的时候 返回false 否则为true
console.log(Number.isFinite(111));
console.log(Number.isFinite("111"));
console.log(isFinite("111"));
Infinity表示无穷大
console.log(Number.isFinite(-Infinity));
Number.parseFloat
该函数指定字符串中首个字符是否为数字 parseFloat 没区别 如果是 则对字符串进行解析 直到到达数字结束 然后返回这个数字 说白了就是把前面的数字截下来 能把小数部分也接下来
console.log(parseFloat("100年以后"));
console.log(parseFloat("100.5年以后"));
console.log(parseFloat("100.555年以后"));
console.log(parseFloat("100.555年以后3.1415926"));
parseInt
截取前面的数字 但是只能截取整数部分
console.log(parseInt("100.555年以后3.1415926"));
console.log(parseInt(10,8));
console.log(parseInt(11,8));
当有两个参数的时候 那么 就和进制扯上关系了 返回8进制的10 转换成10进制的数
console.log(parseInt("10",16));
console.log(parseInt("84",9));
console.log(parseInt("66",7));
对函数的拓展
箭头函数
var fn= ()=>{
console.log("fn");
}
fn()
如果函数有一个参数 ()就可以省略不写了 如果说是多个参数 必须写
var gn=function(a){
console.log(a*2);
}
gn(2)
var gn= a=>{
console.log(a*2);
}
gn(2)
如果说函数体只有一个语句 {}花括号可以不写
var fn=function(){
var fn=()=>console.log(123);
fn()
如果只有一个语句一个参数
var gn=function(a){
console.log(a*2);
}
var gn=a=>console.log(a*2);
gn(2)
如果说函数只有一条带return的语句 {}也可以不写 return也可以不写
var fn=function(a){
return a*2
}
console.log(fn(2));
var fn=a=>a*2;
console.log(fn(2));
<script>
setTimeout(function(){
console.log("xx");
},2000)
setTimeout(()=>{
console.log(xx);
},2000)
setTimeout(()=>console.log("xx"),2000)
</script>
<div>
<button>点我一下</button>
</div>
<script>
let btn=document.getElementsByTagName("button")[0];
btn.onclick=function(){
console.log(this);
console.log("点我干啥");
}
btn.onclick=()=>{
console.log(this);
console.log("点我干啥");
}
</script> -->
<script>
let fn=function(){
return {a:1}
}
let fn=()=>{a:1};
let fn=()=>({a:1});
console.log(fn());
</script>
<script>
function fn(a=666,b){
console.log(a,b);
}
fn()
fn(1)
</script> -->
<script>
function fn(a,b,c,d){
console.log(arguments);
console.log(Array.isArray(arguments));
}
fn(1,2,3,4)
</script>
rest参数
**拓展参数
..args 整体也叫rest参数 他的作用也是收集参数
当你不确定有几个参数的时候 在参数列表 就写...args 那么你写几个都行**
function fn(...args){
console.log(args);
console.log(Array.isArray(args));
console.log(arguments);
}
fn(1,2)
所以说 args 要和 参数列表中的…args搭配使用 /但是 arguments 是一直有的 只要你函数调用的时候传了实参 除去给你形参赋值 还会收集参数到arguments对象上
小作业
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.wd1200 {
width: 1200px;
}
.main {
margin: 0 auto;
}
.mr20 {
margin: 20px auto;
}
.search {
text-align: center;
}
.operation {
text-align: center;
}
button {
width: 100px;
margin: 0 20px;
}
.classlist {
text-align: center;
}
.classlist ul {
list-style: none;
display: table;
width: 100%;
}
.classlist ul li {
display: table-cell;
width: 400px;
}
</style>
</head>
<body>
<div class="wd1200 main">
<div class="search mr20">
<label for="name">姓名</label>
<input type="text" name="name" id="name">
<label for="sid">学号</label>
<input type="text" name="sid" id="sid">
<label for="sclass">班级</label>
<input type="text" name="sclass" id="sclass">
</div>
<div class="mr20 operation">
<button id="add">添加</button>
<button id="searchStudent">查找</button>
</div>
<div class="classlist mr20" id="classlist">
<ul>
<li>姓名</li>
<li>学号</li>
<li>班级</li>
</ul>
</div>
</div>
</body>
<script>
let add = document.getElementById("add");
let name = document.getElementById("name")
let sid = document.getElementById("sid")
let sclass = document.getElementById("sclass")
let classlist = document.getElementById("classlist")
let search = document.getElementById("searchStudent")
let studentList = []
class Student {
constructor(name, id, sclass) {
this.name = name;
this.id = id;
this.sclass = sclass;
}
}
let stu1 = new Student("张三", "14258", "绘画1")
let stu2 = new Student("李四", "14259", "绘画2")
let stu3 = new Student("王五", "14260", "绘画1")
let stu4 = new Student("赵六", "14291", "绘画2")
studentList.push(stu1)
studentList.push(stu2)
studentList.push(stu3)
studentList.push(stu4)
add.onclick = function () {
let stu = new Student(name.value, sid.value, sclass.value);
studentList.push(stu)
let str = `<ul><li>${stu.name}</li><li>${stu.id}</li><li>${stu.sclass}</li></ul>`
let allStr = classlist.innerHTML;
allStr = allStr + str;
classlist.innerHTML = allStr;
}
window.onload = function () {
studentList.forEach(item => {
let str = `<ul><li>${item.name}</li><li>${item.id}</li><li>${item.sclass}</li></ul>`
let allStr = classlist.innerHTML;
allStr = allStr + str;
classlist.innerHTML = allStr;
});
}
search.onclick = () => {
let allStr=`<ul><li>姓名</li><li>学号</li><li>班级</li></ul>`
console.log(sclass.value);
let res = studentList.filter(function (item) {
return item.sclass == sclass.value
})
res.forEach(item => {
let str = `<ul><li>${item.name}</li><li>${item.id}</li><li>${item.sclass}</li></ul>`
allStr = allStr + str;
classlist.innerHTML = allStr;
})
}
</script>
</html>
对数组的拓展
伪数组 又叫类数组 长的 像数组 但不是数组, 是对象 对象的键值对 键比较特殊 {name:“Wc”}
let arr={
"0":"A",
"1":"B",
"2":"C",
"3":"D",
length:4
}
如何去判断他到底是不是数组
console.log(Array.isArray(arr));
1)我们获取的DOM元素,实际上,document.getElementsByTagName 得到的实际上就是一个伪数组 2)在函数内部有一个arguments 他也是一个伪数组
伪数组转换成一个真的数组
在es6中,提供了一个方法 可以把伪数组转换成一个真的数组
Array.from
在这里Array是对象
let arr={
"0":"A",
"1":"B",
"2":"C",
"3":"D",
length:4
}
Array.from(参数) 参数即是你像转换成真的数组的伪数组
let res=Array.from(arr);
console.log(res);
console.log(Array.isArray(res));
实际上在ES6中 对数组的拓展 主要就体现在对伪数组和数组API中 如果现在有一个类,但是我现在只想要 对象中的属性名,将这些属性名单独的放到一个数组中
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
第一反应是循环这个对象,然后用push方法把他放进去 但是在ES6中,提供了一个方法 不需要循环
console.log(Object.keys(obj));
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
如何把他的属性值单独的放到一个数组里面
console.log(Object.values(obj));
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
console.log(Object.keys(obj));
console.log(Object.values(obj));
let objValue=Object.values(obj)
for (let index in objValue) {
console.log(objValue[index]);
}
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
let arr=[[1,2],[3,4],[5,6]];
for (let v1 of arr) {
for(let v2 of v1){
console.log(v2);
}
}
Object.entries
这个方法把 一个对象中的属性名和属性值放到了一个数组 然后又把每条属性放到了一个数组 让一个对象 变成了一个二维数组
let arr=[[1,2],[3,4],[5,6]];
for (let v1 of arr) {
for(let v2 of v1){
console.log(v2);
}
}
console.log(Object.entries(obj));
for(let v1 of Object.entries(obj)){
for(let v2 of v1){
console.log(v2);
}
}
编程 有两种方式: 1.声明式编程 命名式编程 声明式编程就是人家写好的 你拿过来用 人家让 你怎么用 你就怎么用 2.命名式编程 你自己写 你想怎么写 就怎么写
循环
for (let index = 0; index < array.length; index++) {
const element = array[index];
}
for (const key in object) {
if (Object.hasOwnProperty.call(object, key)) {
const element = object[key];
}
}
for (const iterator of object) {
}
find方法
作用是什么? 在一个数组中查找满足条件的第一个元素
let arr=[1,2,3,4,5,6,7]
let res=arr.find(function(item){
return item>2;
})
let res1=arr.find(item=>item>3)
console.log(res);
console.log(res1);
arr.find 在arr中寻找 满足return后面条件的第一个元素并返回这个元素 find函数的参数是一个回调函数
findIndex
找到数组中满足条件的第一个元素的索引,整体的返回值是我们的索引
let arr=[1,2,3,4,5];
let res=arr.findIndex(function(item){
return item>2;
})
let res1=arr.findIndex(item=>item>4)
console.log(res);
console.log(res1);
includes
判断一个元素是否在数组中
let arr=[1,2,3,4,5];
console.log(arr.includes(2));
console.log(arr.includes(20));
map
对数组中的每个元素进行加工, 返回一个加工后的新的数组
let arr=[1,2,3,4,5];
let res=arr.map(function(item){
return item*2;
})
console.log(res);
filter
是对数组进行过滤的 find是查找到满足条件的第一个元素, 那这个filter就是找到所有满足条件的元素并将它们放到一个新的数组 然后返回
let arr=[1,2,3,4,5];
let res=arr.filter(function(item){
return item>2;
})
console.log(res);
every
只有你数组中每一个元素都满足这个条件 返回值为true 否则为false
let arr=[1,2,3,4,5];
let res=arr.every(function(item){
return item == 1
})
console.log(res);
some
这个数组中 只要有一个满足条件 那么他的返回值就是true
let arr=[1,2,3,4,5];
let res=arr.some(function(item){
return item<1
})
console.log(res);
总结
遍历数组: 1)for循环 2)forEach 3)for in 4)for of
遍历对象: 1)for in 2)Object.keys 3)Object.values 4)Object.entries
一些方法:这里面有ES5有ES6: find:在一个数组中找到满足条件的第一个元素 并返回这个元素 如果没有则返回undefined findIndex:在一个数组中找到满足条件的第一个元素并返回这个元素的索引 如果没有则返回-1 includes:判断一个数组中是否包含某个元素 如果包含则返回true否则false map:对数组中的每一个元素进行加工 返回一个加工后的新数组 filter:对数组中每一个元素进行过滤 返回过滤后的新数组 some:遍历数组中的每一个元素,只要有一个元素满足条件,则返回true 并且立即停止遍历 every:遍历数组中的每一个元素 所有元素都满足条件后 返回true 有一个不满足就返回else 并停止遍历
对对象的拓展
let obj={
name:"wc",
age:100
}
let name="wc";
let age=18;
let obj={
name:name,
age:age
}
当你的属性名和属性值相同的时候 就可以直接简写
let name = "wc";
let age = 18;
let obj = {
name,
age,
say(){
console.log("say..");
}
}
console.log(name);
console.log(age);
obj.say();
Object.assign
Object.assign可以将这两对象合为一起 参数1 {} 目标对象 参数2 参数3…源对象 把源对象上面的属性 统统赋值给目标对象
let obj2={age:100}
let obj={}
console.log(Object.assign(obj,obj1,obj2));
console.log(obj);
展开运算符
let arr1=[1,2,3]
let arr2=[4,5,6]
let arr3=[...arr1,...arr2]
console.log(arr3);
展开运算符也可以展开对象
切记 属性名相同的时候 后面的会覆盖**
let obj1={name:"zhangsan",age:"18"}
let obj2={name1:"lisi",age1:"19"}
let obj3={...obj1,...obj2}
console.log(obj3);
展开伪数组
function gn(){
console.log(arguments);
console.log(...arguments);
}
gn(1,2,3,4)
function gn(...args){
console.log(args);
}
gn(1,2,3)
解构赋值
解构赋值就是一种很简单的赋值方式
let arr=["wc","xq","zs"];
let [a1,a2,a3]=["wc","xq","zs"];
let [a1,a2,a3]=arr;
console.log(a1,a2,a3);
你要用结构赋值 必须保持 =两边的数据类型 要保持一致
let a=1;
let b=2;
let c;
c=a;
a=b;
b=c;
console.log(a,b);
let b=2;
[a,b]=[b,a]
console.log(a,b);
如果说一个数组中有三个数,但是我解构赋值只想给后两个 或者后一个赋值
let [,b,a]=[1,2,3]
console.log(b,a);
let [c,,d]=[1,2,3]
console.log(c,d);
解构赋值 能用于数组, 也可以用于对象
let obj={
name:"zhangsan",
age:"18"
}
let {name,age}=obj;
console.log(name,age);
切记一点 就是对象的解构赋值的时候不要加名字 不要起别名
{name:username,age:userage}={name:"wc",age:"100"}
console.log(name,age);
默认解构
let {name,age,score}={name:"wc",age:100}
let {name,age,score=99}={name:"wc",age:100}
console.log(score);
class类
学这个之前 我们的类 通常是函数 也叫构造器 但是在ES6 多了一个新的声明方式 叫class 专门用于声明类
function Father(name){
this.name=name
class Fahter{
}
let f=new Father();
constructor
当我们new的时候就会自动的调用constructor这个函数 在constructor中可以给对象添加私有属性了
class Father{
constructor(name,age){
this.name=name;
this.age=age;
this.say=function(){
console.log("say...");
}
console.log("构造函数被调用了");
}
}
let f=new Father("wc",100);
console.log(f);
f.say();
私有方法和私有属性都写了 公有的怎么办
class Father{
constructor(name,age){
this.name=name;
this.age=age;
console.log("构造函数被调用了");
}
jump(){
console.log("jump");
}
}
let f=new Father("zhangsan","18");
console.log(f);
f.jump();
console.log(f.__proto__);
console.log(f.hasOwnProperty("name"));
console.log(f.hasOwnProperty("age"));
console.log(f.hasOwnProperty("jump"));
console.log("name" in f);
console.log("age" in f);
console.log("jump" in f);
console.log("jumps" in f);
class Father{
static score=100;
constructor(name,age){
this.name=name;
this.age=age;
this.say=function(){
console.log("say..");
}
}
jump(){
console.log("jump..");
}
static haha(){
console.log("haha");
}
}
static 静态属性 静态的属性怎么去用 静态修饰的属性方法 都需要通过类名调用 不能通过对象名调用
et f=new Father("zhangsan","18");
console.log(f.score);
console.log(Father.score);
Father.haha();
</script> -->
以前讲继承 原形继承 call继承 组合继承 只继承共有属性 在ES6中如何继承?
class Father{
constructor(){
this.a=100;
}
getA(){
console.log(this.a);
}
}
Son中没有私有属性 没有共有属性 但是 想继承父级的 用Father里面的公有属性和私有属性
class Son extends Father{};
let son=new Son();
console.log(son.a);
son.getA();
<script>
class Father{
constructor(){
this.job="student";
}
getA(){
console.log(this.a);
}
}
class Son extends Father{
constructor(name){
super();
this.name=name;
}
getA(){
console.log("Son中的getA");
}
}
let son=new Son("zhangsan");
console.log(son);
son.getA()
</script>
ES6中新增加的两个数据结构
)Set 不是对象{} 也不是数组 是一个新的数据解构 2)Map
我们以前说 对象 数组啊 可以通过let a=new Array()去生成 我们这个set和map也是 let mySet=new Set(); 在这里mySet是对象 Set是类
如何往里面这个Set容器里面放东西
mySet.add("张三")
console.log(mySet);
mySet.add("李四")
console.log(mySet);
这个set容器有一个特点 就是你往里面放东西 放重复的 他不会加
mySet.add("张三")
console.log(mySet);
如何看这个容器里有多少个元素呢
console.log(mySet.size);
如何删除Set里面的东西呢
mySet.delete("张三");
console.log(mySet);
mySet.add("张三")
如何判断里面是否有某个元素
console.log(mySet.has("张三"));
console.log(mySet.has("王麻子"));
如何清空Set容器里面的东西
mySet.clear();
console.log(mySet);
如何遍历Set?
mySet.add("李四");
mySet.add("张三");
mySet.add("王麻子");
console.log(mySet);
for (let item of mySet) {
console.log(item);
}
WeakSet
普通的Set 里面存的都是字符串 数字啊 基础数据类型 WeakSet里面存的是引用数据类型
let myWeakSet=new WeakSet();
myWeakSet.add({name:"zhangsan"})
myWeakSet.add({name:"李四"})
myWeakSet.add([1,2,3])
console.log(myWeakSet);
Map也是ES6中新增的一个容器 它里面存的是键值对 学容器 说白了就是学增删改查 以前学数组的时候 开始也是增删改查 学对象的时候也是
迭代器和生成器
了解:可迭代对象 只要是一个可迭代对象 都可以用for of来遍历
在JS中下面的几个类型是可以迭代的 Array Set Map String 你通过构造器创建出来上面的这几个对象 都叫可迭代对象 只有可迭代对象 才能用for of进行遍历
let arr=new Array("a","b","c","d")
for (const item of arr) {
console.log(item);
}
遍历对象 forin Objcet.keys Object.values Object.entries
迭代器是专门用于迭代对象 所有的可迭代对象都有一个方法 叫做next方法 用这个next方法的话 会返回一个对象 这个对象里面有两个属性 一个叫value 一个叫done alue表示当前迭代出来的值 done则表示是否迭代完毕 如果完毕 done的值就是true
生成器:生成迭代器 generator是生成器的意思 (如果在你的function 和 函数名之间 加了一个 那么此时这就是一个生成器)*
function *generator(){
yield "v1"
let it=generator();
console.log(it.next());
console.log(it.next());
function *app(){
yield "v1"
yield "v2"
yield "v3"
yield "v4"
}
let it=app();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
function *app(){
let s1=yield "v1"
console.log("s1:",s1);
let s2=yield "v2"
console.log("s2:",s2);
let s3=yield "v3"
console.log("s3:",s3);
let s4=yield "v4"
console.log("s4:",s4);
}
let it=app();
console.log(it.next("张三"));
console.log(it.next("张三"));
console.log(it.next("李四"));
console.log(it.next("王五"));
console.log(it.next("赵六"));
在调用next的时候 可以给生成器内容变量赋值 传参的话 第一次传的参数 没有用
小结: 生成器的作用:用于生成迭代器 迭代器:主要是迭代出对象 数据可以在生成器中产出 可迭代对象 :内置了迭代器 使用for of就可以迭代
|