咔斯Sama
文章32
标签14
分类6
web学习笔记13 - HTML5和ES6 新特性

web学习笔记13 - HTML5和ES6 新特性

HTML5和ES6新特性
封面画师:唏嘘的星辰 p站ID:13312138

语义化

语义化: 看到它就知道它是干啥的
语义化标签: 使用单词作为标签,使标签更容易被识别

常见的语义化标签

结构化标签: header, main, footer, nav, aside, hr
文本标签: p, h1-h6, strong, i, del

语义化概念

什么是HTML语义化?HTML语义化的好处是什么?
html语义化让页面的内容结构化结构更清晰便于对浏览器、搜索引擎解析;
即使在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读的;
搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO;
使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。

什么是SEO? 如何做SEO优化?

SEO,是英文SearchEngineOptimization的缩写,中文的意思: 搜索引擎优化SEO的目的就是让网站或者网页在搜索结果中,处于靠前的位置

实现SEO优化的方式有:

  1. 合理的title、description、keywords:搜索对着三项的权重逐个减小,title值强调重点即可;description把页面内容高度概括,不可过分堆砌关键词;keywords列举出重要关键词
  2. 语义化的HTML代码,符合W3C规范:语义化代码让搜索引擎容易理解网页
  3. 重要内容HTML代码放在最前:搜索引擎抓取HTML顺序是从上到下,保证重要内容一定会被抓取
  4. 重要内容不要用js输出:爬虫不会执行js获取内容
  5. 少用iframe:搜索引擎不会抓取iframe中的内容
  6. 非装饰性图片必须加alt
  7. 提高网站速度:网站速度是搜索引擎排序的一个重要指标

音视频标签

音视频标签的四个属性:

src 属性设置音视频资源路径
controls 属性设置播放控制器
autoplay 属性设置自动播放, 需要开启浏览器授权
loop 属性设置循环播放

<audio src="https://music.163.com/song/media/outer/url?id=28263184.mp3" controls loop>此浏览器不支持播放</audio>
<video src="./demo.mp4" controls loop></video>

audio演示:

弹性布局

流式布局: 网页默认的布局方式, 元素按照行标签从左向右,块标签从上向下依次排列, 尽量不使标签重叠
弹性布局: html5新增的网页布局方式, 需要手动设置, 有如下特点:

  • 1,弹性布局总是给父元素设置, 对第一级子元素起效
  • 2,弹性布局元素默认从左向右排列,不换行,高度为100%(包含margin)
  • 3,弹性布局元素没有行标签块标签之分,可以正常设置宽距和宽高
  • 4,弹性布局元素不能使用浮动, 可以使用定位

弹性布局中的属性设置:

弹性容器 的属性设置:
display: flex; 设置弹性容器
flex-wrap: wrap; 设置换行
justify-content: space-evenly; 设置说水平对齐方式
align-items: center; 设置单行对齐方式
align-content: flex-start; 设置多行对齐方式
弹性元素 的属性设置:
align-self: flex-end; 弹性元素单独对齐
order: 1; 弹性元素的排列顺序
flex-grow: 2 元素扩展比例
flex-shrink: 0; 元素压缩比例

布局 适配 兼容

响应式布局

概念: 在浏览器窗口尺寸变化时, 使一个网页在不同宽度的窗口上显示不同的排版样式和内容
使用场景: 一般用于PC端网页
实现原理: 使用媒体查询

浏览器适配

概念: 在浏览器窗口尺寸变化时, 使一个网页在不同宽度的窗口上显示相同的排版样式和内容
使用场景: 一般用于移动端网页
实现原理: 视口单位 vw / vh

浏览器兼容

概念: 在不同内核的浏览器上, 使一个网页在不同浏览器的上显示相同的排版样式和内容
使用场景: 在不同内核和不同版本浏览器上的兼容(兼容低版本浏览器)
实现原理: 代码优化

媒体查询

媒体查询的结构:

@media 媒体类型 and (媒体特性) {
    条件满足时,渲染的css样式
}

媒体类型: 此样式会在什么设备上生效 all / screen
媒体特性: 此样式渲染的条件, min-width / max-height

媒体特性.png

移动端适配

适配: 在不同的设备上显示相同的样式

  • viewport: 视口, 可视窗口, 一般指移动端屏幕窗口
  • 移动端视口中有两个长度单位 vwvh
  • vw: viewportWidth 视口宽度 100vw == 视口宽度
  • vh: viewportHeight 视口高度 100vh == 视口高度

100% 和 100vw 的区别

  • 100% 指的是父标签宽度
  • 100vw 指得是宽口宽度

注意: 移动端竖向滚动条不占宽度, 所以移动端 100vw == 100%
结论: 建议PC端用100%, 移动端用100vw

ES6

es6: ECMA script 6

  • ECMAScript 是javascript的一种语法标准
  • es6 第六版js语法
  • ECMA : European Computer Manufacturers 2Xf2E6aEU7n685eHEbXGYHrmWn2y7a62UWBrtZzodVdD

截止目前,各大浏览器都已经实现了es6标准的90%以上。nodejs几乎完全支持es6。

参考教程: http://jsrun.net/t/cZKKp

requestAnimationFrame

requestAnimationFramesetTimeout 类似, 都是一个短暂不重复的计时器

  • setTimeout可自定义计时时间
  • requestAnimationFrame 的计时时间是默认的, 一帧的时间,约等于16.67ms

requestAnimationFrame 优点: 在保证动画流畅运行的前提下, 最大限度的节约性能消耗

由于收到设备性能的影响, 网页的刷新率(帧率)不一定准确维持在60帧/s, 可能偏高或偏低, 所以16.67ms的帧时间是一个大概的值,不是定值

// 使用setInterval实现小球d1运动
var y1 = 0
setInterval(() => {
    y1 += 1
    if(y1 >= 600) y1 = 0
    d1.style.top = y1 + "px"
}, 16.67);


// 使用setTimeout实现小球d2运动
var y2 = 0
function move(){
    y2 += 1
    if(y2 >= 600) y2 = 0
    d2.style.top = y2 + "px"
    setTimeout(move, 16.67); // 递归
}
setTimeout(move, 16.67);


// 使用requestAnimationFrame实现小球d3运动
var y3 = 0
function move1(){
    y3 += 1
    if(y3 >= 600) y3 = 0
    d3.style.top = y3 + "px"
    requestAnimationFrame(move1); // 递归
}
requestAnimationFrame(move1);

地理定位

navigator.geolocation 是H5新增的API,用于浏览器获取位置信息

window.navigator.geolocation.getCurrentPosition(res=>{
    console.log(res.coords)
    // accuracy: 55   定位精度
    // ​
    // altitude: 0    海拔高度
    // ​
    // altitudeAccuracy: 0   海拔精确度
    // ​
    // heading: null     移动方向
    // ​
    // latitude: 34.72326699999999   纬度
    // ​
    // longitude: 113.75165477777777   经度
    // ​
    // speed: null    移动速度
})  // 开启位置监视后, 直接获取位置失效

// 开始监控位置
var watch = navigator.geolocation.watchPosition(res=>{
    console.log("位置更新", res)
})

// 取消监听
setTimeout(() => {
    navigator.geolocation.clearWatch(watch)
}, 10000);

百度地图

<!-- 引用百度地图API3.0文件 -->
<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=你自己の密钥"></script>
<script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&&type=webgl&ak=你自己の密钥">
</script>
<!-- 创建地图容器元素 -->
<div id="container"></div> 
<button onclick="getEarth()">开启地球模式</button>
<script>
    // 创建地图实例
    var map = new BMap.Map("container"); 
    // 设置中心点坐标
    var point = new BMap.Point(116.404, 39.915); 
    // 地图初始化,同时设置地图展示级别
    map.centerAndZoom(point, 15);  
    // 获取当前位置
    navigator.geolocation.getCurrentPosition(res=>{
        // panTo()方法将让地图平滑移动至新中心点
        map.panTo(new BMap.Point(res.coords.longitude, res.coords.latitude)); 
        // 逆地址解析  // 创建地理编码实例, 并配置参数获取乡镇级数据
        var myGeo = new BMap.Geocoder({extensions_town: true}); 
        // 根据坐标得到地址描述    
        myGeo.getLocation(new BMap.Point(res.coords.longitude, res.coords.latitude), function(result){      
            if (result){      
                alert(result.address);      
            }      
        });

    })
    //开启鼠标滚轮缩放
    map.enableScrollWheelZoom(true);  
    // 添加平移缩放控件
    map.addControl(new BMap.NavigationControl()); 
    // 比例尺控件
    map.addControl(new BMap.ScaleControl()); 
    // 缩略图控件 
    map.addControl(new BMap.OverviewMapControl());   
    // 地图类型
    map.addControl(new BMap.MapTypeControl());
    // 添加路况图层
    var traffic = new BMap.TrafficLayer();      
    map.addTileLayer(traffic); 
    // 圆形区域搜索
    var local = new BMap.LocalSearch(map,{ 
        renderOptions:{
            map: map, 
            autoViewport: true
        }
    });      
    // 在天安门附近搜索银行
    local.searchNearby("漫展","上海");   
</script>
<script>
    // 点击按钮切换地球模式
    function getEarth(){
        console.log(123)
        var map = new BMapGL.Map("container");
        var point = new BMapGL.Point(116.404, 39.915);
        map.centerAndZoom(point, 1); 
        map.enableScrollWheelZoom(true);
        map.setMapType(BMAP_EARTH_MAP);
    }
</script>

canvas画布

canvas绘图Api

在script标签中添加如下注释,即可自动提示canvas API
/** @type {HTMLCanvasElement} 添加canvas API语法提示*/
(一) 方法:

getContext("2d") 创建绘图对象

beginPath(); 开始绘制路径

closePath(); 结束绘制路径,闭合线框

moveTo(x,y); 移动到绘制起点

lineTo(x,y); 画线段到指定点

arc(x,y,r,start,end); 绘制圆形(弧度单位)

quadraticCurveTo(x,y,endX,endY) 二次贝塞尔曲线

bezierCurveTo(x1,y1,x2,y2,endX,endY) 三次贝塞尔曲线

stroke(); 线条类型

fill(); 填充类型

fillRect(x,y,w,h) 填充矩形

strokeRect(x,y,w,h) 线框矩形

clearRect(x,y,w,h) 清除矩形

strokeText(string,x,y) 绘制线条文字(空心)

fillText(string,x,y) 绘制填充文字(实心)

drawImage(img,x,y,width,height) 绘制图片(需在img的load函数中)

save() 保存当前状态设定

restore() 恢复到保存之前的状态设定

rotate() 旋转画布角度(弧度制)

(二) 属性:

fillStyle 填充颜色(支持rgb(),#fff,red)

strokeStyle 线条颜色

lineWidth 线条宽度(整数值,默认单位px)

lineJoin 折线拐角类型 (round表示圆角)

font 支持多个值, 例如”10px 宋体”

textBaseline 文字基点(默认bottom左下为基准点, top为左上)

globalCompositeOperation 绘制合成(具体值参考附件)

canvas语法

<style>
    canvas{
        border: 1px solid;
        /* css设置尺寸只能缩放画布,不能改变画布实际尺寸 */
        /* height: 600px; */
    }
</style>
<body>
    <!-- 属性height/width设置的才是画布的实际尺寸 -->
    <canvas id="myCanvas" height="600"></canvas>
    <script>
        // 获取canvas标签元素
        /** @type {HTMLCanvasElement} 添加canvas API语法提示*/
        var canvas = document.getElementById("myCanvas")
        // 通过canvas标签获取一个绘图对象
        var ctx = canvas.getContext("2d")

        // 1, 绘制线段
        ctx.moveTo(20, 20); // 设置绘制起点
        ctx.lineTo(120, 20); // 绘制线段到终点
        ctx.lineTo(120, 120); // 绘制线段到另一个终点
        ctx.lineTo(20, 120);
        ctx.lineTo(20, 20);
        ctx.moveTo(20,70);  // 设置另一个绘制起点
        ctx.lineTo(120,70);
        ctx.moveTo(70, 20);  // 设置另一个绘制起点
        ctx.lineTo(70,120);
        ctx.stroke(); // 执行绘制线段


        // 2, 绘制线框矩形
        ctx.strokeRect(150, 20, 100, 60);
        // 绘制填充矩形
        ctx.fillRect(150, 100, 100, 60);
        // 清理矩形区域
        ctx.clearRect(180, 130, 20, 20);

        // 3, 绘制弧形和扇形
        // ctx.moveTo(120, 200) // 先移动移动到圆弧起点
        ctx.beginPath()  // 开始另一个绘制路径
        ctx.arc(70, 200, 50, 0, Math.PI);
        // ctx.stroke()  // 圆弧
        ctx.fill()       // 扇形区域
        ctx.closePath() // 结束另一个绘制路径

        // 4, 绘制曲线
        // 二次贝塞尔曲线
        ctx.moveTo(20, 300);  // 曲线起点
        ctx.quadraticCurveTo(100, 200, 240, 300);
        ctx.stroke()
        
        // 三次内塞尔曲线
        ctx.beginPath()
        ctx.strokeStyle = "yellow";
        ctx.lineWidth = 2;
        ctx.moveTo(20, 400);// 曲线起点
        ctx.bezierCurveTo(100, 200, 200, 500, 240, 330);
        ctx.stroke()
        ctx.closePath()


        // 5, 绘制文字
        ctx.font = "50px 楷体";
        ctx.strokeStyle = "red";
        ctx.lineWidth = 1
        ctx.fillStyle = "green"
        ctx.strokeText("饕餮", 20, 500);
        ctx.fillText("王粲博", 150, 500);  

        // 6, 绘制图片
        var img = document.createElement("img")
        img.src = "./item338.gif"
        // 不能直接绘制图片,需要在img的load事件中绘制
        img.onload = function(){
            ctx.drawImage(img, 20, 520, 260, 80)
        }
    </script>
</body>

实例:刮刮乐

<style>
        canvas{
            position: relative;
            background-image: url(item338.gif);
            background-size: 100% 100%;
        }
    </style>
<body>
    <canvas id="canvas"></canvas>
    <script>
        /** @type {HTMLCanvasElement} 添加canvas API语法提示*/
        var canvas = document.getElementById("canvas")
        var ctx = canvas.getContext("2d")

        // 先绘制灰色图层
        ctx.fillStyle = 'gray';
        ctx.fillRect(0,0,300,150);
        
        // 再绘制提示文字
        ctx.font = "30px 黑体"
        ctx.fillStyle = "green"
        ctx.fillText('刮开有惊喜', 60, 80);

        // 图层叠加 (目标图像是已经绘制的图层, 源图像是即将绘制的图像)
        ctx.globalCompositeOperation = "destination-out"

        // 刮图层的函数
        function gua(e){
            ctx.beginPath()
            // e.pageX 相对于网页,  e.layerX 相对于非静态定位元素
            ctx.arc(e.layerX, e.layerY, 20, 0, Math.PI*2)
            ctx.fill()
        }

        // 鼠标按下,开始绘制圆形
        canvas.onmousedown = function(){
            canvas.addEventListener("mousemove", gua)
        }
        // 鼠标抬起, 停止绘制
        canvas.onmouseup = function(){
            canvas.removeEventListener("mousemove", gua)
        }
    </script>
</body>

globalCompositeOperation.png

WebWoker

概念
进程: 一个应用的代码执行流程, 一个应用有且仅有一个进程
线程: 也叫分线程, 可以独立于主线程执行, 通过代码创建, 可以没有也可以有多个
主线程: 同 进程
分线程: 同 线程

总结:
分线程使用的API:
new Worker() 创建分线程
postMessage() 线程之间发送数据
onmessage 事件,接收线程发送的数据

注意事项:
1, 分线程不能调用界面相关API,只有主线程可以操作界面
2, 线程之能同源访问, 跨域无法引入分线程脚本, 网页不能使用file协议本地打开
3, 分线程和主线程作用域相互隔离,不能直接调用数据, 需要使用postMessage和onmessage发送和接收
4, 分线程不能执行界面相关的alert()等API,但可以执行与界面无关的ajax请求
5, 分线程无法读取本地文件, 分线程中的数据都要来源于网络

参考教程: http://www.ruanyifeng.com/blog/2018/07/web-worker.html

块级作用域

var 关键字定义变量有两个作用域 全局作用域 和 局部作用域
let 关键字定义变量有三个作用域 全局作用域, 局部作用域 和 块级作用域
全局变量: 在全局范围内定义的变量
局部变量: 在函数内部定义的变量
块级变量: 在语法块中定义的变量 比如循环,判断语法块

举例: 使用在语法块中定义的变量,只能在语法块中使用

if(true){
    var d = 4;
    let e = 5;
}
// console.log(d)  // 4
// console.log(e)  // undefined

举例: 在循环中, 实现延时打印

for(let i = 0; i < 5; i++){
    // 在循环中使用var定义变量, 这个变量是全局变量, 每次循环的count共享同一个作用域, 所以下次循环的count把替换上次循环的count, 循环之后,全局只有一个count,值为4
    var count = i;
    // console.log(count) // 0,1,2,3,4
    setTimeout(() => {
        console.log(count) // 4,4,4,4,4
    }, 100);


    // 在循环中使用let定义变量, 这个变量是块级变量, 每次循环都会在一个新的块级作用域中定义一个独立块级变量number, 循环结束后, 就有5个块级变量number,他们的值各不相同, 互补影响
    let number = i;
    setTimeout(() => {
        console.log(number) // 0,1,2,3,4
    }, 200);
}
// console.log(i) // undefined 循环变量i建议使用let定义, 再循环之外无法调用, 也就避免了全局作用域污染 

如果要在循环中添加计时器或事件绑定, 需要保留每次循环的变量值, 有以下两种解决方案,

  1. 使用let定义块级变量
    for(let i = 0; i < 5; i ++){
        setTimeout(()=>{
            console.log(i)
        }, 300);
    }
  2. 使用闭包, 保持count局部变量
    function outter(count){
        return function inner(){
            console.log(count)
        }
    }
    for(var i = 0; i < 5; i ++){
        setTimeout(outter(i), 300);
    }

let和var的两点主要区别:

  1. var 在同一作用域可以重复定义同一个变量, let不行
  2. var 没有块级作用域, 在循环中定义的变量都是全局的, 会相互覆盖, let在循环中定义的变量都是独立的,互不影响

const常量

ES6新增了两个关键字

  1. let 定义变量
  2. const 定义常量
    const 定义值类型数据, 绝对不能改
    const 定义引用类型数据, 数据内容(对象/数组中的数据)可以改, 引用类型本身(内存地址)不能改

字符串模板

如果要把字符串和变量拼接到一起, 有两种写法

var year = 2020, month = 4, day = 20;
// 1, ES5字符串拼接
console.log(year + "年" + month + '月' + day + "日")

// 2, es6模板字符串
console.log(`${year}${month}${day}日`)

// 由于模板字符串支持换行, 所以可以用来渲染标签字符串
var htmlStr = `
    <ul>
        <li>${year}年</li>
        <li>${month}月</li>
        <li>${day}日</li>
    </ul>
`
console.log(htmlStr)

箭头函数

箭头函数用法:

  1. 在事件函数或计时器或异步回调函数中可以保留this上下文指向
  2. 箭头函数在参数和返回值处,满足条件时,都可以简化
  3. 在对象中有一个简化的函数写法
// 普通的function函数不能转化为箭头函数
function add(){ }
// 只有匿名函数可以转化为箭头函数
var add = function(){ }
var add = ()=>{}

// 在node环境下, this默认指向空对象
console.log(1, this)  // {}
// 可以修改这个对象
this.name = "zhangsan"
console.log(2, this)  // {name: "zhangsan"}


// setTimeout会把this指向修改为Timeout对象
setTimeout(function(){
    console.log(3, this) // Timeout
}, 1000);

// 箭头函数会保留this的上下文指向, 使this指向和setTimeout外部相同
setTimeout(() => {
    console.log(4, this) // {name: "zhangsan"}
}, 1000);

// 箭头函数的简化
var add = (count)=>{
    // return count ++
    return ++ count 
}
console.log(add(5)) 
// 如果箭头函数只有一个参数, 可以省略小括号
var add = count => { return ++ count; }
// 如果箭头函数的函数体中只有一句return返回,  return和{}可同时省略
var add = count => ++count; 
console.log(add(100))

// 箭头函数在对象中的写法, 对象中的函数有以下三种写法
var student = {
    name: "张三",
    age: 20,
    // ES5函数的写法, 其中的this是当前对象
    eat: function(){
        console.log(this.name+"吃饭")
    },
    // ES6箭头函数写法, 其中的this是对象上下文(全局作用域)指向
    drink: ()=>{
        console.log(this.name+"喝水")
    },
    // 简化写法, 其中this的指向还是当前对象
    sleep(){
        console.log(this.name+"睡觉")
    }
}
student.eat()
student.drink()
student.sleep()

数组对象

数组解构: var [count1,count2,...count3] = array
数组赋值1: array.push(…array2)
数组赋值2: array = […array, …array2, 5,6,7]
对象解构: var { age } = student
对象赋值: {…student, height:120}

// 数组的解构
var array = [1,2,3,4]
// 一般,使用数组中的数据要使用索引取值
console.log(array[1])
// 数组解构允许我们直接使用变量读取数组中的数据
let [count1, count2, count3, count4] = array
console.log(count3)
// 注意: 由于数组有顺序,在解构时,一般前边变量个数和数组中数据个数要一一对应

// 可以使用 ... 语法解构数组中的一部分数据(靠后的好几条数据)
let [num1, ...num2] = array
console.log(num2)

// 数组的赋值
var array2 = ["a", "b", "c"]
// 需求: 把array2拼接到array中
// 方法1: 循环array2把array2的每一条数据加入array中
// array2.forEach(item=>{
//     array.push(item)
// })
// console.log(array)
// 方法2: 使用concat数组拼接API
// array = array.concat(array2)
// console.log(array)
// 方法3: 使用 ... 数组赋值
array.push(...array2)
console.log(array)
// 数组也可以如下拼接
array = [...array, ...array2, 5,6,7]
console.log(array)



// 对象的解构
var student = {
    name: "张三",
    age: 12,
    sex: "男",
    phone: "110"
}
console.log(student)
// 如果要获取一个对象中的某个字段, 直接用对象打点调用即可
console.log(student.phone)
// 也可以使用对象解构写法获取某个字段值
var { age, sex } = student;
console.log(age, sex)
// 注意: 由于对象中的数据没有顺序, 所有对象解构无需把所有字段都写上,可以按需定义变量读取对象中的某一个或几个字段即可, 但必须保证变量名和字段名相同


// 把student这个对象中的数据拼接到people对象中
var people = {
    height: 120,
    weight: 180,
    ...student
}
console.log(people)



// 字符串解构, 和数组解构类似
var string = "ABC"
var [a,b,c] = string;
console.log(a,b,c)

数组对象拼接

数组拼接
var array1 = [1,2,3]
var array2 = [4,5,6]
console.log([...array1, ...array2, 7,8,9])

[
1, 2, 3, 4, 5,
6, 7, 8, 9
]

对象拼接
var obj1 = { age: 20 }
var obj2 = { sex: true }
console.log({...obj1, ...obj2})

{ age: 20, sex: true }

参数的默认值

function add1(a,b){
    console.log(a+b)
}
add1()      // NaN
add1(3)     // NaN
add1(3,4)   // 7
add1(3,4,5) // 7

// js函数定义时有两个参数, 调用时就必须传入至少两个参数,
// 如果传入的实参少于形参的个数,为防止错误, 可以给形参设置默认值

// ES5中使用 || 设置默认值
function add2(a,b){
    a = a || 0; //设置默认值
    b = b || 0; //设置默认值
    console.log( a + b )
}
add2()      // 0
add2(3)     // 3
add2(3,4)   // 7
add2(3,4,5) // 7

// ES6中使用 初始化形参 设置默认值
function add3(a=0, b=0){
    console.log( a + b )
}
add3()      // 0
add3(3)     // 3
add3(3,4)   // 7
add3(3,4,5) // 7

// 关于函数的参数, 如果参数个数不确定, 如果获取所有参数
// ES5中通过arguments字段获取参数数组
function add4(){
    // arguments是一个类数组, 里边放了所有参数
    console.log(arguments, Array.from(arguments))
}
add4()      // {}   []
add4(3)     // {"0": 3}   [3]
add4(3,4)   // {"0":3, "1": 4}   [3,4]
add4(3,4,5) // {'0': 3, '1': 4, '2': 5 }  [3,4,5]


// ES6中通过形参...arr获取参数数组
function add5(...array){
    // 形参array是所有参数所在的数组
    console.log(array)
}
add5()      // []
add5(3)     // [3]
add5(3,4)   // [3,4]
add5(3,4,5) // [3,4,5]

Promise

Promise的由来

js代码执行过程中,分为同步执行异步执行的两种代码执行逻辑
同步执行: 代码总是从上向下依次执行,只有上一句执行完,才会执行下一句, 默认js是通过
异步执行: 特殊形况下,异步代码可以和其他代码同时执行,相互不影响,不严格按照顺序执行, 常见的异步执行逻辑有 计时器, js事件, ajax, promise调用
异步代码的标志性特点是: 回调函数
结论: 一段逻辑代码中,总是先执行同步代码, 再执行异步代码

上代码:

// 这是正常的函数返回值调用
function getRandom(){
    return Math.random()
}
var random = getRandom()
console.log(1, random)


// 当函数中有异步操作时,能否return返回异步结果
function getRandom2(){
    setTimeout(() => {
        console.log(3)
        return Math.random()// 异步函数中的return是无效的
    }, 100);
}
var random2 = getRandom2()
console.log(2, random2)  // 2 undefined

Promise的语法

// Promise 在es6中属于一个 类  要通过new创建promise对象使用,  如下

// 新建一个promise对象, 参数是一个同步函数, 同步函数的参数是成功和失败的回调函数 
var p = new Promise(function(resolve, reject){
    // 使用new创建promise对象这个操作是同步操作还是异步操作?   同步的
    console.log(1)
    // 在promise对象中执行异步任务
    setTimeout(() => {
        console.log(3)
        var random = Math.random()
        if(random > 0.5){
            resolve("成功")
        }else{
            reject("失败")
        }
    }, 100);
})
console.log(2)
// 使用promise对象调用函数then拿成功的数据, 调用catch拿失败的数据
p.then(data=>{
    console.log(4, data)
})
p.catch(err=>{
    console.log(4, err)
})


// promise支持链式调用
p.then().catch().then().then(data=>{
    console.log(5, data)
}).then()

// promise无论何时,何地,多次调用then,总能拿到成功时的数据

// 注意: Promise对象的创建过程是同步的, then函数的调用是异步的, 简单说peomise是异步的

Promise示例

// 需求: 在四个异步操作中打印四句话,而且要保证打印顺序
// setTimeout(() => {
//     console.log("窗前明月光")
// }, Math.random()*1000);
// setTimeout(() => {
//     console.log("疑似地上霜")
// }, Math.random()*1000);
// setTimeout(() => {
//     console.log("举头望明月")
// }, Math.random()*1000);
// setTimeout(() => {
//     console.log("低头鞋两双")
// }, Math.random()*1000);


// 方法一: 四个计时器嵌套, 上一个执行后再执行下一个
// setTimeout(() => {
//     console.log("窗前明月光");
//     setTimeout(() => {
//         console.log("疑似地上霜");
//         setTimeout(() => {
//             console.log("举头望明月");
//             setTimeout(() => {
//                 console.log("低头鞋两双")
//             }, Math.random()*1000);
//         }, Math.random()*1000);
//     }, Math.random()*1000);
// }, Math.random()*1000);

// 此方法有两个缺点: 
// 1, 代码多层嵌套造成结构复杂,可读性差
// 2, 四句打印的计时时间累加起来了, 降低效率


// 首先, 我们使用promise解决异步任务多层嵌套问题
// new Promise(function(resolve){
//     setTimeout(() => {
//         console.log("窗前明月光"); resolve() // 调用resolve以执行then
//     }, Math.random()*1000);
// }).then(function(){
//     return new Promise(function(resolve){
//         setTimeout(() => {
//             console.log("疑似地上霜"); resolve() // 调用resolve以执行then
//         }, Math.random()*1000);
//     })
// }).then(function(){
//     return new Promise(function(resolve){
//         setTimeout(() => {
//             console.log("举头望明月"); resolve() // 调用resolve以执行then
//         }, Math.random()*1000);
//     })
// }).then(function(){
//     return new Promise(function(resolve){
//         setTimeout(() => {
//             console.log("低头鞋两双"); resolve() // 调用resolve以执行then
//         }, Math.random()*1000);
//     })
// })


// 然后, 我们使用promise解决 多异步任务并发 的顺序问题
var p1 = new Promise(function(resolve){
    setTimeout(() => {
        resolve("窗前明月光")
    }, Math.random()*1000);
})
var p2 = new Promise(function(resolve){
    setTimeout(() => {
        resolve("疑似地上霜")
    }, Math.random()*1000);
})
var p3 = new Promise(function(resolve){
    setTimeout(() => {
        resolve("举头望明月")
    }, Math.random()*1000);
})
var p4 = new Promise(function(resolve){
    setTimeout(() => {
        resolve("低头鞋两双")
    }, Math.random()*1000);
})
// Promise有一个类函数all, 可以把多个promise对象合并成一个
var p = Promise.all([p1,p2,p3,p4])
// 当合并前的所有promise对象都调用resolve后, 才会调用合并后的then
p.then(function(array){
    // all合并后的then回调函数参数是一个数组, 数组中按照合并顺序依次获取每一个promise对象的成功数据
    console.log(array)
})

// 类函数: 就是使用类名调用的函数 如 all()
// 实例函数: 就是使用对象调用的函数  如 then()


// 总结: 说一下你对promise的理解?
// promise 是es6新增的一个类,主要用于解决项目开发中常见异步回掉地域问题,原理上是对回调函数的封装, 开发中经常用于多异步任务嵌套时和多异步任务并发时

async和await

// 在es6新增了一个关键字 叫 async 用于放在函数function前,修饰函数
function a (){
    console.log('a')
}
a()
// 在函数前添加async标记可以使此函数变为异步函数
async function b(){
    console.log('b')
}
b()
// 箭头函数也可以定义为异步函数
var c = async ()=>{
    console.log('c')
    return "彬哥" // 即使有返回值, 调用得到的也是promise
}
c()

// async异步函数的返回值总是一个promise对象
console.log(a())
console.log(b())
console.log(c())

async function d(){
    var p = new Promise(resolve=>{
        setTimeout(() => {
            resolve("成功")
        }, 1000);
    })
    // 调用then函数,在异步回调函数中获取数据
    p.then(data=>{
        console.log(1,data)
    })

    // await关键字一般放在promise对象前边, 等待promise对象成功的结果,一旦成功, 无需调用then, 而是通过同步返回值的形式拿到promise中的异步结果
    var res = await p
    console.log(2,res)
    // await 的作用就是让异步回调结构改成同步返回值结构,依然能拿到数据, 好处是简化代码结构, 减少嵌套, 优化语法结构 
    // await is only valid in async function  await只能在async函数中使用
}
console.log(d())

ES6模块化

  • 模块化: 把一个整体的js文件或代码块通过功能性分割成多个js文件或代码块, 这样每一个js文件都称之为一个模块, 然后通过固定语法导入/导出把多个js文件联系到一起, 这种操作,我们称之为模块化

  • html文件中使用script导入js算不算模块化?
    答: 不算, 因为模块化有一个显著特点,是作用域隔离, 各个模块用于各自独立的作用, 互不干涉, 用script导入js相当于把所有js拼到一起了,共享了同一个作用域,这种不能称之为模块化

  • 模块化语法:
    导出: export default data
    导入: import data from "path"

从模块myModule中导入数据
myModule.js

var count = 100

// 使用模块化语法把数据导出
export default count

index.js

import count from "./myModule.js"
// Cannot use import statement outside a module 
// 不识别import这个语法, 因为es6模块化语法是不能直接在node或浏览器执行的 
console.log(count)

es6模块化一般用于vue框架react框架

本文作者:咔斯Sama
本文链接:https://blog.kassama.top/webNotesES6.html
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可