JavaScript学习笔记

文章目录

一、JavaScript发展历程

编程语言,从上世纪50年代,就已经开始发展了

1950年前后,出现了用于科研的编程语言,如Fortran

1960年前后,出现了 肯·汤普森、丹尼斯·里奇 研发的C语言

  • 肯·汤普森和丹尼斯·里奇 一起研发了Unix操作系统
  • 1960~1962年,使用C语言重构了Unix操作系统

1983年前后,出现了C++语言

1989年,出现了Python语言

1992年前后,出现了Java语言

1995年,出现了JavaScript语言

近几年,陆续出现了swfit语言、go语言、Rust语言

JavaScript发展历程

  • 1990年,web网络应用开始出现(M国)
  • 2000年,国内引入各种网络硬件、软件…开始出现了国内的网络应用
  • 当时的网络速度:56K左右 | 下载速度28K,上传速度28K
  • 1992年,NetScape(网景)公司,研发了自己的浏览器(付费使用)(导航者navigator),占据了全球80%+的使用市场
  • 意识到了网络缓慢的问题
  • 如:用户注册、需要填写大量的内容才能注册账号…
  • 研发了自己的浏览器一侧的 用于数据验证的 编程(脚本)语言:LiveScript,短时间占据大量的开发市场
  • 1993年~1994年,Microsoft(微软)计划和网景公司合作(收购)
  • 没有成功
  • 微软开始 打压网景公司
  • 微软开始研发自己的浏览器explore(探险者):ie,号称自己的操作系统,不再对第三方浏览器保证兼容性
  • 1995年,网景公司,找寻 当时最厉害的sun公司(Java母公司)合作
  • LiveScript语言,更名:JavaScript
  • JavaScript语言在全球范围内出现了一波迅速发展的高潮期
  • 1996年前后,微软结合自己的ie浏览器,研发了自己的脚本语言
  • JScript
  • 1996年~1998年,sun公司联合NetScape公司,将自己的JavaScript捐献给了 欧洲计算机制造协会联盟
  • 欧洲计算机制造协会联盟:简称ECMA组织
  • ECMA组织,结合JavaScript语言,制定一套语言开发标准
  • 前端脚本语言标准出台:ECMAScript,简称ES语法标准,每年都会出一版新的语法标准**(日积月累)**
  • 比较出名的标准:ECMAScript5.0、ECMAScript 2015(ES6.0)
  • 行业中,ECMAScript(ES)语法,一般情况下就是指代JavaScript(JS)

总结:关于JavaScript

JavaScript是一个编程语言,工作在浏览器一侧,主要用于网页数据验证、网页特效开发、网页数据交互功能开发

  • 遵循ECMAScript语法标准,ES语法行业中一般指代JS
  • ECMAScript语法标准,每年都会出新的语法补充,比较重要的:ES6

关于标记语言和编程语言的区别?

标记语言:以HTML/css为代表,主要用于存储、展示数据;不能对目标数据执行运算功能
编程语言:可以针对数据执行加减乘除以及各种高级运算,可以执行数据运算完成生活中业务的模拟交易

结构 HTML

样式 CSS

交互 JavaScript

面试题:(了解)

1、什么是JavaScript

  • JavaScript是一个可以工作在浏览器中的脚本语言,可以完成和用户交互的行为,…

2、为什么要使用JavaScript

  • JavaScript可以实现网页和用户的交互过程,使用HTML/css无法实现交互的时候可以通过JavaScript实现

JavaScript是一门弱类型,解释型语言,由网景公司于1995年提出,简称JS,主要用于构建用户交互式网页,JS中一切皆对象

弱类型:


        
        // 弱类型解释:
        // 在js里面声明一个变量a。
        var a=100;
            a=true;
            a="张三";
            alert(a);

        var list = [10,"text",true];

        // 在java里面创建一个变量a,这个a呢,只能接收整数
        int a =100;
            a=true;

        // 解释型编程语言
		机器能够看懂的只有0 1   二进制机器码。
    

解释型语言:

计算机只能理解机器语言,不能理解高级语言,开发者使用高级语言编写的程序,需要经过编译变成机器语言后才能被计算机执行。编译型语言是指高级语言会先编译成机器语言,然后每次执行时直接执行机器语言;解释型语言是指每次运行时,将高级语言逐行编译为机器语言并执行。

面试题:(了解)

请简要描述解释型语言和编译型语言的区别?描述JavaScript为什么是解释型语言?

  • 解释型:代码解释一行,执行一行;需要一个解释语言的工具,目前前端开发领域中,对JavaScript解释性能最好的工具:Chrome V8 engine(谷歌公司的V8引擎:浏览器内置工具);解释型语言以JavaScript为代表
  • 编译型:一个工具软件将开发人员编写的代码,全部进行编译过程整理成可执行的目标文件,对应的操作系统/平台上直接运行目标文件的过程,以C语言为代表
  • 编译解释型语言:一个工具可以将编写的代码编译成目标文件,另一个工具专门用来运行目标文件;以Java为代表

笔试题:通过解释型语言的特性,解释下面代码的运行问题

// 2、代码中的操作
var name = "hello" // 记录姓名


var name = "world" 


alert(name + "姓名") // 结果?为什么会输出world

0 1 二进制机器码。

交互式网页:

<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>
</head>
<body>
    <span id="span1">这是网页显示的内容</span>
    <button type="button" onclick="text()">点击改变</button>
    <script>
        // 当用户点击页面中的某一个地方,页面会显示不同的元素。那么这个就是非常简单的交互式页面
        var s=document.getElementById("span1");
            function text(){
                s.innerText="测试内容";
            }
    </script>
</body>
</html>

二、基础语法

1.JS引入方式

  • 总结:企业项目开发中,推荐使用外联.js文件完成脚本代码的编写
    • 最大程度的提高代码的复用性
    • 将结构代码和程序代码分离,方便代码的维护
  • 一般禁止使用标签内嵌js代码;页面特殊的js代码可以使用页面内嵌

1.1 行内方式 (不推荐使用)

案例:

<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>
</head>
<body>
    <!-- 1.行内方式
        语法:HTML属性 on事件名称="js代码" 
        2.a标签的href属性也可以写js代码
    -->
    <div onclick="alert(123)">这是一个div</div>
    <a href="javascript:alert(100)">超链接</a>
</body>
</html>

1.2 内嵌方式

在页面任何位置都可以写入

案例:

<!-- 2.内嵌方式
        语法:<script>
                JS代码
            </script>
 -->
    <script>
        alert(123);
    </script>

 	<script type="text/javascript">
        alert(123);
    </script>

1.3 外联方式(推荐使用)

创建一个.js文件。在项目中添加script标签。引入js文件。

text.js

<script type="text/javascript" src="js/text.js"></script>

面试题:(了解)

1、简述js文件的编写规范?

  • 建议将js代码编写到.js文件中进行独立管理

2、简述htmljs代码可以出现的位置?

  • 出现的位置主要有三个地方,标签内嵌、页面内嵌、外部文件关联

3、下面的代码描述正确的是?( A )

A. <script src="./demo.js"></script>

B.<link href="./demo.js"></link>

C.<script src="./demo.js"/>

D.<script src="./demo.js"> alert("hello") </script>

2.JS中的注释

什么是注释:出现在代码中用于解释说明的文字,不会随着代码执行

  • 单行注释:主要针对一行或者多行代码的关键性描述
// 单行注释
  • 多行注释:主要针对一行或者多行复杂的代码,进行详细描述
/*
	多行注释
	多行注释
*/
  • 文档注释:一般出现在js文件中,描述文档开发作者、开发时间、功能描述等作用
/**
	文档注释
*/

面试题:(了解)

简要描述一下你们公司的注释使用规范?

  • 回答思路:首先回答注释的重要性(作用)、分别阐述三种注释不同的使用场景(使用基本规范)、最后说明自己公司开发项目的时候固定的注释内容

3.JS的输出方式

3.1 页面弹窗

代码弹窗方式
alert警告对话框
confirm确认对话框
prompt交互对话框

企业开发中,下面三个对话框偶尔在做代码错误排查的时候使用,项目中几乎不用!

案列:

// 警告对话框
alert("警告信息,一种重要的提示信息,暂停代码的向下执行,直到用户点击确定")

// 确认对话框
var res = confirm("针对用户的一些危险行为,进行提示,让用户确认自己的选择")
alert("用户的选择:" + res) // res: true / false表示真假两种行为

// 交互对话框
var pmp = prompt("提示信息,提示用户输入的文本内容", "默认数据")

3.2 数据输出

  • alert(xxx)将数据以弹窗的形式展示出来,经常用于代码错误测试打印数据
  • document.write(xxx):将数据在网页中输出,不论是错误调试或者项目开发,都严禁使用
  • console.log(xxx):将数据在浏览器的控制台中输出展示,使用频率最高

案例:

var name = "张三"
// 查看name变量中的数据
// 1.alert()
alert(name)		// 页面弹窗,阻止代码向下继续执行,一般很少使用(影响页面加载效率)

// 2.document.write()
document.write(name)	// 网页中直接输出数据,严禁使用;影响网页布局

// 3.console.log()
console.log("姓名数据:", name,"color:red") // 代码错误排查时,使用较多

3.3 页面交互

JavaScript在浏览器中开发,主要用于服务页面;通过代码获取标签、操作标签内容、操作标签样式

  • document.getElementById('btn'):获取页面中id="btn"的一个标签
  • div.innerHTML = xxx:设置标签中的文本内容
  • div.style.color = 'red':设置标签中的文本颜色

案例:

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  <div id="box">赳赳老秦,共赴国难</div>
  <button id="btn">按钮:设置div中的内容</button>
  
  <script>
    // 获取页面标签
    var _box = document.getElementById("box")
    var _btn = document.getElementById("btn")

    // 查看标签
    // console.log(_box)
    // console.log(_btn)

    // 查看标签中的内容
    // console.log(_box.innerHTML)
    // console.log(_btn.innerHTML)

    // 设置页面内容
    // 固定语法:点击_btn对应的按钮,执行后面function(){}花括号中的代码
    _btn.onclick = function() {
      // 修改div中的内容
      _box.innerText = "血不流干,死不休战"
      // 修改div的样式
      _box.style.width = "300px"
      _box.style.height = "200px"
      _box.style.backgroundColor = "orangered"
      _box.style.color = "white"
      _box.style.lineHeight = "200px"
      _box.style.textAlign = "center"
    }
  </script>
</body>
</html>

3.4 案例:页面弹窗

<!DOCTYPE html>
<html lang="zh">

<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;
    }

    html,
    body {
      width: 100%;
      height: 100%;
    }

    #dialog {
      position: absolute;
      display: none;
      /* display: flex;
      justify-content: center;
      align-items: center; */
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.2);
    }

    #box {
      margin: 200px auto;
      overflow: hidden;
      border-radius: 5px;
      width: 400px;
      height: 260px;
      box-shadow: #fff 2px 2px 3px;
      background: white;
    }

    #header {
      height: 50px;
      background: orangered;
      color: white;
      font-size: 18px;
      line-height: 50px;
      letter-spacing: 2px;
      padding-left: 20px;
    }
    .close{
      float:right;
      margin-right: 20px;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <button id="btn">点击显示登录</button>

  <!-- dialog:对话框的意思 -->
  <div id="dialog">
    <!-- box:盒子的意思 -->
    <div id="box">
      <div id="header">会员登录
        <span class="close" id="close">[X]</span>
      </div>
    </div>
  </div>

  <script>
    // 获取按钮标签
    var _btn = document.getElementById("btn")
    var _dialog = document.getElementById("dialog")
    var _close = document.getElementById("close")

    // 点击按钮,执行一些代码
    _btn.onclick = function() {
      // 点击了按钮后要执行的代码,写在花括号中间
      // 修改样式,显示
      _dialog.style.display = "block"
    }

    // 点击span标签,隐藏弹窗
    _close.onclick = function() {
      // 修改样式:隐藏
      // 排查错误的时候,关键的位置打印一些信息,通过这些信息的展示或者隐藏,判断错误
      // 出现在这行代码的前面或者后面,方便错误定位,方便错误排查
      // alert() / console.log()
      // alert("隐藏窗口")
      console.log("隐藏窗口")
      _dialog.style.display = "none"
    }
  </script>
</body>

</html>

思考题:页面中id="dialog"这个div我们如果使用了display: flex布局,页面效果开发中如何隐藏这个div?

隐藏页面标签的实现方式

  • display: none
  • visibility: hidden
  • opacity: 0

3.5 简易计算器

开发一个可以接受用户输入数值的表单,当用户点击计算按钮时得到运算结果

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  <div id="box">
    <input type="text" id="num1">
    <span>+</span>
    <input type="text" id="num2">
    <button id="btn">计算</button>
    <div>计算结果:<span id="result"></span></div>
  </div>

  <script>
    // 获取需要的标签
    var _num1 = document.getElementById("num1")
    var _num2 = document.getElementById("num2")
    var _btn = document.getElementById("btn")
    var _result = document.getElementById("result")
    
    // 单击按钮
    _btn.onclick = function() {
      // 获取数据(获取表单元素的数据,使用.value获取)
      var num1Value = _num1.value
      var num2Value = _num2.value
      console.log(num1Value, num2Value, "需要计算的数据")

      // 运算并输出结果
      // 网页中用户输入的任何数据,都是字符串,并不是数值;
      // 字符串加法运算时,会拼接;不会相加
      // var res = num1Value + num2Value
      // 字符串数据,可以通过固定语法parseInt(),转换成数值
      var res = parseInt(num1Value) + parseInt(num2Value)
      _result.innerText = res 
    }
  </script>
</body>
</html>

3.6 简易购物车

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  <ul>
    <li><img src="./images/face.webp" alt="" style="width: 200px;height: 200px;"></li>
    <li>商品名称:表情</li>
    <li>商品单价:<span id="price">1699.00</span></li>
    <li>购买数量:<input type="number" id="cnt" value="1"></li>
    <li>小计金额:<span id="result"></span></li>
  </ul>

  <script>
    // 获取标签
    var _price = document.getElementById("price")
    var _cnt = document.getElementById("cnt")
    var _total = document.getElementById("result")

    // 鼠标点击:onclick
    // 输入框数据变化:onchange
    // 键盘按下:onkeydown,键盘抬起:onkeyup
    _cnt.onchange = function() {
      // 获取购买数量,转化成整数
      console.log("购买数量:", _cnt.value)
      var _count = parseInt(_cnt.value)

      // 如果不做任何操作,用户可以输入负数(了解-可以通过选择结构完成判断)
      if(_count <= 0) {
        alert("购买数量不能小于1")
        _cnt.value = 1 // 将数据修改成1
        // return 关键字,表示代码不再向后执行,到return直接结束
        return
      }

      // 获取商品单价
      var _priceValue = parseInt(_price.innerText)

      // 计算小计金额
      var subtotal = _count * _priceValue

      // 输出小计金额
      _total.innerText = "¥" + subtotal + "元"
    }
  </script>
</body>
</html>

4.字面量

字面量:描述的是代码的字面意思,一般情况在JavaScript中表示字面意思的数据,如数字、字符串等等

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  <script>
    // 字面量:代码的字面意思,代码字面表示的数据
    // 12、1
    // 字面量,可以在代码中直接使用
    // alert(3.1415)
    alert(175)
    // alert(85)

    // 存在的问题:不能重复利用
    alert("饮料的价格:" + 5.00)
    alert("两瓶的价格:" + 5.00*2)  // 使用5.00字面量,需要重新编写

    // 思考:如何在代码中,重复的使用某个字面量数据?
  </script>
</body>
</html>

5.变量

5.1 什么是变量

变量(Variable):存储数据的容器,可以在代码中存储数据,然后通过变量名称重复使用这些数据

为什么要使用变量临时存储数据?

  • 已经学习过的数据,包括数值、字符串,都是字面量;字面量在使用的时候无法重复利用;可以通过变量存储字面量数据,通过变量名称就可以实现字面量的重复使用!提高数据的复用性

5.2 变量的声明

原生JavaScript中,有两种方式可以创建变量:

  • 可以直接通过一个自定义名称创建一个变量;
  • 使用var关键字创建变量(推荐)

声明了一个变量【尽管可以使用,但是项目规范中严禁使用】
如果没有变量的声明关键字,当js中出现大量代码时,我们无法定位这个变量什么位置被第一次声明
缺点:降低了代码的可读性

声明变量语法:

var 变量名;

给变量赋值:

变量名=数据;

输出变量值:

console.log(变量名);

声明变量简写方式:

  • 方式一

声明变量时直接初始化值

语法:

var a=数据;
  • 方式二

一次声明多个变量 分别给变量赋值

语法:

var a,b,c,d;
a=10;
b=11;
c=12;
d=13;
  • 方式三

一次声明多个变量 分别给变量赋值

语法:

var a,b=数据,c=数据;

var a,b=12;c=10;

案例:

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  <script>
    // 变量:Variable,表示临时存储数据的容器
    // 使用var关键字声明一个变量
    var pi = 3.1415926   // 使用变量pi存储了一个圆周率
    alert("圆周率: " + pi) // 通过变量名称,使用变量中存储的数据

    var price = 5.00  // 使用price(单价)存储一瓶饮料单价
    alert("饮料价格:" + price)
    alert("两瓶饮料价格:" + price * 2)

  </script>
</body>
</html>

关于es6中声明变量的操作

ES6语法标准中,提供了letconst用来声明变量和常量,主要用于补充原生JavaScript中的var关键字功能,相当于对变量的声明语法,提供了更多的功能扩展

5.3 命名规则

① 什么是标识符
用于表示数据的符号,由字母、数字、下划线、$组成,其中数字不能开头;标识符中包含了变量、关键字
② 什么是变量
变量是开发人员自定义的名称,可以是单词、可以是拼音
③ 什么是关键字
关键字就是编程语言中已经占用的单词,如var

语法要求(必须遵守):

  1. 由大写字母A~Z、小写字母a~z、数字0~9、下划线_和美元符号$组成,且数字不能开头。
  2. 变量名区分大小写,Aa 不是同一个变量。
  3. 不能使用关键字(常见的有typeofifelseforswitchcasedefaultfunctionwhiledo等)和保留字(常见的有classintdoublepublicstatic等)

5.4 命名规范

(可以不遵守,但建议遵守)

  1. 变量名采用纯英文单词书写。
  2. 使用小驼峰命名法书写:一个或者多个单词(拼音)组成,第一个单词(拼音)全部小写,后面每个单词(拼音)首字母大写
  3. 不要使用汉字为标识符命名。(可以使用,但是不规范)
<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  
  <script>
    // 这四个变量,分别表示了什么意思?
    var a = 12
    var b = 80
    var c = 180
    var d = 1

    // 这四个变量,分别表示了什么意思?
    var shenGao = 178
    var tiZhong = 80
    var xingBie = 1
    var nianLing = 16     // ninaLing(【小】驼峰命名法)   NianLing(大驼峰命名法 | 帕斯卡命名法)

    // 这四个变量,分别表示了什么意思?
    var height = 180
    var weight = 75
    var gender = 0
    var age = 20


    // 下面两个变量,那个变量语法更加人性化/更容易阅读
    var xian = "xxxx"

    var xiAn = "xxxxx"
    var xian = "xxxxx"

    var gerenjieshao = "........"
    var geRenJieShao = "xxxxxxxx"

    var personalIntroduce = "......"
    var personalintroduce = "xxxxxx"
  </script>
</body>
</html>

5.5 变量的赋值

变量作为一个存储数据的容器,需要添加数据之后才能正常访问,数据访问方式主要有:存储数据、查询数据、修改数据以及删除数据

变量中存储数据的方式就是变量的赋值操作,需要使用 赋值运算符:=

 // 1、赋值方式(默认)
    // 使用赋值语句,给单个变量中存储数据
    var version = "V1.0.0"
    console.log("version:", version)

    // 2、连续赋值
    // 项目开发中使用到多个变量,初始数据都是一致的
    // 1 1 2 3 5 8... 斐波那契数列
    // 基本赋值
    var n1 = 1
    var n2 = 1
    console.log("n1:", n1, ",n2:", n2)

    var n3 = n4 = 1
    console.log("n3: ", n3, ", n4:", n4)

    // 3、项目中某些场景下,多个变量初始数据不一致
    var name = '张三', age = 20, gender = '男'
    console.log('name:', name, ", age:", age, ", gender:", gender)

    // 4、注意的问题:关于变量的交叉赋值
    // var name, age = '张三', 28 
    // 期望  name="张三" age=28; js语法中不支持

面试题:关于变量的赋值操作

下面的变量赋值语句,正确的是? ( ABC )

A. var _name = "damu"

B. var name = "damu", age = 20

C. var num1 = num2 = 10

D. var name, age = "张三", 28

5.6 变量的使用

项目中的数据操作,根据操作方式主要区分为两种

  • 数据的操作:数据作为一个独立的整体,可以执行存储、查询、修改、删除,简称增删改查
    • 增删改查:简称CRUD
    • C:Create 增加、R:Retrieve 查询、U:Update 修改、D:Delete 删除
  • 数据的运算:数据和数据之间,通过运算符执行运算,一般都是基础的加减乘除

变量的使用,区分增加、修改、查询和删除的操作

  • 增加:声明变量赋值的过程
  • 查询:通过变量名称,获取变量中数据的过程
  • 修改:给指定的变量重新赋值的过程
  • 删除:
    • 业务删除:项目开发中,约定变量中存储一个无效数据,表示该数据被删除;变量依然存在
    • 真实删除:项目代码中,使用delete关键字针对变量进行物理删除,很容易造成代码稳定性问题,语法上受到一定的限制,如不能直接删除var声明的变量
<script>
    // 声明变量
    // 声明变量的同时可以赋值;也可以声明变量以后再进行赋值
    var myName;   // 等价于:var myName = undefined(未定义)
    console.log("myName:", myName)

    // 赋值:增加数据
    myName = "Wendy"
    console.log("myName:", myName)

    // 修改数据:给变量中存储新的数据,覆盖旧的数据
    myName = "文帝"
    console.log("myName:", myName)

    // 删除数据:对于已经不再使用的变量,需要删除变量释放占用的系统资源
    // 业务中的删除,并不建议直接删除变量,而是给变量赋值一个(开发规范)约定的空值
    // 1- 约定空字符串,表示删除了数据
    // 2- 约定undefined,表示删除了数据
    myName = ""
    console.log("myName: ", myName)

    // 只有在特殊的情况下,才会真实删除变量
    // 直接删除变量的操作是一种敏感并且危险的操作: 变量一旦真实删除,代码中再次使用很容易出现问题
    // delete语句对于var声明的变量,目前语法上不支持删除DontDelete
    // delete myName
    // console.log("myName delete:", myName)

  </script>

5.7 变量预解析

什么是预解析:

预:预备、预先的意思

解析:浏览器读取变量的声明语句,将变量声明在代码中的意思

// 练习1
// 项目中我想使用班级的名称 
console.log("班级名称:", className)
// Uncaught Reference Error: className    is not defined
// 未捕获的  引用       错误:className变量  没有    定义
// 一旦程序报错,后面的代码不会执行(程序崩溃退出)


// 练习2
// 项目中变量的使用规则:先声明后使用
var className = "普通班"
console.log("班级名称:", className)


// 练习3
// 变量的预解析 
console.log("班级名称:", className) // undefined,没有报错?!
var className = "普通班"
console.log("班级名称:", className) // "普通班"


// 练习4
// 为什么没有报错?var关键字声明的变量,存在预解析功能
// 预解析:也称为变量提升,将变量的声明语句提升最前面,赋值还在原来的位置
// 上面的代码,等价于:
var className; // 变量预解析:提升了变量的声明,保障当前程序代码运行正确性(容错性)
console.log("班级名称:", className) // undefined,没有报错?!
className = "普通班"
console.log("班级名称:", className) // "普通班"

三、数据类型

1.认识数据类型

什么是软件?

计算机术语:计算机中一堆可执行指令的集合

行业:软件是计算机操作系统上安装的可以处理业务数据的计算机程序

软件的核心?

软件,是为了解决生活中的问题出现的!

软件的核心就是处理生活中的问题

处理生活中的问题的必要条件?

处理生活中的问题,首先还原生活场景

如:处理商品交易业务,通过软件模拟商店、模拟商品、模拟货币,完成交易

软件如何模拟生活场景?生活场景过度复杂

模拟生活中的场景,表示生活中的各种事物,软件代码中定义一种语法:基本数据类型

基本数据类型:可以描述一些基础数据,并且可以通过大量基本数据类型组合起来描述复杂类型

就可以通过软件代码中一些简单的基本类型,描述生活中的各种事物

编程体系中出现了一种基本语法:数据类型

什么是数据类型

可以表示各种数据的类型的概念

编程语言中,通过具体的代码,描述对应的数据类型!

JS到目前为止,没有提供任何内置的用于精确获得数据类型的方式。

使用typeof这个关键字,可以得到一个字符串,方便我们对一个表达式的数据类型进行初步判断。

2.基本数据类型(掌握)

数据类型说明
Number数值类型
String字符串类型
Boolean布尔类型
Null空值
Object对象类型
Undefined未定义

number

​ 可以存储数字【整数,小数】

JS中八进制前面加0,十六进制前面加0x

String

​ 可以存储任意【数字,中文,字母,符号】
​ 注意:必须写在双引号里面

数值相加,字符相连

boolean

​ 里面存储的只有两个数据 true【真】,false【假】。

Object

​ null: 表示为空【引用数据类型】

undefined

​ 表示变量没有初始化,未定义的变量

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script type="text/javascript">
    var a=12;
    console.log(typeof a); //number  数据类型

    a="你好";
    console.log(typeof  a);//String  字符串类型

    a=true;
    console.log(typeof  a);//boolean  布尔类型

    a=null;
    console.log(typeof  a);//Object  对象类型

    var b;
    console.log(typeof  b);//undefined类型


</script>
</body>
</html>
// String 字符串类型,可以使用双引号、单引号包含起来的一串字符
// 开发规范中:一般推荐或者要求使用单引号包含的语法
// 描述一个人的姓名
var name = "廉颇" // var name = '廉颇'
console.log('姓名:',name)

// Number 数值类型,包含整数和小数(浮点数)
// 描述一个人的身高
var height = 1.75
// 描述一个人的体重
var weight = 80
console.log('height身高:',height)
console.log('weight体重:',weight)

// Boolean 类型,布尔类型,只有两种取值:true / false
// 描述一个人是否存活|该用户账号是否可用
var status = true   // false
console.log('status可用:',status)

// undefined:表示无效数据,未定义数据
// 描述一个无效数据
var jobs;   // var jobs = undefined
console.log('jobs工作:',jobs)

// null:表示空值,表示一种没有任何数据的状态
// 描述一个空数据
var address = null
console.log('address地址:',address)

3.复杂数据类型(了解)

原生JavaScript中也提供了一些复杂数据类型,用于描述一些较为复杂的事物,如:常见的复杂类型

  • Array:数组
  • Function:函数
  • Object:对象
  • Math:处理数学运算的类型
  • Date:处理日期时间的类型
  • RegExp:处理正则表达式的类型
  • UUID:处理唯一数据的类型

代码中的简单操作:

 // 复杂类型的基本使用
// 1、数组
var names = ["老王", "小李", "大黄", "小灰"]
console.log(names)

// 2、日期
var date = new Date()
console.log("今年是:", date.getFullYear(), ",月份:", date.getMonth() + 1)

// 3、随机数:得到一个验证码
var rcode = Math.random().toString(36).substr(2, 6)
console.log("随机验证码:", rcode)

4.查看类型

5.引用数据类型

项目开发中,经常会出现各种类型的数据,如果对数据类型没有明确的情况下,代码很容易出现问题:

如:案例-简易计算器中,从页面中获取的数值,参与运算后才发现参与运算的数值属于字符串类型(BUG
项目中,我们如何对目标数据进行类型的查看呢?

  • typeof(dat):简易的数据类型查看方式,适用于大部分场景
  • Object.prototype.toString.call(dat):数据类型原型查看方式,有争议的情况下可以使用
// 定义基本类型
var name = "耀"
console.log(name, typeof name)  // 耀 string

var hero = "娜可露露"
console.log(hero, typeof(hero)) // 娜可露露 string

var height = 20
console.log(height, typeof(height)) // 20 'number'

var pi = 3.1415
console.log(pi, typeof(pi))  // 3.1415 'number'

// status 单词,和前面用过的name一样,浏览器软件里面已经使用过这个变量
var sts = true
console.log(sts, typeof(sts)) // true  'boolean'

var address = undefined;
console.log(address, typeof(address))  // undefined 'undefined'

var intro = null
console.log(intro, typeof(intro)) // null 'object'
// 基本类型中存在Null类型,为什么这里打印object类型?有争议的类型
console.log(intro, Object.prototype.toString.call(intro)) // null '[object Null]'


// 复杂类型
var names = ["李信", "吕布"]
console.log(names, typeof(names)) // ['李信', '吕布'] 'object'
console.log(names, Object.prototype.toString.call(names)) // ['李信', '吕布'] '[object Array]'

var date = new Date()
console.log(date, typeof(date)) // 
console.log(date, Object.prototype.toString.call(date)) //

6.类型转换

项目中原生JavaScript数据的表示方式,同一个数据可能会以不同类型的形式表示出来;进行数据运算(加减乘除)的时候很容易出现错误运算结果;需要掌握类型的转换技术

  • 转换成字符串
    • 字符串拼接
    • String(dat)
    • dat.toString()
  • 转换成数值
    • Number(dat)
    • parseInt(dat)
    • parseFloat(dat)
  • 转换成布尔(字符串、数值、null/undefined
    • Boolean(dat)
// 同一个数据,可以是不同的类型
// var n1 = 3.14   // number
// var n2 = '3.14' // string

// var b1 = true     // boolean
// var b2 = 'false'  // string

// 需要进行类型转换(大部分类型转换都是基本类型的转换)
// 练习1、将其他类型转换成字符串类型
var x = 12
console.log(x, typeof(x))

var x1 = x + ''
console.log(x1, typeof(x1))
var x2 = String(x)
console.log(x2, typeof(x2))
var x3 = x.toString()
console.log(x3, typeof(x3))

var b = true
var b1 = String(b)
console.log(b1, typeof(b1))   // 'true'  string
var n = null
var n1 = String(null)
console.log(n1, typeof(n1))   // 'null'  string
var u = undefined
var u1 = String(u)
console.log(u1,  typeof(u1))  // 'undefined' string

// 练习2、转换成数值
var age = '20.01'
console.log(age, typeof(age))  // '20' string

// 转换成数值
var a1 = Number(age)
console.log(a1, typeof(a1))  // 20.01 number

// 转换成整数
var a2 = parseInt(age)
console.log(a2, typeof(a2))  //  20 number

// 转化成浮点数
var a3 = parseFloat(age)
console.log(a3, typeof(a3)) //  20.01 number

// 特殊转换
var money = "200元"
var m1 = parseInt(money)
console.log(m1, typeof(m1))  //  200 number

money = "¥200元"
m1 = parseInt(money)
// NaN(具体数据): not a number不是一个数值;属于数值类型
console.log(m1, typeof(m1))  //  NaN  number

// 其他类型
// 布尔类型,true -> 1;false -> 0
var b = true
var b1 = Number(b)
console.log(b1, typeof(b1))  //  1  number

// null 和 undefined
var n = null
var n1 = Number(n)
console.log(n1, typeof(n1), "Number") //  0 number
var n2 = parseInt(n)
console.log(n2, typeof(n2), "parseInt") // NaN number

var u = undefined
var u1 = Number(u)
console.log(u1, typeof(u1))  // NaN number
var u2 = parseInt(u)
console.log(u2, typeof(u2))  // NaN number

// 练习3、布尔类型
// 字符串转换布尔类型 
// 空字符串-> false,非空字符串->true
var s = ""    // 空字符串
var s2 = "  "  // 包含空白字符的字符串
var s3 = "helloworld" // 非空字符串

var s01 = Boolean(s)
console.log(s01, typeof(s01)) // false boolean

var s02 = Boolean(s2)
console.log(s02, typeof(s02)) // true boolean

var s03 = Boolean(s3)
console.log(s03, typeof(s03)) // true boolean

// 数值转换成布尔类型
// 0-> false, 非0-> true
var n1 = -10
var n2 = 0
var n3= 10

var n01 = Boolean(n1)
console.log(n01, typeof(n01)) // true, boolean

var n02 = Boolean(n2)
console.log(n02, typeof(n02)) // false booelean

var n03 = Boolean(n3)
console.log(n03, typeof(n03)) // true boolean

// null和undefined
var n = null
var n01 = Boolean(n)
console.log(n01, typeof(n01)) // false 'boolean'

var u = undefined
var u01 = Boolean(u)
console.log(u01, typeof(u01)) // false 'boolean'

7.显式/隐式转换

项目中经常会有很多地方,出现类型的自动转换,导致数据的类型不确定的情况出现,所以对于类型的转换方式需要有一定的掌握程度

关于类型转换和项目中的使用方式,小总结

  • 需要掌握常见的隐式类型转换的场景
  • 自己开发的项目中,如果要对数据执行运算操作,建议使用显式类型转换,准确的定位数据的类型然后参与运算,不要依赖代码中提供的隐式转换功能!
// 加法运算:参与运算的数据,无法执行隐式转换,所以得到错误结果
// 通过固定语法,将类型进行转换后完成数据运算:显示类型转换
// 1.
var price = '20'
var total = price + price
var totalx = parseInt(price) + pasreInt(price) // 显式转换
console.log('total:', total)  // total: 2020 期望以外的错误结果(代码没有报错)

// 数据的隐式类型转换:数据参与运算时,类型在运算过程中进行了自动匹配转换

// 2. 字符串和数值执行乘法运算时,出现了类型自动转换(字符串-> 数值-> 参与运算)
var price2 = '30'
var cnt = 2
var total2 = price2 * 2 // 字符串 乘以 数值
console.log('total2:', total2) // total2: 60

// 3. 字符串和字符串执行减法运算时,出现类型自动转换(字符串-> 数值-> 参与运算)
var pay = '180'
var money = '200'
var balance = money - pay  // 字符串 减法 字符串
console.log("找零:", balance) // 找零: 20


// 4. 数值执行保留小数位数操作时,出现类型自动转换(数值-> 字符串)
var pi = 3.1415926
var pi2 = pi.toFixed(2) // 保留两位小数位数
console.log(pi2, typeof(pi2)) // 3.14 string

true在进行数学运算时可以看作1,false在做数学运算时可以看作0。

案例:

 //通过隐式转换把true转换为了1
    console.log(1==true);//true
    //通过隐式转换把false转换为了0
    console.log(1===true);//false

	/**
	理解==或===的区别
	==会把比较的二者进行

如:0==false;//true,会把0转成bool值进行比较
   1==true;//true,同样把1转成bool值再和true进行比较
	===是不会把比较的二者进行类型转换,是string就是string,是number就是number
如:0===false;//false,因为0是number,false是boolean,两者就肯定不相等
   1===true;//false
	
	*/

四、运算符

运算符Operation,主要用于描述数据之间执行运算的符号,编程语言中包含的运算符:

  • 赋值运算符
  • 算术运算符
  • 混合运算符
  • 比较运算符
  • 逻辑运算符
  • 三元运算符
  • 位运算符

1.关于数据的表示

编程语言中,一般处理数值数据,会有不同的进制表示方式:

  • 二进制(逢二进一):0, 1, 10, 11, 100, 101, 110, 111...
  • 八进制(逢八进一):0,1,2,3,4,5,6,7,10,11,12,13,14,15,16,17,20....
  • 十进制(逢十进一):0,1,2,3,4,5,6,7,8,9,10,11,12,...
  • 十六进制(逢十六进一):0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,10,11,12,....
// 二进制:存储数据时,以0b/0B开头的数值,描述二进制数据
var b = 0b1111
console.log(b)    // 15

// 八进制:存储数据时,以0o/0O开头的数值,描述八进制数据
var o = 0o10
console.log(o)

// 十进制
var d = 12
console.log(d)   // 12

// 十六进制
var x = 0xF1
console.log(x)   // 241

2.赋值运算符

符号描述
=将等号右侧的数据,赋值给左侧的变量
+=先加后赋值
-=先减后赋值
*=先乘后赋值
/+先除后赋值
%=先取模后赋值
// 赋值操作
var name = "Wendy"

3.算术运算符

运算符说明
+两个数相加
-两个数相减
*两个数相乘
/两个数相除
%取模
++自增
- -自减

代码操作:

// 2、算术运算符
var n1 = 12 
var n2 = 5

console.log(n1 + n2) //  17
console.log(n1 - n2) // 7
console.log(n1 * n2) // 60
console.log(n1 / n2) // 2.4
console.log(n1 % n2) // 2(整除的情况下得到的余数)

// 自增运算
n1++      // 独立出来的,++符号放在前面和后面没有区别
console.log('n1',n1)  // 13
++n1
console.log('n1',n1)  // 14

// 自增赋值
var x1 = n1++   // 先赋值,后加加
console.log(x1,',x1, ', n1, ",n1") // 14 ',x1, ' 15 ',n1'

var x2 = ++n1   // 先加加,后赋值
console.log(x2, ',x2, ', n1, ",n1") // 16 ',x2, ' 16 ',n1'

// 思考:自减运算应该如何操作?运算过程和自增运算是否一致?

注意事项:算术运算符可以和赋值运算符进行混合使用

符号描述
+=a += 1
等价于
a = a + 1
// 2.1、混合运算符
var num = 12
// num += 10
num = num + 10
console.log(num, ": num")

字符串拼接运算符 +

字符串拼接从左往右,如果没有遇到字符串,那么数值相加,如果遇到一个字符串,那么全部拼接

​ 当+两边任意一边为字符串时,+做字符串拼接运算;当+两边都是数字时,+做数学运算。

var a = "ab" + "cd" //a的值是abcd
var b = "test" + 50 //b的值是test50
var c = "30" + 50 //c的值是3050
var d = 30 + "50" //d的值是3050
var e = 30 + 50 //e的值是80,这里是数学运算

var g = 20
var e = g + "ef" //e的值为20ef,作为变量使用,不要加引号
var h = "g" + "ef" //h的值为gef

var myName = "张三"
var myAge = 29
var desc = "我是" + myName + ",今年" + myAge + "岁了。"

//字符串拼接运算也能使用 += 的形式
var test = "abc"
test += "def"
console.log(test) //abcdef
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    var a=1;
    console.log(a+1);//2

    console.log(a-1);//0

    console.log(a*1);//1

    console.log(a/1);//1



    console.log(4%2);//0
    console.log(4%3);//1

    console.log("a="+a);// a=1;
     var i= 1;
    //var j= i++; //++在后,是先赋值后自增   j=i   j=i+1;  变量赋予的是旧值,也就是1
    var j= ++i; //++在前:先自增后赋值   i=1+i   j=i    变量赋予的是新值  也就是2.
    console.log("j="+j);

    var b=12.3;
	//把小数转换为整数。
    console.log(parseInt(b));

</script>


</body>
</html>

++在后,是先赋值后自增 j=i , j=i+1; 变量赋予的是旧值,也就是1

++在前:先自增后赋值 i=1+i , j=i 变量赋予的是新值 ,也就是2.

–同上。

4.比较运算符

项目中经常做一些数据的比较操作,通过返回的数据(布尔类型的)体现比较的结果(true | false

比较运算符返回的结果是布尔值。

运算符说明
>大于
>=大于等于
<小于
<=小于等于
==比较两个值是否相等
===比较两个值以及类型是否相等
!=两个值不等于
!==两个值以及类型不等于
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <script type="text/javascript">
    var a=3,b=4;
    console.log(3>4); //false
    console.log(3>=4); //false
    console.log(3<4); //true
    console.log(3<=4);//true



    console.log(3=="3");//true
    console.log(3==="3");//false
    console.log(3!="2");// true
    console.log(3!=="2");//true
        
    
    </script>
</body>
</html>
 // 3、比较运算符
var age = 17      // 真实年龄
var verify = 20   // 限制年龄

console.log(age > verify)  // false:age不大于verify
console.log(age >= verify)  // false
console.log(age < verify)  // true:age数据小于verify数据
console.log(age <= verify) // true

age = 20
console.log(age == verify) // true 相等
console.log(age != verify) // false

age = '20'
console.log(age == verify) // true age中的数值和verify数值相等
console.log(age === verify) // false: age和verify,数据类型或者数值不相同
console.log(age !== verify) // true

// 字符串,通过ascii码(整数)表示
// 字符串进行比较运算时,自动通过ascii码进行判断
var c1 = "a"    // 字母a ascii: 97
var c2 = "b"    // 字母b ascii:98
console.log(c1 > c2) // false,"a"不大于"b"

// 字符串中包含多个字符时,逐位比较
var c3 = "ab"
var c4 = "abc"
console.log(c3 > c4) // false

5.逻辑运算符

项目中如果同时出现多个条件比较时,需要多个条件并且关系、或者关系,取反的关系,将多个条件合并起来进行处理,使用到逻辑运算符

逻辑运算符返回的结果是布尔值。

符号描述
&&并且关系,多个条件同时为true返回true
//或者关系,多个条件只要有一个为true返回true
!取反

代码操作:

// 4、逻辑运算符
// 账号+密码,同时正确,表示登录成功
var uname = "admin"
var upass = "123"

// 判断账号密码是否正确
console.log("admin" === uname && "1234" === upass) 
// true:账号密码正确
// false:提示账号或者密码有误

// 用户可以使用账号或者手机号码登录
var uname = "admin"
var uphone = "15899990000"
var upass = "123"
console.log(
  ('admin' === uname || '15899990000' === uphone)
  &&
  "123" === upass
) // true: 账号|手机号码 + 密码输入正确
// false:账号|手机号码  或者 密码有误


// 注册一个账号,判断账号是否合法
var account = "admin" // 模拟用户输入
console.log(Boolean(account)) // false,提示-注册账号不能为空
// true,用户输入了账号,可以继续注册
console.log(!Boolean(account)) // 和上一行代码的结果刚好相反,为了方便明天要学的合法性if判断

<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>
</head>
<body>
    <script>
        var a=4,b=5,c=6,d=7;
        // 逻辑运算符  &&   于        true && true    结果为true    false && true  结果为false
        //            ||   或        (只要有一个是真就是真,两个都是假才是假)
        console.log((a<b) && (c<d));//true 小括号指把这一部分看作整体   两边都成立true,
        console.log((a>b) && (c<d));//false 两边其中一边不成立false


        console.log((a>b) || (c<d));//true
        console.log((a>b) || (c<d));//true
        console.log((a>b) || (c>d));//false
        

    </script>
</body>
</html>

6.三元运算符

编程语言中提供了一种特殊的符号,可以执行简单的判断操作:三元运算符

语法:

表达式 ?1:值2;

判断表达式的值,如果值为true,则取值1,如果为false,则取值2.

代码操作:

// 5、三元运算符
var uname = "admin"
var upass = "123"

var name = prompt("请输入账号:")
var pass = prompt("请输入密码:")

name === uname && pass === upass ? alert("用户登录成功"): alert("账号或者密码有误")

7.位运算符(了解)

项目中所有的代码里面的数据运算,最终都会交给计算机中的CPU运算,CPU里面的运算都是二进制数据的运算;代码中的运算过程,二进制运算表达式性能最高!位运算符就是专门提供给二进制的运算符号

符号描述
&与运算,1 - 1 -> 1、1 - 0 -> 0 、0 - 0 -> 0
eg: 1 & 2 => ?
eg: 01 & 10 => 00
\或运算:1 - 1 -> 1、1- 0-> 1、0 - 0 -> 0
`eg: 1
^异或运算:1-1-> 0、0-0-> 0、1-0-> 1
>>右移运算,100 -> >> -> 010
4 4>>1 2
<<左移运算,010 -> << -> 100
2 -> 2<<1 -> 4

五、程序结构

1.认识程序结构

程序结构,描述了业务处理流程,反映到代码中就是代码的执行顺序/过程;常见的程序结构

  • 顺序结构:代码从上到下逐行执行
  • 选择结构:根据某个指定的条件,决定运行指定的代码块
  • 循环结构:根据某个指定的条件,决定是否重复执行某个代码块

JavaScript中针对选择结构,提供了两种语法:

  • if-else选择结构
  • swtich-case选择结构

JavaScript针对循环结构,提供了多种语法:

  • for循环
  • while循环
  • do-while循环
  • for..in循环

编程语言一旦出现了程序结构,执行流程就会变得复杂,一些复杂执行过程经常需要配合图解的方式进行说明,这种画图的方式:UML流程图

2.if-else选择结构

单分支结构

​ 语法:

if(条件表达式){
	代码块;  //当括号里面的条件表达式为true时,执行代码块
}
var a=10;
        if(a<11){
            console.log("执行了代码块") //当括号里面的条件表达式结果为true时,执行代码块。
        }

双分支结构

语法:

if(条件表达式){
 代码块; //当条件表达式为true时,执行此代码块
 }else{
 代码块;  //当条件表达式为false时,执行此代码块
 }
var a=10;
        if(a>11){
            console.log("条件表达式为true时,执行此代码块") //当括号里面的条件表达式结果为true时,执行代码块。
        }else{
            console.log("条件表达式为false时,执行此代码块")
        }

多分支结构

语法:

if(条件表达式1){
		代码块;
 }else if (条件表达式2){
 		代码块;
}else{
 		代码块;
}
 var score2 = 98
if(score2 > 0 && score2 < 60) {
  console.log("不及格")
} else if(score2 >= 60 && score2 < 80) {
  console.log("及格")
} else if(score2 >= 80 && score2 < 90) {
  console.log("良好")
} else if(score2 >= 90 && score2 <= 100) {
  console.log("优秀")
} else {
  console.log("成绩不合法")
}

嵌套结构

 语法:
            if(条件表达式){
                代码块;
                if(条件表达时){
                    代码块;
                }else{
                    代码块;
                }
            }else if(条件表达式){
                代码块
            }else{
                代码块
            }
// 关于是否重修
var score = 40
if(score > 0 && score < 60 ){
  	console.log("不及格")
  // 嵌套选择结构:40分以下留级、40分以上继续学习
  	if(score > 0 && score < 40) {
    	console.log("留级")
  	} else {
    	console.log("继续学习,天天向上")
  	}
} else {
  	console.log("及格")
}

需求:判断成绩小于60的控制台输出不合格,60-80的输出中等,80-100的输出优秀。

3.switch-case选择结构

3.1 基本语法

主要用于等值匹配

 <!DOCTYPE html>
<html lang="zh">

<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>
</head>

<body>
  <input type="text" id="answer" placeholder="请输入答案(A/B/C/D)">
  <button id="btn">验证答案是否正确</button>
  <script>
    // 用户进行选择判断
    var _btn = document.getElementById("btn")
    var _an = document.getElementById("answer")
    

    _btn.onclick = function () {
      // 获取了用户输入的答案
      var _val = _an.value 
      // switch-case基本语法
      // 将_val变量中的数据,和case后面的值进行相等判断,相等的话就执行对应case中的代码
      switch (_val) {

        case 'A':
          console.log("不好意思,你答错了")
          break

        case 'B':
          console.log("Congratulations,答对了")
          break

        case 'C':
          console.log("错误答案,再检查检查")
          break

        case 'D':
          console.log("这也是错误的结果呀")
          break

        default:  // 所有数据都不匹配的情况下
          console.log("没有这个选项")
      }
    }


  </script>
</body>

</html>

3.2 case穿透问题

当某个case语句中,省略了/丢失了break关键字,造成case语句直接向下执行(对下一个case条件不做判断),造成的问题就是case穿透问题,如:

// 用户答案
var value = "A"

switch(value) {

  case 'A':
    console.log("用户选择了A,错误答案")
    // break

  case 'B':
    console.log("选择B,恭喜您答对了")
    break

  case 'C':
    console.log("选择了C?你确定,错了")
    break

  case 'D':
    console.log("D这个答案,也是错的")
    break

  default:
    console.log("没有这个选项")
}

// 执行结果
// 用户选择了A,错误答案         case 'A'中丢失了break
// 选择B,恭喜您答对了           case穿透执行....

注意事项:任何问题,都有两面性;可能会存在问题,同时也有自己的适用场景!

3.3 案例:行车限号判断

需求:周一1/6、周二2/7、周三3/8…、周六周日不限号

// 车牌尾号
var num = "1"

// 查询周几限号
switch(num) {

  case '1': // 当尾号为1的时候,穿透执行case 6的代码
  case '6':
    console.log("周一,限号尾号1或者6")
    break

  case '2':
  case '7':
    console.log("周二,限号尾号2或者7")
    break

  case '3':
  case '8':
    console.log("周三,限号尾号3或者8")
    break

  case '4':
  case '9':
    console.log("周四,限号尾号4或者9")
    break

  case '5':
  case '0':
    console.log("周五,限号尾号0或者5")
    break

  default:
    console.log("没有这个尾号...")
}

3.4 案例:基础版-石头剪刀布

<!DOCTYPE html>
<html lang="zh">

<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>
</head>

<body>
  <input type="text" id="user" placeholder="请输入您的招数(石头|剪刀|布)">
  <button id="btn">判断</button>

  <script>
    var _btn = document.getElementById("btn")

    // 1、记录用户输入
    var _user = document.getElementById("user")
    var _userChuzhao = ""
    // 添加一个输入改变事件 onchange输入框中的数据发生变化就会产生的事件
    _user.onchange = function () {
      _userChuzhao = _user.value
      // alert("用户出招:" + _userChuzhao)
    }

    _btn.onclick = function () {
      // 2、记录 程序自动生成的招数(1-石头 2-剪刀 3-布)
      // Math.random() 生成一个0~1之间的随机数
      // Math.random()*3 生成一个0~3之间的随机数
      // Math.ceil() 向上取整 0.1-> 1   2.2-> 3   1.3-> 2
      var _computer = Math.ceil(Math.random() * 3)
      var _comChuzhao = ""
      if (_computer === 1) {
        _comChuzhao = "石头"
      } else if (_computer === 2) {
        _comChuzhao = "剪刀"
      } else if (_computer === 3) {
        _comChuzhao = "布"
      }
      // alert("电脑出招:" + _comChuzhao)

      // 3、判断 谁输谁赢
      if( (_userChuzhao === "剪刀" && _comChuzhao === "布") ||
          (_userChuzhao === "石头" && _comChuzhao === "剪刀") ||
          (_userChuzhao === "布" && _comChuzhao === "石头")
        ) {
        alert("用户出招(" + _userChuzhao + "); 电脑出招(" + _comChuzhao +");玩家胜出")
      } else if(_userChuzhao === _comChuzhao) {
        alert("用户出招(" + _userChuzhao + "); 电脑出招(" + _comChuzhao +");平局")
      } else {
        alert("用户出招(" + _userChuzhao + "); 电脑出招(" + _comChuzhao +");电脑胜出")
      }
    }

  </script>
</body>

</html>

3.5 案例:进阶版-图形界面

步骤

  • 记录用户输入
    • 页面中展示三张图片,用户点击选择出招
    • 用户点击了某个图片,用户选择了出招
  • 电脑自动出招
    • 模拟—1-石头 2-剪刀 3-布,随机出现一个整数
    • 根据不同的整数,判断电脑的出招招数
    • 根据电脑出招招数,展示对应的图片
  • 判断:谁输谁赢

代码实现:

<!DOCTYPE html>
<html lang="zh">
<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>
    .user p, .com p, #result p{
      font-size: 22px;
      font-weight: bolder;
    }
    .user img, .com img, #result img{
      width: 200px;
      height: auto;
    }
  </style>
</head>
<body>
  <div class="user">
    <p>用户:点击对应的图片选择自己的出招</p>
    <img src="./images/shitou.png" alt="" id="shitou">
    <img src="./images/jiandao.png" alt="" id="jiandao">
    <img src="./images/bu.png" alt="" id="bu">
  </div>

  <div class="com">
    <p>电脑:电脑出招随机出现的,当用户点击了判断按钮,电脑就可以出招</p>
    <img src="./images/loading.png" alt="" id="com-img">
  </div>

  <button id="btn">判断</button>
  <div id="result">
    <p>游戏结果</p>
    <img src="./images/loading.png" alt="" id="res-img">
  </div>

  <script>
    // 1、记录用户的出招
    var _shitou = document.getElementById("shitou")
    var _jiandao = document.getElementById("jiandao")
    var _bu = document.getElementById("bu")

    var _userChuzhao = ""
    _shitou.onclick = function() {
      _userChuzhao = "石头"
      _jiandao.style.border = "none"
      _bu.style.border = "none"
      _shitou.style.border = "red 2px solid"
      // alert("用户出招:" + _userChuzhao)
    }
    _jiandao.onclick = function() {
      _userChuzhao = "剪刀"
      _shitou.style.border = "none"
      _bu.style.border = "none"
      _jiandao.style.border = "red 2px solid"
      // alert("用户出招:" + _userChuzhao)
    }
    _bu.onclick = function() {
      _userChuzhao = "布"
      _shitou.style.border = "none"
      _jiandao.style.border = "none"
      _bu.style.border = "red 2px solid"
      // alert("用户出招:" + _userChuzhao)
    }


    // 2、电脑出招
    var _btn = document.getElementById("btn")
    var _comImg = document.getElementById("com-img")
    var _comChuzhao = ""
    _btn.onclick = function() {
      // 随机一个1~3的整数
      var num = Math.ceil(Math.random() * 3)
      if(num === 1) {
        _comChuzhao = "石头"
        _comImg.src = "./images/shitou.png"
      } else if(num === 2){
        _comChuzhao = "剪刀"
        _comImg.src = "./images/jiandao.png"
      } else if(num === 3) {
        _comChuzhao = "布"
        _comImg.src = "./images/bu.png"
      }

      // 3、判断输赢
      var _resImg = document.getElementById("res-img")
      if(
        (_userChuzhao === "石头" && _comChuzhao === "剪刀") ||
        (_userChuzhao === "剪刀" && _comChuzhao === "布") ||
        (_userChuzhao === "布" && _comChuzhao === "石头")
      ) {
        _resImg.src="./images/win.png"
        // alert("玩家胜出")
      } else if(_userChuzhao === _comChuzhao) {
        _resImg.src="./images/pingju.png"
        // alert("平局")
      } else {
        _resImg.src="./images/fail.png"
        // alert("电脑胜出")
      }
    }


  </script>
</body>
</html>

六、循环结构

1.for循环

1.1 认识循环

什么是循环?

循环,指代的就是重复的过程

循环结构:代码中可以根据某个条件是否满足,重复执行某个代码块的过程

为什么要用循环?

JavaScript语法在浏览器一侧,主要是用于网页中的数据验证、数据处理和网页特效开发的!

网页中经常出现相似的一些结构,外观样式一模一样,仅仅是展示数据不同,如商品列表

页面中重复的视图结构,开发的时候不会每个视图结构都单独开发一次,重复的工作量太大!

需要循环结构的支持,将多个商品直接在同一个视图结构中进行重复渲染,页面中就可以一次加载多个商品

JavaScript语法结构中,提供了如下一些常见的循环

  • for循环【基础】
  • while循环【基础】
  • do-while循环【基础】
  • for..in循环【数组】
  • for..of循环
  • forEach循环【数组】

1.2 for基础语法

需求:火车站售票,需要将0~10号票全部售出

// 售票程序
// 1、普通的实现流程,代码的重复量过大;企业开发时代码审计不会通过
// console.log("售出1号票")
// console.log("售出2号票")
// console.log("售出3号票")
// console.log("售出4号票")
// console.log("售出5号票")
// console.log("售出6号票")
// console.log("售出7号票")
// console.log("售出8号票")
// console.log("售出9号票")
// console.log("售出10号票")

// 2、循环实现,减少重复的代码
// var i = 1:初始变量,循环执行的时候 这段代码只会执行一次
// i<= 10:循环条件,当条件的结果为true的时候,执行循环内部的代码
// i++:自增运算,循环内部的代码执行完成后,对循环变量进行自增
for(var i = 1; i <= 10; i++) {
  console.log("sale No." + i + " tickets")
}

1.3 break关键字

作用:不论循环条件是否为true,直接终止循环,跳出循环后继续执行循环后面的代码

需求:火车站售票(1~10号票),但是售出第6张票时,执行反恐演练;火车站提前关闭!

// 3、正常售票,售出第6张票时,反恐演练提前关闭火车站
for(var i = 1; i <= 10; i ++){
  console.log("售出了 No." + i + "号票")
  // 当售出第6张票时,关闭火车站/售票窗口
  if( i === 6 ){
    console.log("执行反恐演习,关闭火车站")
    // 循环中一旦执行了break这行代码,不论循环的条件是否为true,这个循环直接结束
    break
  } 
}

console.log("美好的一天结束了..")

1.4 continue关键字

作用:终止本次循环(不再继续执行本次循环后面的代码),直接开始下一次循环

火车站售票:预留6号票和8号票

// 4、continue关键字
// for(var i = 1; i <= 10; i++) {
//   if(i === 6 || i === 8) {
//     console.log("保留票,不能售出")
//   } else {
//     console.log("售出了.No." + i + "号票")
//   }
// }

for(var i = 1; i <= 10; i++) {
  if(i === 6 || i === 8) {
    console.log("保留票,不能售出")
    // 中断本次循环(本次循环结束,后面的代码不再执行;直接开始下一次循环)
    continue
  }

  console.log("售出了.No." + i + "号票")
}

2.while循环

JavaScriptwhile循环区分为

  • while循环
  • do-while循环

2.1 基本语法

// 练习1、while循环
// 循环变量,写在循环外面
var i = 1
// 循环上,添加条件判断
while(i <= 10) {
  console.log("售出了" + i + "号票")
  // 循环内部,修改循环变量
  i++
}

// 练习2、break关键字
var i = 1
while(i <= 10) {
  console.log("售出了" + i + "号票")
  if(i === 6) {
    console.log("反恐演练,提前下班")
    break
  }
  i++
}


// 练习3、continue关键字
var i = 1
while(i <= 10) {
  if(i === 6 || i === 8) {
    console.log("保留票---------------")
    // 注意:一定要记得写循环变量的修改
    i++
    continue
  }

  console.log("售出了" + i + "号票")
  // 注意:一定要记得写循环变量的修改
  i++
}

2.2 do-while循环基本语法

// 4、do-while循环
// 循环条件写在外面
var i = 1;
// 先循环,后判断条件(do-while循环不论条件是否为true,至少会执行一次循环代码)
do {
  console.log("售出了" + i + "号票")
  // 注意:一定要记得修改循环变量,避免造成死循环的情况
  i++
}while(i <= 10)

2.3 案例开发

通过forwhiledo-while循环实现:9x9乘法表

  • 第一步:通过一个for循环,实现输出9行 span
  • 第二步:通过一个内部for循环,实现第一行输出一列、第二行输出两列…
  • 第三步:给内部for循环输出的空格,填充数据,完成乘法表
/*
    1 x 1= 1
    1 x 2 = 2   2 x 2 = 4
    ....
    1 X 9 = 9 .... 9 X 9 = 81
    */
for (var i = 1; i <= 9; i++) {
  //  document.write("<span></span> <br />")
  for (var j = 1; j <= i; j++) {
    // document.write("<span></span>")
    document.write("<span>" + i + " X " + j + " = " + (i*j) + "</span>")
  }
  document.write("<br />")
}

3.死循环

循环中有一种非常特殊的循环:循环条件可能永远为true,这样的循环会一直进行下去,直到循环条件主动的修改为false或者循环内部主动的break

  • 开发过程中,如果有固定的循环结束条件,尽量避免出现死循环
  • 如果不确定循环结束条件,需要通过死循环完成重复执行,也需要明确可能跳出循环的条件

案例:完成一局游戏的时候,可以通过死循环的方式控制单局游戏的进行,游戏结束后用户只能通过再来一局的方式开启新的游戏!

<body>
  <button id="start">开始游戏</button>
  <button id="restart">再来一局</button>

  <script>
    // 定义一个变量,控制当前游戏是否已经开始
    // true: 游戏已经开始
    // false: 游戏尚未开始
    var flag = false

    var _start = document.getElementById("start")
    var _restart = document.getElementById("restart")

    // 开始游戏
    _start.onclick = function() {
      if(!flag) { // 游戏尚未开始,开启游戏
        // 游戏已经开始,修改flag
        flag = true
        // 开启游戏
        _start.innerText = "暂停游戏"
        _restart.style.display = "inline-block"
        // 重复执行某些事情
        while (flag) {
          var result= confirm("游戏正在进行中....(是否确定退出游戏)")
          if(result) {
            alert("游戏准备退出")
            flag = false
            // 游戏重启
            _start.innerText = "开始游戏"
            _restart.style.display = "none"
          }
        }
      }
    }

    _restart.onclick = function() { // 再来一局
      // 游戏已经开始的情况下,才能再来一局
      if(flag) {
        // 游戏一旦重启,修改flag
        flag = false
        // 游戏重启
        _start.innerText = "开始游戏"
        _restart.style.display = "none"
      }
    }
  </script>
</body>

4.循环案例

4.1 1~100的和

for循环、while循环、do-while循环实现

// 1、模拟 1..5的和:观察代码,哪些代码是重复的?重复的代码中哪些部分是有规律变化的,将重复的代码我们一般通过循环进行处理,有规律变化的部分会通过循环变量处理
// var sum = 0; // 记录总和
// sum += 1
// sum += 2
// sum += 3
// sum += 4
// sum += 5
// console.log("1..5的和:", sum)

// 2、循环简化,1..5的和
// var sum = 0
// for(var i = 1; i <= 5; i++){
//   sum += i
// }
// console.log("1..5的和:", sum)

// 3、循环计算1..100的和
var sum = 0
for(var i = 1; i <= 100; i++){
  sum += i   // 等价于  sum = sum + i
}
console.log("1..100的和:", sum)

思考:如何计算1…100奇数的和?偶数的和?

// 4、1..100奇数的和
var sum = 0; // 记录总和的变量
for(var i = 1; i <= 100; i++) {
  // 如果i是奇数的话,添加到总和中
  if(i % 2 == 1) {
    // 奇数
    sum += i   // sum = sum + i
  }
}
console.log("1..100奇数的和:", sum)


// 5、1..100偶数的和
var sum = 0; // 记录总和的变量
for(var i = 1; i <= 100; i++) {
  // 判断是否偶数
  if(i % 2 == 0) {
    sum += i
  }
}
console.log("1..100偶数的和:", sum)

4.2 循环打印图形

使用for循环输出如下的图形

*
**
***
****
*****
// 1、打印三角形
// 第一行1列、第二行2列、第三行3列..
for(var i = 1; i <= 5; i++) {
  // 网页中写入一个字符内容
  // document.write("*<br/>")
  
  // 第一行输出1列;第二行输出2列...
  for(var j = 1; j <= i; j++) {
    document.write("*")
  }
  // 一行内容输出完成后,打印换行
  document.write("<br />")
}

使用for循环输出如下的图形

*
***
*****
*******
*********
// 2、打印三角形
// 第一行1列、第二行3列、第三行5列...
for(var i = 1; i <= 5; i++){
  // document.write("*<br/>")
  // 第一行1列、第二行3列、第三行5列...
  for(var j = 1; j <= (2*i - 1); j++) {
    document.write("*")
  }
  document.write("<br />")
}

使用for循环输出如下的图形

    *
   ***
  *****
 *******
*********
// 3、打印等腰三角形
for(var i = 1; i <= 5; i++){
  // document.write("*<br />")
  // 打印空格
  for(var m = 5; m > i; m--){
    document.write("<span></span>")
  }

  // 打印符号
  for(var j = 1; j <= (2*i-1); j++){
    document.write("<span>*</span>")
  }
  document.write("<br />")
}

使用for循环输出如下的图形

    *
   ***
  *****
 *******
*********
 *******
  *****
   ***
    *
// 4、打印菱形
// 输出9行
for(var i = 1; i <= 9; i++) {
  // document.write("*<br />")
  // 输出正三角形
  for(var m = 5; m > i; m--) {
    document.write("<span></span>")
  }
  for(var j = 1; j <= (2*i-1) && i <= 5; j++) {
    document.write("<span>*</span>")
  }

  // 输出倒三角形
  // 输出空格(6-1 7-2 8-3 9-4)
  for(var y = 1; y <= (i-5); y++){
    document.write("<span></span>")
  }
  // 输出符号
  // 6行-7列 7行-5列 8-3列 9-1列
  // (9-6)*2+1 = 7
  // (9-7)*2+1 = 5
  // (9-8)*2+1 = 3
  // (9-9)*2+1 = 1
  for(var x = 1; x <= ((9-i)*2+1) && i > 5; x++){
    document.write("<span>*</span>")
  }

  document.write("<br />")
}

思考:思考如何输出如下的一个界面图形?

=================================================
=                                               =
=                                               =
=                                               =         
=                                               =
=================================================
// 5、打印长方形
for(var i = 1; i <= 6; i++) {
  // document.write("=<br />")
  for(var j = 1; j <= 50; j++) {
    // 第一行/最后一行全部输出
    if(i!==1 && i!== 6){
      // document.write("=")
      // break
      if(j === 1 || j === 50){
        document.write("<span>=</span>")            
      } else {
        // console.log("<span></span>")
        document.write("<span></span>")
      }
      continue
    }
    document.write("<span>=</span>")
  }
  document.write("<br />")
}

4.3 水仙花数

输出100~999之间的水仙花数

// 水仙花数
// 是一个三位数
// 每个位数上的数字的3次方的和,等于它本身
// 1^3 + 5^3 + 3^3 = 153
for(var i = 100; i <= 999; i++){
  // 拆分数字
  var b = parseInt(i / 100)
  var s = parseInt(i % 100 / 10)
  var g = parseInt(i % 10)

  // 判断是否水仙花数
  if(b*b*b + s*s*s + g*g*g === i) {
    console.log("水仙花数:", i)
  }
}

4.4 打印10个斐波那契数列

// 2、斐波那契数列
var num1 = num2 = 1
var next = 0

console.log(num1, num2)

for(var i = 1; i <= 10; i++) {
  next = num1 + num2
  console.log(next)

  // 交换数据
  num1 = num2 // num2数据存放到num1中
  num2 = next // next数据存放到num2中
}

扩展:打印100以内的斐波那契数列

// 3、打印100内斐波那契数列
var num1 = num2 = 1
var next = 0

console.log(num1, num2)

// 死循环,获取100内斐波那契数列
// for(;;){},省略了数据初始化、数据条件和循环变量自增,但是不能省略分号
for(;;) {
  next = num1 + num2
  if(next > 100){
    break
  }
  console.log(next)


  // 交换数据
  num1 = num2 // num2数据存放到num1中
  num2 = next // next数据存放到num2中
}

七、数组

1.认识数组

JavaScript语法中提供了一个复杂类型:Array 数组,可以允许用户在一个变量/容器中存储多个数据

1.1 什么是数组

数组Array:一个容器中可以存储多个数据的对象,语法中通过Array表示

1.2 为什么要使用数组

项目开发中,经常需要变量临时存储数据,让数据参与运算;

某些场景中,需要对批量数据进行操作,如记录一个班级所有的学员、记录一个图书馆所有的书号、记录一个课程中所有的章节,在没有确定下来具体有多少学员、多少书号、多少章节的情况下没有办法使用多个变量进行记录;迫切需要一个变量中如何存储多个数据的语法:数组!

2.数组声明

数组的声明操作,在原生JavaScript中主要有两种方式:

  • 字面量方式
  • 对象的创建

2.1 字面量创建数组(推荐)

// 1、字面量,声明一个数组
// 记录课程中需要学习的那些技术, html,css,javascript,nodejs,express,mysql,...
var baseTechs = ['html', 'css', 'javascript', 'jQuery', 'bootstrap']
console.log(baseTechs)
// var b = []   创建一个空数组对象
// ① 数组中可以存放多个数据
// ② 数据中存放的数据有顺序
// ③ 顺序按照0,1,2,3,4..编号/下标/索引的方式记录

2.2 对象创建方式(了解)

// 2、对象创建,声明一个数组// 对象的创建语法:固定语法, new 关键字()var advTechs = new Array('vue', 'react', 'mp', 'uni-app', 'data')console.log(advTechs)// new Array() 创建了一个【空】数组对象// new Array('vue', 'react') 创建了一个包含两个数据的数组对象

2.3 注意事项(熟悉)

new Array(dat)创建数组时,如果只传递一个整数,数组创建结果就会出现差异

// 3、注意事项
var nums = [5]   // 字面量,可以创建包含单个数字的数组
console.log(nums, '语法[5]')
// [5]

var nums2 = new Array(5) 
// 创建对象,注意~如果直接包含某个数值,创建一个该数值长度的空数组
console.log(nums2, '语法new Array(5)') 
// (5)[空],创建了包含5个空元素的数组

// 拓展语法
var nums3 = new Array(5,)
// 和 new Array(5)没有区别

2.4 数组基础操作

数组中的数据,对应了编号/下标/索引,数据的操作区分查询、增加、修改和删除

  • 通过下标,对数据数据进行操作【不推荐,除非必要】
  • 原因:数组中存储的数据数量是变化的,每个数据对应的索引编号也是动态变化的,所以大部分情况下无法通过编号完全对应某一个数据,所以开发中一般不推荐直接通过编号操作具体某个数据
// 声明数组
var jobs = ['前端工程师', '后端工程师', '测试工程师', '维护工程师']

// 查询:以对象的形式展示
console.log(jobs, "查询整个数组")

// 查询:查询下标/编号对应的数据
console.log(jobs[2], "下标查询数据")

// 添加数据:通过下标添加(下一个数据)
jobs[4] = "需求工程师"
console.log(jobs, "下标添加数据")

// 修改数据:通过已经存在的下标进行处理
jobs[0] = "WEB工程师"
console.log(jobs, "下标修改数据")

// 删除数据:业务删除、真实删除
jobs[1] = null
console.log(jobs, "业务删除|位置保留")
console.log(jobs[1], "业务删除的数据")

delete jobs[2]
console.log(jobs, "delete删除数据") // 数据位置:空
console.log(jobs[2], "delete删除的数据")

3.常见操作操作

JavaScript中给数组单独创建了一个类型:Array

给这个类型提供了大量的操作函数,可以直接通过固定语法完成数据的增删改查

函数名称描述
a.push(dat)数组的末尾追加一个数据dat
a.pop()删除数据末尾的一个数据
a.unshift()数组的开头添加一个数据dat
a.shift()数组的开头删除一个数据

代码操作:

// 声明一个数组
var jobs = ['需求工程师']
console.log(jobs, "jobs")

// 1、push() 末尾追加一个数据的函数
jobs.push('开发工程师')
console.log('jobs',jobs)
// jobs (2) ['需求工程师', '开发工程师']

// 2、pop() 末尾删除一个数据(和具体那个数据无关)
jobs.pop()
console.log('jobs',jobs)
// jobs ['需求工程师']

// 3、unshift() 开头增加一个数据
jobs.unshift("售前工程师")
console.log('jobs',jobs)
// jobs (2) ['售前工程师', '需求工程师']

// 4、shift() 开头删除一个数据
jobs.shift()
console.log('jobs',jobs)  
// jobs ['需求工程师']

4.数组遍历函数

一个数组中可以包含多个数据,将多个数据循环操作的过程(多个数据挨个操作的过程)称为遍历数组

遍历方式掌握程度描述
for循环了解普通for循环 遍历数组
for..in循环掌握增强型for循环 遍历数组
forEach()掌握遍历数组的函数
filter()掌握条件遍历数组的函数
map()掌握算法遍历数组的函数
every()了解全部数据判断遍历数组的函数
some()了解部分数据判断遍历数组的函数
reducer()了解数据累计遍历数组的函数

4.1 for循环

// 声明一个数组
var arr = ["一", "二", "三", "四"]

// 1、普通for循环
for(var i = 0; i < arr.length; i++) {
  // 通过下标编号获取数据
  console.log(i, arr[i], " 遍历数据")
}
/* 控制台打印输出:
0 '一' ' 遍历数据'
1 '二' ' 遍历数据'
2 '三' ' 遍历数据'
3 '四' ' 遍历数据'
*/

4.2 for…in循环

// 声明一个数组
var arr = ["一", "二", "三", "四"]

// 2、for..in循环
for(var i in arr) {
  console.log(i, "-", arr[i], " for.in遍历数组")
}
/*
0 - 一  for.in遍历数组
1 - 二  for.in遍历数组
2 - 三  for.in遍历数组
3 - 四  for.in遍历数组
*/

4.3 forEach()循环

// 3、forEach循环
// item:每次循环的数据
// index:循环的数据对应的下标
// brr:第三个数据~就是数组本身,一般省略
arr.forEach( function(item, index) {
  console.log(item, "-", index)
})

/*
一 - 0
二 - 1
三 - 2
四 - 3
*/

4.4 filter()

// 4、filter()
// 要求:获取数组中的偶数
var brr = [1,2,3,4,5,6,7,8,9]
// filter() 循环遍历数组
// item: 每次循环的数据
// index:每次循环的数据对应的下标/编号
// b:数组,一般不用,直接省略
var xbrr = brr.filter(function(item) {
  // 循环过程中,满足条件(true)的数据被得到/否则被遗弃
  if(item % 2 === 0){
    return true
  } else {
    return false
  }
})
console.log('xbrr',xbrr)

// 思考:将数组中合法(账号长度大于等于6)的账号找出来
var names = ['tom', 'damu', 'manager', 'administrator']
var xnames = names.filter(function(item) {
  if(item.length >= 6){
    return true
  } else {
    return false
  }
})
console.log('xnames', xnames)

4.5 map()

// 2、map()
// 要求:将下面数组中的数据,求平方得到一个新数组
var arr = [1,2,3,4,5,6,7,8,9]
// map() 将数据做一个算法转换,得到新的数组
// item:每次循环的数据
// index:每次循环数据的下标
// brr:数组,一般不用直接省略
var xarr = arr.map(function(item) {
  // console.log(item)
  return item * item
})
console.log('xarr',xarr)

// 思考:对商品价格200,进行转换,输出标准价格格式:¥200.00元
var prices = [100, 200, 202, 400]
var xprices = prices.map(function(item) {
  return "¥" + item + ".00元"
})
console.log('prices',prices)
console.log('xprices',xprices)

4.6 every()

// 1、every()
// 要求:判断数组中的数据是否都是数值
// 全部都是数值:true
// 只要有一个非数值:false
var arr = [1,2,3,4,5,6,7,8,9,100]
// item:正在循环的数据
// index:循环数据对应的下标/标号/索引
// b:数组本身,可以省略
var result = arr.every(function(item) {
  // console.log(item, index, b)
  if(typeof(item) === "number") {
    return true
  } else {
    return false
  }
})
console.log("数组中包含的数据都是数值:", result)

4.7 some()

// 2、some()
// 要求:查询给定的多个账号中,是否包含合法账号(长度大于等于6)
var names = ['tom', 'jerry', 'shuke', 'beita', 'manager']
// some(),只要有一个满足条件的,返回true;否则返回false
var result = names.some(function(item) {
  // console.log(item)
  if(item.length >= 6) {
    return true
  } else {
    return false
  }
})
console.log("是否包含合法账号:", result)

4.8 reducer()

 // 3、reduce()
// 需求:计算数组中所有数据的和
var arr = [1,2,3,4,5,6,7,8,9,10]
// 数组中提供了一个循环迭代的函数:reduce
// a:循环的输入数据,每次循环的结果当成下一次的a输入
// b:正在循环的数据
var result = arr.reduce(function(a, b) {
  // console.log(a, b)
  return a + b
})
console.log("数组求和:", result)

5、数组其他函数

5.1 查询可操作函数

数组中可以操作的函数特别多,如果开发过程中遗忘了某个函数应该怎么处理怎么办?

① 浏览器查询

打开浏览器控制台, 创建一个数组;展开数组查看数组的可操作函数都有哪些

② 查看官方文档

操作数组中的某个函数的时候,遗忘了整个函数操作语法,可以查看官方描述

  • 推荐百度搜索:MDN javascript filter

5.2 常见的函数

数组中包含了多个数据,操作方式和对应的场景比较多

① 查询某个数据是否包含在数组中

函数描述
a.includes(dat)判断dat是否包含在a数组中
包含true、不包含false
掌握
a.indexOf(dat)获取dat数据在数组a中第一次出现的位置,得到索引
如果不包含返回-1
掌握
a.lastIndexOf(dat)获取dat数据再数组a中最后一次出现的位置
如果不包含返回-1
a.find(function() {})查询并返回数组a中包含的某个数据-第一次出现
掌握
a.findIndex(function() {})查询并返回数组a中包含的某个数据的索引
掌握
a.findLast(..)查询并返回数组a中包含的某个数据-最后一次出现
a.findLastIndex(..)查询并返回数组a中包含的某个数据的索引-最后一次出现的位置

代码操作:

// 声明一个数组
var arr = ["零", "一", "二", "三", "四", "五", "六", "零", "一", "二"]

// 1、includes
var result = arr.includes('二')
console.log("数组中是否包含:二:", result)

// 2、indexOf() / lastIndexOf()
var result2 = arr.indexOf("一")
console.log("数组中 一 出现的位置(第一次):", result2)

var result3 = arr.lastIndexOf("一")
console.log("数组中 一 出现的位置(最后一次):", result3)

// 3、find() / findLast()
var result4 = arr.find(function(item) {
  return item === "零"
})
console.log("数组中是否包含 零 :", result4)

var result5 = arr.findLast(function(item) {
  return item === "一"
})
console.log("数组中是否包含 一:", result5)

// 4、findIndex() / findLastIndex()
var result6 = arr.findIndex(function(item) {
  return item === "二"
})
console.log("数组中 二 第一次出现的位置:", result6)

var result7 = arr.findLastIndex(function(item) {
  return item === "二"
})
console.log("数组中 二 最后一次出现的位置:", result7)

② 其他操作函数

函数描述
concat()拼接两个数组
join()将数组中的数据拼接成字符串
reverse()翻转数组
slice()拆分数组,截取数组
sort()数组排序
splice()删除或者替换数据
toString()转换成字符串

代码操作:

// 5、concat() 拼接数组
var arr1 = ["tom", "jerry"]
var arr2 = ["舒克", "贝塔"]

var xa = arr1 + arr2
console.log(xa, " 加号拼接")
// 相当于数组自动转换成字符串然后拼接
// tom,jerry舒克,贝塔  加号拼接
var xa2 = arr1.concat(arr2)
console.log(xa2, " concat()函数拼接")
// ['tom', 'jerry', '舒克', '贝塔'] ' concat()函数拼接'

// 6、join() 数组拼接成字符串
var fav = ["篮球", "游戏", "编程", "音乐"]
console.log(fav, "直接输出数组")
console.log(fav.join(","), "join拼接输出")
console.log(fav.join("--"), "join拼接数组")

// 7、reverse() 数组翻转
var ages = [10, 20, 70, 40, 50]
console.log("年龄条件列表:", ages)
console.log("年龄条件(翻转):", ages.reverse())

// 8、slice() 截取数组
var arr = ["零", "一", "二", "三", "四", "五", "六", "零", "一", "二"]
var newArr = arr.slice(1, 5)
console.log(newArr, "截取后的数组")
// 包含开始位置的数据,不包含结束位置的数据
//  ['一', '二', '三', '四']

// 9、sort() 数组简单排序
var nums = [1,5,2,3,56,7,8,4,23,10,5,5,68,89]
// var nums = [1, 3, 6, 8, 2, 9, 0, 4, 6, 7]
console.log('nums:',nums)
var newNums = nums.sort()
console.log('nums排序后:',newNums)

// 10、splice() 数据删除或者替换
var accounts = ["admin", "damu","xiaoli", "manager"]
console.log('accounts原有账号:',accounts)
// 删除索引为1的账号
// 第一个数值:表示从那个索引开始删除
// 第二个数值:表示删除多少个数据
// 第三个数值:使用什么数据替换删除后的数据
accounts.splice(1, 1) // 删除一个数据
// accounts.splice(1, 1, 'xxxxx') // 修改一个数据【删除了某个位置的数据,使用新的数据替换】
console.log('accounts账号:',accounts)

// 11、toString()
var accounts = ["admin", "damu","xiaoli", "manager"]
// 将数组转换成字符串输出
console.log(accounts.toString()) // 等价于:accounts.join(",")

八、函数

1.认识函数

1.1 什么是函数

函数Function,描述了生活中的一种行为、代码中封装了多行代码可以实现一定功能的代码块

如:生活中吃饭的行为、玩游戏的行为、看电影的行为…

1.2 函数的声明

基本语法

/**
 * 函数的声明注释,重要的函数都要写完善的文档注释,说明函数的作用
 * author: 函数的作者
 * time: 函数的开发时间
 * modity: 函数最后由谁修改的
 * info: 函数的使用注意事项
 */
// 声明语法1
function 函数名称() {
  // 函数名称:命名规范参考变量的命名规范
  // 大括号中编写函数封装的代码,带上代码缩进
  // 函数中的代码
}

// 声明语法2
const 函数名称 = function() {
  // 函数名称:命名规范参考变量的命名规范
  // 大括号中编写函数封装的代码,带上代码缩进
  // 函数中的代码
}

函数声明练习

// 1、普通的操作功能
// // 吃饭
// console.log("买菜")
// console.log("买面")
// console.log('和面')
// console.log('炒菜')
// console.log('吃饭')
// console.log('洗碗刷锅')
// console.log("收拾")

// // 又需要吃饭的功能
// // 导致相同的功能在多个代码位置使用时,出现大量代码重复
// console.log("买菜")
// console.log("买面")
// console.log('和面')
// console.log('炒菜')
// console.log('吃饭')
// console.log('洗碗刷锅')
// console.log("收拾")

// 2、功能 封装成函数,提高代码的复用性
// 吃饭:行为、函数
function eat() {
  console.log("买菜")
  console.log("买面")
  console.log('和面')
  console.log('炒菜')
  console.log('吃饭')
  console.log('洗碗刷锅')
  console.log("收拾")
}

// 需要函数功能的地方,需要通过函数名称调用执行
eat()

// 其他位置又需要吃饭的功能,只需要再次通过函数名称调用
// 避免了大量的代码重复
eat()

1.3 函数调用执行

函数声明完成后,函数内部的代码不会立即执行!

函数内部的代码只有在通过函数名称调用函数时才会执行

// 使用函数的第二种声明方式
// 声明函数,并不会立即执行函数内部的代码
var watchMovie =  function() {
  console.log("等朋友")
  console.log("去电影院")
  console.log("验票进大厅")
  console.log("看电影-独行月球")
  console.log("看完电影,回家")
}

// 通过函数名称,调用函数执行函数内部的代码
// 执行语法:函数名称()
watchMovie()

// 再看一场电影
watchMovie()

1.4 函数的预解析

函数本质上也是一个变量,变量内部存储了一个函数对象而已!

对于函数的预解析,会出现什么样的情况呢?

标准语法

// 1、标准语法预解析
    
// 标准语法声明的函数,解释器执行时包含预解析功能
// 预解析:将函数的声明提升;保障当前范围中函数声明前调用函数也可以正常执行函数

// 调用函数
sayHello() // hello function!

// 声明函数
function sayHello() {
  console.log("hello function!")
}

// 调用函数
sayHello() // hello function!

赋值语法

// 2、赋值语法 预解析
// 赋值语法中,预解析的是变量 | 不是函数
// 相当于变量提升,也就是var helloFn;变量的声明出现了提升
// 并不是函数声明得到了提升

// 调用函数
// console.log(helloFn)  // undefined
helloFn() // Uncaught TypeError: helloFn is not a function
// 未捕获    类型 错误: helloFn 不是一个  函数

// 声明函数
var helloFn = function() {
  console.log("函数Fn执行")
}

// 调用执行函数
helloFn()

1.5 其他函数

  • alert():函数,弹出窗口的函数
    • confirm() / prompt()
  • push() / pop() / unshift() / shift():操作数组数据的函数
  • forEach() / filter() / map() / reduce() / every() / some():遍历数组数据的函数

2.函数基本语法

2.1 声明基本语法

扩展函数的语法,完整的声明过程如下:

① 函数名称:封装的代码块形成一个函数,这个函数对象的名称,遵循变量的命名规范
② 函数参数:描述语法时,反括号包含的东西表示可选内容;
            函数执行时需要的数据
③ 函数内部代码:函数封装的一行或者多行代码
④ 函数返回结果:也称为函数返回值,表示函数内部代码的执行结果
                可以通过return关键字返回;如果不写默认返回undefined

function 函数名称( [函数参数] ) {
  // 函数内部的代码
  [return 返回结果]
}

2.2 基本函数

不需要参数,不需要返回值

需求:生活中的一个场景,关一下窗户

分析:

  • 参数:关窗户,需要什么数据支持?不需要
  • 返回值:关窗户,不需要汇报结果!
// 1、关窗口行为: 不需要参数、不需要返回值
// 执行过程不需要数据
// 执行完成不需要汇报结果
function closeWindow() {
  console.log("窗口已经关上了")
}

// 执行函数
closeWindow()

2.3 函数参数

需要参数,不需要返回值

函数参数Arguments、Parameters,表示了函数内部代码执行需要的数据

需求:看电影

分析:

  • 参数:看电影,我们得知道要去看什么电影?需要参数
  • 返回值:不需要;没有谁看完电影给大家汇报~电影已看完请知悉

代码操作:

// 2、看电影行为
// 执行时需要知道看什么电影?
// 看完电影之后不需要汇报

// 函数声明的时候,写在声明括号中的参数变量:形式参数
// 形式参数:描述了函数执行时名义上需要的数据
function watchMovie(movieName) {
  console.log("去看电影吧,看[" +  movieName + "]")
}

// 调用函数时,在括号中传递的具体数据:实际参数
// 实际参数:描述了函数执行时传递的具体数据
watchMovie("壮志凌云")

watchMovie("独行月球")

2.4 函数返回值

不需要参数,需要返回值

函数返回值,也称为返回结果,描述了函数内部代码执行的结果

需求:小明收到快递(付过款),让小李帮忙取一下

分析:

  • 参数:不需要
  • 返回值:需要,小李收到的包裹,交给小明 | 不能丢弃

return关键字主要用于返回数据;一旦执行函数立即结束!

代码操作:

// 3、收快递行为
function getKuaidi() {
  console.log("小李代收快递")
  // 函数内部,return关键字用于返回结果
  // return代码一旦执行,函数结束
  return "阿米洛花旦娘 键盘"
}

// 存在返回值的函数,需要使用自定义变量接收返回值
var thing = getKuaidi()
console.log("小明收到快递:", thing)

2.5 参数+返回值

需要参数,需要返回值

需求:研发了一个超市购物软件,需要一个结算计算器

分析:

  • 参数:做商品结算,需要输入商品单价、购买数量,需要参数
  • 返回值:商品结算结束后,需要打印小票,需要结算的结果;需要返回值

代码操作:

// 4、超市结算:计算器
function calculation(price, cnt) {
  // 计算小计金额
  var total = parseFloat(price) * parseInt(cnt)
  // 返回计算结果
  return total
}

// 一个结算过程
var t = calculation(12.88, 4)
console.log("打印小票:小计金额(" + t + ")")

3.变量

编写JavaScript代码时,变量可以声明在任意位置

但是一旦出现了函数,变量的使用就会受到一定的限制

// 1、变量声明在不同的位置,出现什么问题?
var myName = "Wendy"

function fn() {
  var myName2 = "文帝"
  }
// 执行函数,让函数内部的代码执行
fn()

console.log(myName, "myName") 
// Wendy myName
console.log(myName2, "myName2")
// Uncaught ReferenceError: myName2 is not defined
// 未捕获的  引用     错误:  myName2变量 没有定义

// 思考:myName2变量在函数内部声明过呀?为什么后面不能使用?

3.1 局部变量和全局变量

**全局变量:**声明在函数外部的、可以给所有函数使用的公共变量,相当于公共数据

**局部变量:**声明在函数内部的、只能被当前函数使用的变量 / 其他函数访问不到当前函数的局部变量,相当于私有数据

代码操作:

// 2、全局变量 vs 局部变量
// 全局变量:声明在函数外部的变量
//          全局变量可以让任何函数使用
//          类似生活中的公共资源
var machine = "公园的健身器材" // 全局变量

function fnDamu() {
  // 访问全局变量
  console.log(machine, "fnDamu")
  // 局部变量:声明在函数内部
  //          只能被当前函数使用
  //          类似生活中 私人物品
  var board = "科创K3键盘"
  // 当前函数内部,可以使用自己的局部变量
  console.log("键盘:", board)
}

function fnXiaoli() {
  // 访问全局变量
  console.log(machine, "fnXiaoli")
  // 函数中,不能访问另一个函数中的局部变量
  // Uncaught ReferenceError: board is not defined
  // 未捕获的  引用     错误:  board 变量没有定义
  console.log("键盘:", board)
}

fnDamu()
fnXiaoli()

小总结:项目开发中,全局变量和局部变量的使用

  • 如果一个变量可能被多个函数使用,就将它声明为全局变量
    • 如:开发石头剪刀布游戏,定义一个变量记录用户积分score
  • 如果一个变量只在当前函数内部使用,函数的外面任何地方都没有用过,就可以将这个变量声明为局部变量
    • 如:开发石头剪刀布游戏,电脑出招产生了一个1/2/3随机数,存放这个随机数的变量可以声明为当前函数内部的局部变量

3.2 命名空间和作用域

出现了函数之后,变量区分为全局变量和局部变量

代码语法中为了准确的描述一个变量可以被访问的范围,提出了两个概念:

  • 命名空间namespace :声明变量的范围,变量的声明和可以访问的位置
    • 类似:县人民公园【名称/名词,描述了 这个公园属于 县城公共所有,这个县城中的所有人都可以访问这个公园】
    • 语法中:全局命名空间、局部命名空间
  • 作用域scope :声明的变量可以被访问的范围大小,起作用的范围
    • 类似:县人民公园(命名空间)提高了全县人民的健康(作用域)
    • 语法中:全局作用域、局部作用域

作用域链:

一旦项目中使用一个变量,需要从当前作用域空间查询变量是否存在继续向上查询作用域空间中的变量,如果都不存在就会报错

下面的代码执行时,第13行代码中使用了变量name,作用域链查询过程:

  • 查询局部作用域:是否声明了name变量?没有 | 有-直接使用
  • 查询全局作用域:是否声明了name变量?没有 | 有-直接使用
  • 查询javascript解释器作用域:是否声明了name变量?没有 | 有-直接使用
  • 报错
// 3、作用域链
// js内置作用域:javascript解释器环境

// 全局变量
// var name = "Wendy"

function fn() { 
  // 局部变量
  // var name = "文帝"

  // 使用变量:就近原则
  // 查询离使用变量最近的作用域
  console.log(name, "name") // ?
}

fn()

3.3 变量的预解析

变量 的 预解析,出现了函数之后,依然可以预解析;需要明确变量的作用域即可!

全局变量预解析

<script>
    // var version;  全局变量预解析
    // 为了保障当前文件中的所有位置,可以使用version变量而不报错

    // 1、全局变量:当前文件的所有地方

    // 变量预解析:当前命名空间(全局命名空间)中,将变量声明提到最前面
    console.log("version:", version)  // undefined

    // 函数中使用全局变量
    function fn() {
      console.log("version fn:", version) // 
    }

    fn()

    // 全局变量
    var version = "V1.0.0"
</script>

局部变量预解析

// 2、局部变量预解析
// 全局变量
var myName = "文帝"

function fn() {
  // var myName; 局部变量预解析:声明被提升了,赋值还在原来的位置

  // 使用myName变量,就近原则 
  console.log("myName:", myName) // undefined

  // 局部变量:当前命名空间(局部命名空间)预解析
  var myName = "Wendy"
}

fn()

4.高级函数

4.1 函数的递归

4.1.1 什么是递归

递归recursion,函数的递归,描述了函数自己调用自己的一种执行方式

4.1.2 递归基本语法

需求:需要展示5~1这五个数据

for循环

// 1、基本语法:输出5~1五个数据
// - 普通for循环
// 理解:
// var i= 5: 循环变量的初始化,循环第一次执行时执行,并且只执行一次
// i > 5:循环条件,每次进入循环时需要判断
// i++:循环变量修改,每轮循环结束时进行变量值修改
for(var i = 5; i > 0; i--) {
  console.log('i-> ', i)
}

recursion递归

  • 递归的本质:循环、函数级别的循环
// 2、函数递归:函数自己调用自己
// 理解这段代码:fn()函数就是用于展示数据的,你交给它一个数据;它就展示一个数据

// 展示数据的函数
function fn(n) {
  // 结束条件
  console.log("n计数:", n)
  if(n == 1) return 1

  // 递归调用:函数内部调用函数自己
  // 输出完当前的n,输出下一个n:比当前的n小于1
  return fn(n-1)
}

// 通过函数递归的方式,展示数据
fn(5)
4.1.3 递归操作案例

需求:计算斐波那契数列1,1,2,3,5,8,13....第n位的数据

for循环实现

// 1、for循环实现斐波那契数列 100以内
var num1 = num2 = 1 // 初始准备的两个数据
console.log("数列初始数据:", num1, num2)
var next = 0        // 下一个数据

// 获取第10位的数据
for(var n = 3; n <= 10; n++) {
  // 计算获取下一个数据
  next = num1 + num2
  /*if(next >= 100 ) {
    // 如果斐波那契数列当前某个数据大于100,跳出循环
    break
  }*/
  console.log("-数列数据:[" + next + "]")

  // 交换数据
  num1 = num2
  num2 = next
}

recursion递归实现

 // 2、函数递归,获取100内的斐波那契数列
function feib(n) {       // 参数n:表示获取第几个位置的数据
  if(n <= 2) { // 初始数据
    // 表示递归结束的条件: 当获取第一位或者第二位数据时,直接返回1
    return 1
  }
  // 下一个数据是前面两个数据的和:递归调用
  return feib(n-1) + feib(n-2)
}

var r = feib(1) // 获取第1个斐波那契数列的数据
console.log('r第一位:',r)

var r = feib(2) // 获取第2个斐波那契数列的数据
console.log('r第二位:',r)

var r = feib(10) // 获取第10个斐波那契数列的数据
console.log('r第十一位:',r)

小总结:recursion递归相比较普通循环,优势是什么?

  • 函数的递归,其实本质上也是一个循环执行的过程;相比较普通for循环语句,语法上语义上得到了非常大的提升
4.1.4 拓展:青蛙跳台问题

青蛙跳台问题:请通过代码解决,青蛙跳上10级台阶,有几种跳发?

类推法

分别分析青蛙跳上1级台阶、2级台阶、3级台阶、4级台阶、5级台阶有多少种跳法,找出跳发数列之间的规律进行计算

分析:青蛙在不同数量的台阶上,跳上最顶层的台阶的方法,有如下的规律

1层    2层     3层     4层     5层     6层  ....
1      2       3       5       8      13   ....      不同的层数,跳法符合斐波那契数列规律

审题规律

通过审题,我们会发现青蛙跳到最高处的次数,刚好是前两个台阶跳法的总和,符合斐波那契数列规律

整理得到的结论:f(n ) = f(n-1) + f(n-2); 注意:n=1,直接返回1

如何计算10层台阶青蛙的跳法次数?

思考:分别通过循环和递归的方式,实现上面的青蛙跳台的问题!

4.1.5 函数在内存中执行过程

普通函数的执行过程

// 函数的声明部分
function fn() {
  console.log("xxxxxx")
}

// 函数的调用执行
fn()

递归函数在内存中的执行过程

function fn(n) {
  console.log("数据:", n)
  if(n <= 1) { // 最后当n小于等于1的时候,直接返回1,结束函数的继续执行
    return 1
  }
  // 输出完当前数据之后,继续输出下一个数据(比当前数据小于1的数据)
  return fn(n - 1)
}

fn(5)   // 5, 4, 3, 2, 1

代码在内存中的执行情况,如图所示:

  • 递归执行,相当于当前声明的函数在内存中一遍又一遍的创建对象,并执行函数内部的代码,内部递归的函数执行没有完成时,函数占用的内存空间不会释放
  • 企业开发规范:如非必要不要使用函数递归方式处理复杂计算问题;如果一定要使用递归来处理问题,建议递归的循环次数一般不要超过5次
  • 问题:递归函数,在执行过程中如果不控制递归次数,很容易占满内存空间导致程序运行的内存被消耗完毕(专业术语:内存溢出),程序崩溃退出

4.2 函数的闭包

4.2.1 认识闭包

闭包closure,函数的一种高级语法,描述了在函数的内部,声明一个内部函数的语法

// 函数的闭包
function outerFn() {// 外部函数
  // ...
  function innerFn() { // 内部函数(闭包函数),声明在外部函数的内部
    // ...
  }
  
  return innerFn    // 返回内部函数,方便函数的使用
}
4.2.2 闭包基本语法

闭包基本语法和使用

  • 了解函数的闭包,完整语法
  • 了解闭包函数的调用方式
// 函数的闭包:目标-先熟悉语法
function outerFn() {
  // 局部变量: 一般都是声明在函数内部,只在当前函数内部可以被访问
  var total = 200

  // 闭包函数
  function jiSuan(dat) {
    var result = total + dat
    return result
  }

  // 返回了内部的闭包函数(返回的是函数的声明)
  return jiSuan
}

// 调用外部函数,获取到内部函数
var inFn = outerFn()  // inFn 是一个函数

// 继续执行获取到的闭包函数:outerFn()函数的外部,直接操作局部变量的数据
var res = inFn(300)
console.log("res:" , res)

小总结:关于闭包的语法

闭包函数:本质上就是函数

闭包函数的语法:在一个函数的内部,声明了一个内部函数

为什么要使用闭包:扩展函数内局部变量的访问范围、解决变量的全局污染问题

使用闭包函数注意的问题:内存占用的问题

function outerFn() {
// ...
// 重点:一个函数声明在其他函数的内部 | 特殊的声明位置
function innerFn() {
 // ...
}

// 返回内部的函数声明
return innerFn
}

// 调用:调用外部函数,获取到闭包函数
var inFn = outerFn()    // inFn也是一个函数
// 通过inFn 调用闭包函数
var result = inFn()     // 调用执行inFn这个函>数,就是innerFn函数
4.2.3 关于全局污染问题

需求:开发一个函数,用于计程车 计价器,计算打车过程的费用

// 实际项目开发的时候,每个人/每个团队负责的功能非常多;大量的代码混合在一个文件中

// 需求:开发一个函数,用于计程车 计价器,计算打车过程的费用
var sum = 0; // 总费用
// 计价器函数
function jiJiaQi(msg, money) {
  console.log(msg + ":" + money + "元")
  sum += parseInt(money)
}

// 模拟:打车
jiJiaQi("启动-启动价", 5)

jiJiaQi("行驶5公里", 15) // 每公里3元

// ---------------开发人员,开发其他算法功能,修改当前文件
var sum = 0
for(var i = 1; i <= 100; i++) {
  sum += i
}
console.log("sum 1~100的和:", sum)
// -----------------

jiJiaQi("堵车", 4)  // 堵车一次4元

jiJiaQi("行驶3公里", 9)

console.log("到达目的地,总价格:", sum, "元")  // 总价格: 5063 元


// 思考上述代码
// 1、代码有没有报错?  没有
// 2、上述代码包含几项功能?  2项:打车计价器、算法求和
// 3、代码运行结果正确吗? 算法求和:正确;打车计价器:不正确
// 为什么?
// 两项功能中,使用了相同名称的全局变量,导致数据互相覆盖
// 专业术语:变量的全局污染,开发的项目中出现大量代码,使用全局变量的时候
// 出现了数据的互相影响,导致运行结果错误,这样的问题称为全局污染问题
4.2.4 闭包案例

函数的闭包,主要解决 局部变量的访问范围、变量全局污染的问题

需求:使用闭包,完计价器程序的开发

// 声明一个计程车函数;通过计程车可以获取到计价器
function taxi() {

  // 总价格:局部变量
  var sum = 0;   

  // 计价器
  function jiJiaQi(msg, money) {
    console.log(msg + ":" + money + "元")
    sum += parseInt(money)
    return sum
  }
  // 返回计价器
  return jiJiaQi
}

// 执行函数,获取计程车的计价器
var jjq = taxi()

jjq("起步", 5)
jjq("行驶5公里", 15)
jjq("堵车", 4)
var s = jjq("行驶3公里", 9)

console.log("达到目的地:费用", s, "元")
// 如何解决全局污染问题?
// 如果声明的变量不是全局变量,不就不存在全局污染问题了吗?!

// 声明一个计程车函数;通过计程车可以获取到计价器
function taxi() {

  // 总价格:局部变量
  var sum = 0;   

  // 计价器
  function jiJiaQi(msg, money) {
    console.log(msg + ":" + money + "元")
    sum += parseInt(money)
    return sum
  }
  // 返回计价器
  return jiJiaQi
}

// 闭包:开发一个算法引用,计算m~n的和
function calculation() {
  // 记录总和的局部变量
  var sum = 0

  function add(m, n){
    for(var i = m; i <= n; i++) {
      sum += i
    }
    return sum
  }

  return add
}

// 执行函数,获取计程车的计价器
var jjq = taxi()

jjq("起步", 5)
jjq("行驶5公里", 15)

// 使用算法应用 - 这里的算法代码,不会影响计程车数据运算,解决全局污染问题
var ad = calculation()
var res = ad(1, 100)
console.log("1~100的和:", res)

jjq("堵车", 4)
var s = jjq("行驶3公里", 9)

console.log("达到目的地:费用", s, "元")

4.3 自执行函数

需求:网页加载的时候就需要网页中出现一些特效,如轮播图、选项卡、楼层效果、背景特效之类的,能不能网页中引入javascript文件时就让代码执行?

4.3.1 代码编写即刻执行

代码写在全局的范围,只需要写了代码立即会执行

  • 代码的执行,没有问题

  • 存在的缺陷:因为网页中存在多种效果,可能会引起全局污染

// 1、代码直接下载全局范围,写完代码就会立刻执行
// 轮播图效果[模拟]
var effect1 = "轮播图"
console.log(effect1)

// 选项卡效果
var effect2 = '选项卡'
console.log(effect2)

// 楼层效果
var effect3 = "楼层效果"
console.log(effect3)
4.3.2 函数封装调用执行

将对应的网页特效,封装到多个独立的函数中,调用执行

  • 每个网页特效的代码都是 独立的函数 开发
  • 存在的小缺陷:某些特效的函数代码,网页渲染的过程中只会调用一次,标准的函数声明和调用语法,让函数声明和调用分散/代码量增加
    • 期望:某些只会执行一次的函数,能不能让函数在声明的时候就立刻执行
// 2、函数封装对应的特效,调用执行函数
function bannerEffect() {
  // 声明和轮播图相关的局部变量
  console.log("轮播图效果")
}

function tabEffect() {
  // 声明和选项卡效果相关的局部变量
  console.log("选项卡效果")
}

function floorEffect() {
  // 声明和楼层效果相关的局部变量
  console.log("楼层效果")
}

// 调用执行
bannerEffect()
tabEffect()
floorEffect()
4.3.3 自执行函数

自执行函数:函数在声明的同时就调用执行,这样的函数只会执行一次!

// 3、自执行函数:基本语法
// 解释器依然会将 函数 解释成函数的声明;不会立即执行
// 如果大括号后面添加一对圆括号,引发语法错误:原因~这不是一个完整的表达式
// 表达式:参与运算的数据+符号
// function fn() {
//   console.log("函数内部的代码执行了")
// }()

// 通过函数名称调用执行
// fn()

// 第一种写法:将函数的声明+调用 使用小括号包含起来
// 建议大家编写的时候,前后的代码行都主动加上代码结尾的分号
// 无参数
(function fn() {
  console.log("函数内部的代码执行了(1)")
}());
// 带参数
(function fn(name) {
  console.log("函数内部的代码执行了(1)", name)
}("文帝"));

// 第二种写法:将函数的声明部分,用小括号包含起来当成表达式
// 无参数
(function fn2() {
  console.log("函数内部的代码执行了(2)")
})();
// 带参数
(function fn2(msg) {
  console.log("函数内部的代码执行了(2)", msg)
})("参数数据");

// 第三种写法:可以在函数的前面,添加一个运算符当成表达式
// 一般自执行函数前面添加的运算符,常见的 ~、-、+、!... 
// 无参数
!function fn() {
  console.log("函数内部的代码执行了(3)")
}();
// 带参数
!function fn(param) {
  console.log("函数内部的代码执行了(3)", param)
}("运算符自执行函数");

// 第四种写法:可以使用关键字void,将函数声明变成一个表达式
// 无参数
void function fn() {
  console.log("自执行函数内部代码执行了(4)")
}();
// 带参数
void function fn(args) {
  console.log("自执行函数内部代码执行了(4)", args)
}("javascript");

// 第五种写法:使用方括号包含函数的声明+调用,将函数执行过程当成表达式
// 无参数
[function fn() {
  console.log("自执行函数执行了..(5)")
}()];
// 带参数
[function fn(vip) {
  console.log("自执行函数执行了..(5)", vip)
}("一种特殊语法")];

小总结:关于自执行函数,项目中常见的声明和执行语法有上述5种,实际开发时项目规范中要求较多的方式只有两种:

// 第一种常见的自执行函数语法
(function fn() {
  // 函数内部的代码
})()

(function fn() {
  // 函数内部的代码
}())
// 第二种常见语法,函数声明前的符号可以变化,如~、+、-等等
!function() {
  // 函数内部的代码
}()

4.4 总结

今天的学习目标:熟悉函数的各种高级操作语法

(1) 什么是函数递归?

函数递归recursion,描述了函数在自己的内部代码中调用自身的过程

(2) 为什么要使用函数递归?

函数递归本质上是循环的过程,相比较普通循环,可以让业务的处理流程更加清晰,提高了代码语义的可读性

(3)使用递归需要注意哪些问题?

需要注意递归算法的运算次数;因为在递归过程中会在内存中创建大量的函数对象,很容易造成内存溢出导致程序崩溃!

(4) 什么是函数闭包?

函数闭包closure,描述了在一个函数的内部声明函数的语法;扩展了外部函数中局部变量的访问范围,同时避免了多功能开发时的变量全局污染问题!

(5) 为什么要使用闭包

使用闭包的好处很多,常见的:

  • 扩展函数中局部变量访问范围
  • 避免变量和函数的去全局污染问题
  • 将功能相似的变量和函数代码统一封装,方便维护

(6) 使用闭包需要注意什么问题?

使用闭包函数时,只要内部函数还在使用,外部函数占用的内存空间就不会释放(专业术语:常驻内存),如果一个项目中出现大量的闭包函数很容易造成占用内存无法释放的问题(专业术语:内存泄漏),严重的话会导致内存耗尽程序崩溃(专业术语:内存溢出)

(7) 什么是自执行函数?

自执行函数,就是描述了函数在声明的同时就立即执行的一种语法结构

(8) 你了解哪些自执行函数的语法

自执行函数的语法很多,常见的有如下几种

// 第一种
(function() {...} ())

// 第二种
(function(){...}) ()

// 第三种
!function() {...} ()
             
// 第四种
void function() {...}()
                 
// 第五种
[function() {...}()]           

(9) 为什么要使用自执行函数?

网页中一些特效、一些功能,在网页第一次加载的时候需要执行并且只需要执行一次;这样的情况为了编码简单建议使用自执行函数来完成;自执行函数可以在函数声明的同时直接执行函数内部代码,方便维护!

九、事件概述

1.认识事件

事件Event,描述了根据用户在网页中的操作行为,执行一定的功能的操作过程

JavaScript是一门事件驱动的编程语言!

  • 事件驱动:用户的操作行为引发的一系列后续功能!

网页中用户常见的操作行为(事件):

  • 鼠标相关:点击、双击、移动、移入/移除/悬浮…
  • 键盘相关:按键按下/按住/抬起…
  • 输入相关:输入框获取焦点 / 输入框改变内容 / 输入框失去焦点…
  • 网页相关:复制 / 剪贴 / 粘贴 / 加载 / 滚动…

2.事件的绑定

网页中事件的绑定方式,常见的有三种

  • 标签属性绑定
  • JavaScript对象属性绑定
  • 标准事件绑定函数addEventListener

代码操作:

<!DOCTYPE html>
<html lang="zh">
<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>事件绑定方式</title>
</head>
<body>
  <h3>1、标签绑定</h3>
  <!-- 
    通过标签的事件属性,指定一个执行函数
    当指定的事件发生时,对应的函数就会执行
    onclick 单击事件
    当用户点击了当前按钮,对应的hanlder()函数就会执行

    注意:不能同时绑定多个事件函数;只有第一个会生效
  -->
  <button onclick="handler()"
          onclick="handler2()">点击我试试</button>

  <h3>2、对象绑定方式</h3>
  <button id="btn">对象来了</button>

  <h3>3、事件标准绑定方式</h3>
  <button id="my-btn">标准语法来了</button>

  <script>
    // 1-1 事件处理函数
    function handler() {
      alert("你点我干吗,今天又不休息!!!")
    }

    function handler2() {
      alert("没有关系,今天已经周三了..")
    }

    // 2-1 对象绑定函数
    var _btn = document.getElementById("btn")

    // 通过对象的事件属性,给事件添加一个处理函数
    // 事件名称,大小写敏感(不能写错onClick 和onclick是两个不同的东西)

    // 不能同时绑定多个事件处理函数
    // 如果写了多个事件处理函数,最后一个生效(解释型特点)
    _btn.onclick = function() {
      alert("还有两天本周又结束了...")
    }

    _btn.onclick = function() {
      alert("提前祝大家周末愉快...")
    }

    // 3-1 标准事件绑定方式
    var _myBtn = document.getElementById("my-btn")

    // 通过固定函数,给标签对象绑定事件
    // addEventListener: add 增加  Event 事件 Listener 监听
    // 标准语法下:事件名称不需要添加on单词,单击事件click
    // 标准语法下:可以给一个标签对象,添加多个相同事件
    _myBtn.addEventListener("click", function() {
      alert("本周学习目标:语法进阶")
    })

    _myBtn.addEventListener("click", function() {
      alert("本周锻炼:开始出现自己的编程思路")
    })

  </script>
</body>
</html>

关于事件面试题:简单描述一下JavaScript中事件绑定时如何处理兼容性问题?

分析:这个问题归结于历史原因!

软件行业发展过程中,有一家公司微软开发了自己特立独行的浏览器:探险家/IE,内核中使用了大量和其他浏览器不同的程序,所以导致后续开发的很多应用都需要兼容IE

JavaScript中绑定事件的标准语法,为了兼容IE6~IE11,事件绑定语法:

  • IE浏览器:绑定事件addEventListener(事件名称, 处理函数)
  • IE浏览器:绑定事件attachEvent(事件名称,处理函数)

思考题:事件可以绑定,那么事件可以取消吗?

3.事件的取消

绑定到标签上的事件,是可以取消的!

对象属性绑定的事件,取消

// 绑定事件
_btn.onclick = function() {...}

// 取消事件
_btn.onclick = null

标准语法绑定事件,取消

function handler() {
  // 事件处理函数
}
// 绑定事件
_btn.addEventListener("click", handler)

// 取消指定事件
_btn.removeEventListener("click", handler)

4.this关键字

this英文单词:本意~这、这个的意思,代码中指代当前对象,一般类似生活中名词

编码过程中,为了方便的操作数据,函数中经常出现this关键字

// 1、全局函数中的this,指向浏览器窗口对象
function fn() {
  // 普通声明的函数,this指向的是浏览器窗口对象Window
  console.log("this:", this)
}
// 函数的调用
// fn()
// window.fn()

// 以前弹窗
// alert("这是一个弹窗")
// window.alert("这是一个浏览器弹窗")


// 2、事件函数
var _btn = document.getElementById("btn")
_btn.onclick = function() {
  // 事件操作函数中,this指向当前操作标签
  console.log("事件函数this:", this)
}

// 3、标准语法
var _btn2 = document.getElementById("btn2")
_btn2.addEventListener("click", function() {
  // 事件函数中,this指向的是当前操作标签
  console.log("addEventListener this:", this)
})

5.常见网页事件[了解]

一般和网页相关的事件,包含网页加载、鼠标事件、键盘事件等等

常见事件:

事件名称描述
onclick单击事件鼠标左键点击
ondblclick双击事件鼠标左键双击
onmouseenter鼠标进入鼠标光标从元素外移动到元素上
onmouseover鼠标悬浮鼠标光标在目标元素上
onmouseleave鼠标离开鼠标光标从元素上移动到元素外
onkeydown按键按下键盘上任意按键,按下时触发
onkeyup按键抬起
oncopy复制
oncut剪贴
onparse粘贴
onload网页加载网页第一次在浏览器中加载,加载完成时触发
onscroll滚动条网页中滚动条滚动时触发
onresize窗口尺寸变化浏览器可视窗口大小发生变化时触发

扩展阅读:网页中常见事件

  1. 鼠标事件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LtTHOchI-1660302104333)(assets/image-20220810114253514.png)]

  1. 键盘事件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iiKN8BSy-1660302104335)(assets/image-20220810114311433.png)]

  1. 触摸事件(了解)

触摸touch事件 说明
touchstart 手指触摸到一个 DOM 元素时触发
touchmove 手指在一个 DOM 元素上滑动时触发
touchend 手指从一个 DOM 元素上移开时触发

  1. 表单事件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-br07ATU0-1660302104336)(assets/image-20220810114355214.png)]

  1. 过渡事件

过渡事件 触发条件
ontransitionend 在过渡完成时触发

  1. 动画事件

动画事件 触发条件
onanimationend 在动画结束播放时触发
onanimationiteration 在动画重复播放时触发
onanimationstart 在动画开始播放时触发

6.事件对象[重点]

什么是事件对象?

事件对象event,描述了一个正在发生的事件行为!可以在事件的处理函数中直接获取到并通过事件对象操作某些数据!

如何获取事件对象

  • 为什么要获取事件对象?为了通过事件对象直接处理某些数据,如用户在页面中点击了鼠标,需要获取鼠标在网页中的位置!
<body>
  
  <button onclick="fn()">获取事件对象</button>

  <script>
    // 添加一个单击事件
    // 如果没有给事件函数传递参数,默认第一个参数就是事件对象
    function fn(e) {
      // 事件对象,存在兼容性问题,获取的时候需要判断赋值
      var e = e || event
      console.log("事件对象:", e)
    }
</script>
</body>

事件对象的重要属性

事件对象中,需要关注的属性如下表

属性描述
altKey操作事件时有没有按下Alt按键
ctrlKey操作事件时有没有按下Ctrl按键
shiftKey操作事件时有没有按下shift按键
clientX / clientY鼠标指针 相对于 浏览器可视窗口左上角定位
pageX / pageY鼠标指针 相对于 网页文档 左上角定位
offsetX / offsetY鼠标指针 相对于 操作的标签 左上角的定位
screenX / screenY鼠标指针 相对于 电脑屏幕 左上角的定位
layerX / layerY了解、鼠标指针相对于 定位父元素/body 左上角的定位
x / y 了解,鼠标指针相对于 父文档 左上角的定位

事件执行过程[3个阶段]

原生JavaScript语法中,规范了事件的执行过程,区分为三个阶段

  • 捕获阶段:查询那个目标标签被点击
  • 目标阶段:被操作的标签上事件触发,并执行对应的函数
  • 冒泡阶段:标签上的事件触发完成,将事件继续向父标签传递,一直到根标签

一个单击事件,在网页中触发的三个阶段。

事件-阻止冒泡

实际项目开发中,事件的冒泡是一个很重要的功能,但是在某些特效中需要阻止冒泡:也就是具体目标元素上的事件一旦触发,不允许事件继续向上冒泡,会影响网页特效

原生JavaScript中提供了阻止冒泡的语法,通过事件对象进行操作:

// 固定语法
if(event.stopPropagation) {
  event.stopPropagation()  // 通用阻止事件冒泡的方式
} else {
  event.cancelBubble = true  // 兼容IE系列浏览器阻止冒泡的方式
}

事件-阻止默认行为

给超链接标签,添加单击事件;发现事件触发的同时页面也发生了跳转;

项目中的某些特效开发过程中,需要这样的行为按照代码执行逻辑发生,而不是跟随标签自动产生!

原生JavaScript语法中,提供了阻止默认行为的操作方式:

if(e.preventDefault) {
  e.preventDefault()			// 传统浏览器阻止标签默认行为
} else {
  e.returnValue = false   // IE系列浏览器阻止标签默认行为
}

代码操作:

<body>
  <a href="http://www.baidu.com" id="alink">百度一下</a>

  <form action="http://www.baidu.com">
    <button id="btn">点击按钮</button>
  </form>

  <script>
    var _alink = document.getElementById("alink")

    // 1、事件触发了,弹窗展示了
    // 2、页面也发生了跳转(超链接标签默认行为)
    _alink.onclick = function(e) {
      // 阻止超链接默认行为
      var e = e || window.event
      if(e.preventDefault) {
        e.preventDefault()
      } else {
        e.returnValue = false
      }

      alert("用户点击了超链接按钮:正在升级中")
    }
  
    var _btn = document.getElementById("btn")

    // 1、点击按钮,触发事件函数,弹窗展示
    // 2、form标签自带提交功能导致页面跳转(默认行为)
    _btn.onclick = function(e) {
      // 阻止表单的默认行为
      var e = e || window.event
      if(e.preventDefault) {
        e.preventDefault()
      } else {
        e.returnValue = false
      }
      
      alert("验证表单数据:暂时不提交")
    }
  </script>
</body>

7.特效案例开发

7.1 选项卡效果

网页中的选项卡效果,也称为tab效果

点击每个选项卡,让对应的内容显示出来,比较繁杂的版本:

<!DOCTYPE html>
<html lang="zh">

<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; box-sizing: border-box;}
    #box{
      width: 400px;
      height: 400px;
      border:solid #888 1px;
      border-radius: 5px;
      overflow:hidden;
      margin: 50px auto;
      
    }
    #title{
      height: 50px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      border-bottom: 2px orangered solid;
    }
    #title span{
      display: block;
      text-align: center;
      line-height: 50px;
      flex: 1;
    }
    #title span.active{
      background: orangered;
      color: white;
    }
    #content{
      position: relative;
    }
    #content p{
      position: absolute;
      top: 10px;
      left: 10px;
      opacity: 0;
      transition: all .2s;
    }
    #content p.active{
      opacity: 1;
    }
  </style>
</head>

<body>
  <div id="box">
    <div id="title">
      <span class="active">新闻</span>
      <span>动态</span>
      <span>通知</span>
    </div>
    <div id="content">
      <p class="active">新闻内容~~小佩挺厉害</p>
      <p>动态~~国内有能人</p>
      <p>通知~~哪里来的中线?</p>
    </div>
  </div>

  <script>
    // 1、获取所有需要的标签
    // 获取页面中所有的span标签
    var _spans = document.getElementsByTagName("span")
    // 获取页面中所有的p标签
    var _p = document.getElementsByTagName("p")

    // 1-1 点击第一个_span标签时,显示第一个_p内容
    _spans[0].onclick = function() {

      // 删除所有的_span标签的active样式
      for(var i = 0 ; i <_spans.length; i++) {
        _spans[i].className = ""
      }
      _spans[0].className= "active"
      
      // 让所有的_p元素的透明度变成0,然后让第一个_p透明度变成1
      for(var i = 0; i < _p.length; i++) {
        _p[i].style.opacity = 0
      }
      _p[0].style.opacity = 1
    }

    // 1-2 点击第二个_span标签时,显示第二个_p内容
    _spans[1].onclick = function() {

      // 删除所有的_span标签的active样式
      for(var i = 0 ; i <_spans.length; i++) {
        _spans[i].className = ""
      }
      _spans[1].className= "active"

      // 让所有的_p元素的透明度变成0,然后让第一个_p透明度变成1
      for(var i = 0; i < _p.length; i++) {
        _p[i].style.opacity = 0
      }
      _p[1].style.opacity = 1
    }

    // 1-3 点击第三个_span标签时,显示第三个_p内容
    _spans[2].onclick = function() {

      // 删除所有的_span标签的active样式
      for(var i = 0 ; i <_spans.length; i++) {
        _spans[i].className = ""
      }
      _spans[2].className= "active"

      // 让所有的_p元素的透明度变成0,然后让第一个_p透明度变成1
      for(var i = 0; i < _p.length; i++) {
        _p[i].style.opacity = 0
      }
      _p[2].style.opacity = 1
    }

  </script>
</body>

</html>

通过循环,给span标题添加单击事件

<!DOCTYPE html>
<html lang="zh">

<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; box-sizing: border-box;}
    #box{
      width: 400px;
      height: 400px;
      border:solid #888 1px;
      border-radius: 5px;
      overflow:hidden;
      margin: 50px auto;
      
    }
    #title{
      height: 50px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      border-bottom: 2px orangered solid;
    }
    #title span{
      display: block;
      text-align: center;
      line-height: 50px;
      flex: 1;
      cursor: pointer;
    }
    #title span.active{
      background: orangered;
      color: white;
    }
    #content{
      position: relative;
    }
    #content p{
      position: absolute;
      top: 10px;
      left: 10px;
      opacity: 0;
      transition: all .2s;
    }
    #content p.active{
      opacity: 1;
    }
  </style>
</head>

<body>
  <div id="box">
    <div id="title">
      <span class="active">新闻</span>
      <span>动态</span>
      <span>通知</span>
      <span>公告</span>
    </div>
    <div id="content">
      <p class="active">新闻内容~~小佩挺厉害</p>
      <p>动态~~国内有能人</p>
      <p>通知~~哪里来的中线?</p>
      <p>公告~~演习正在进行中..</p>
    </div>
  </div>

  <script>
    // 1、获取所有需要的标签
    // 获取页面中所有的span标签
    var _spans = document.getElementsByTagName("span")
    // 获取页面中所有的p标签
    var _p = document.getElementsByTagName("p")

    // 2、循环给标题添加单击事件
    for(var i = 0; i < _spans.length; i++) {
      // 注意事项:一旦循环中出现函数,尽量避免在函数内部操作索引!!!
      // 给当前正在循环的标签,添加一个自定义属性index,记录自己的索引
      _spans[i].index = i
      // 添加单击事件
      // _spans[i].onclick = function() {
      _spans[i].onmouseenter = function() {
        // alert("用户点击了标题:" + this.index)
        
        // 取消所有标题class="active",让当前正在点击的标题添加active
        for(var j = 0; j < _spans.length; j++){
          _spans[j].className = ""
        }
        this.className = "active"

        // 让所有的内容隐藏,让和标题对应的内容显示
        for(var z = 0; z < _p.length; z++){
          _p[z].className= ""
        }
        _p[this.index].className = "active"
      }
    }

  </script>
</body>

</html>

7.2 树形菜单

基本功能实现

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  <ul>
    <li>1、课程大纲</li>
    <li>2、课程内容
      <ul>
        <li>2.1 事件概述</li>
        <li>2.2 事件对象</li>
        <li>2.3 事件操作
          <ul>
            <li>2.3.1 阻止冒泡</li>
            <li>2.3.2 阻止默认行为</li>
          </ul>
        </li>
        <li>2.4 事件特效</li>
      </ul>
    </li>
  </ul>
  <script>
    // 获取所有的li元素【菜单】
    var _lis = document.getElementsByTagName("li")

    
    for(var i = 0; i < _lis.length; i++){
      // 点击菜单
      _lis[i].onclick = function() {
        // 大家可以测试一下事件冒泡:点击不同的菜单,查看弹窗的次数
        // alert("用户点击了菜单")

        // 思路:如果当前li包含子元素ul,显示->隐藏 隐藏->显示
        // 解决问题1:如何获取子元素ul
        // 解决问题2:如何获取和设置子元素ul上的样式
        
      }
    }
  </script>
</body>
</html>

树形菜单点击实现

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  <ul>
    <li>1、课程大纲</li>
    <li>2、课程内容
      <!-- 添加了行内样式,让子菜单 显示 ------------------------------>
      <ul style="display: block">
        <li>2.1 事件概述</li>
        <li>2.2 事件对象</li>
        <li>2.3 事件操作
          <ul style="display: block">
            <li>2.3.1 阻止冒泡</li>
            <li>2.3.2 阻止默认行为</li>
          </ul>
        </li>
        <li>2.4 事件特效</li>
      </ul>
    </li>
  </ul>
  <script>
    // 获取所有的li元素【菜单】
    var _lis = document.getElementsByTagName("li")

    
    for(var i = 0; i < _lis.length; i++){
      // 点击菜单
      _lis[i].onclick = function(e) {
        // 3、通过事件对象阻止冒泡---------------------------------------
        var e = e || window.event;
        if(e.stopPropagation) {
          e.stopPropagation()
        } else {
          e.cancelBubble = true
        }

        // 大家可以测试一下事件冒泡:点击不同的菜单,查看弹窗的次数
        // alert("用户点击了菜单")

        // 思路:如果当前li包含子元素ul,显示->隐藏 隐藏->显示
        // 解决问题1:如何获取子元素ul
        // 搜索的答案:标签.children 获取
        // 解决问题2:如何获取和设置子元素ul上的样式
        
        // 2、获取子标签,根据子标签的display样式,切换 显示或者隐藏
        var children = this.children
        if(children.length > 0) {
          // 显示 / 隐藏子菜单
          var child = children[0]
          // console.log(child, "child子菜单")
          // console.log(child.style.display, "display")
          if(child.style.display === "block") {
            child.style.display = "none"
          } else {
            child.style.display = "block"
          }
        }
      }
    }
  </script>
</body>
</html>

7.3 自定义右键菜单

页面样式,修饰了自定义菜单

<!DOCTYPE html>
<html lang="zh">
<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; box-sizing: border-box;}
    #menu{
      transition: all .2s;
      position: absolute;
      width: 0px;
      height: 0px;
      opacity: 0; 
      /* width: 200px;
      height: 300px;
      opacity: 1; */
      background-color: #eff1f1;
      box-shadow: #888 2px 2px 0;
      display:flex;
      flex-direction: column;
      justify-content: space-between;
      list-style:none;
      border-radius: 5px;
      overflow:hidden;
    }
    #menu li{
      text-align:center;
      cursor:pointer;
      height: 55px;
      line-height: 55px;
    }
    #menu li:hover{
      background:#333;
      color: white;
    }
  </style>
</head>
  <body>
    <ul id="menu">
      <li>上一章</li>
      <li>下一章</li>
      <li>返回目录</li>
      <li>刷新</li>
      <li>返回首页</li>
    </ul>
  </body>
</html>

阻止浏览器默认右键菜单

<script>
    var _menu = document.getElementById("menu")
    // 鼠标右键单击事件
    // document 网页文档 根标签
    // oncontextmenu事件:鼠标右键事件
    document.oncontextmenu = function(e) {
      // 阻止鼠标右键默认行为
      var e = e || window.event
      if(e.preventDefault) {
        e.preventDefault()
      } else {
        e.returnValue = false
      }
    }
</script>

显示自定义右键菜单

document.oncontextmenu = function(e) {
  // 阻止鼠标右键默认行为
  var e = e || window.event
  if(e.preventDefault) {
    e.preventDefault()
  } else {
    e.returnValue = false
  }

  // 显示自定义菜单
  _menu.style.height = "300px"
  _menu.style.width = "200px"
  _menu.style.opacity = 1
  _menu.style.left = e.clientX + "px"
  _menu.style.top = e.clientY + "px"
}

隐藏右键菜单

// 空白处点击左键,自定义菜单消失
document.onclick = function() {
  // 隐藏自定义菜单
  _menu.style.height = "0px"
  _menu.style.width = "0px"
  _menu.style.opacity = 0
}

最终完成的代码如下:

<!DOCTYPE html>
<html lang="zh">
<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; box-sizing: border-box;}
    #menu{
      transition: all .2s;
      position: absolute;
      width: 0px;
      height: 0px;
      opacity: 0; 
      /* width: 200px;
      height: 300px;
      opacity: 1; */
      background-color: #eff1f1;
      box-shadow: #888 2px 2px 0;
      display:flex;
      flex-direction: column;
      justify-content: space-between;
      list-style:none;
      border-radius: 5px;
      overflow:hidden;
    }
    #menu li{
      text-align:center;
      cursor:pointer;
      height: 55px;
      line-height: 55px;
    }
    #menu li:hover{
      background:#333;
      color: white;
    }
  </style>
</head>
<body>
  <ul id="menu">
    <li>上一章</li>
    <li>下一章</li>
    <li>返回目录</li>
    <li>刷新</li>
    <li>返回首页</li>
  </ul>
  <script>
    var _menu = document.getElementById("menu")
    // 鼠标右键单击事件
    // document 网页文档 根标签
    // oncontextmenu事件:鼠标右键事件
    document.oncontextmenu = function(e) {
      // 阻止鼠标右键默认行为
      var e = e || window.event
      if(e.preventDefault) {
        e.preventDefault()
      } else {
        e.returnValue = false
      }

      // 显示自定义菜单
      _menu.style.height = "300px"
      _menu.style.width = "200px"
      _menu.style.opacity = 1
      _menu.style.left = e.clientX + "px"
      _menu.style.top = e.clientY + "px"
    }

    // 空白处点击左键,自定义菜单消失
    document.onclick = function() {
      // 隐藏自定义菜单
      _menu.style.height = "0px"
      _menu.style.width = "0px"
      _menu.style.opacity = 0
    }
  </script>
</body>
</html>

十、内置对象

1.字符串

1.1 字符串声明

JavaScript语法中通过String表示字符串,语法中一般显示为单引号或者双引号包含的一串字符;声明方式一般有两种:

字面量(常见)

// 1、字面量方式
var  techVersion = "V2022.2"  // 'V2022.2'
console.log( techVersion, "字面量")

对象创建

// 2、对象方式
var techInfo = new String("JavaScript")
console.log(techInfo, "对象")

1.2 字符串内存分析

面试题:请简单描述,下面的代码在内存中 创建了几个对象 | 分配了几个空间?

  • new创建的对象,都是需要在堆内存中创建的
  • 字符串作为一个项目中最常用的数据类型,编程语言为了提高字符串使用效率会将字符串存储到常量区,创建字符串对象时检查常量区中是否存在这个字符串(存在的话直接复制对象到堆内存;如果不存在的话创建对象并复制到堆内存)
  • 最终在内存中创建了3个对象 | 分配了3个空间
var str = new String("hello")

思考:如何查看字符串常见操作函数?

  • 浏览器控制台,查看字符串对象的操作函数
  • MDN网站上查看字符串常见操作函数
函数描述
charAt()查询某个索引的字符
charCodeAt()查询某个字符的ascii
includes(s)查询是否包含某个字符串s
indexOf(s)查询某个字符第一次出现的索引
lastIndexOf(s)查询某个字符最后一次出现的索引
match(s)查询某个字符串中是否包含目标字符串(开头位置)
search(s)查询某个字符串中是否包含目标字符串(所有位置)
startsWith(s)查询某个字符串是否以指定字符开头
endsWith(s)查询某个字符串是否以指定字符结尾
toUpperCase()将字符串所有字符转换成大写
toLowerCase()将字符串所有字符转换成小写
replace()替换字符串中的数据
repalceAll()替换字符串中所有匹配的数据
slice()截取字符串
substr(start, cnt)截取字符串
substring(start, end)截取字符串
trim()剔除字符串两侧空格
trimLeft() / trimStart()剔除字符串左侧空格
trimRight() / trimEnd()剔除字符串右侧空格
split()使用指定字符拆分字符串
padStart()字符串位数补全ES6
padEnd()字符串位数补全ES6

1.3 charAt(index)

作用:按照索引查询指定位置的字符

var str = "damu"
var result = str.charAt(3)
console.log(result) // u

案例:通过身份证检查性别

var regNo = "410440198011010010"
// 获取性别位
var gender = regNo.charAt(16)
console.log(gender % 2 == 0 ? "女性" : "男性")

1.4 charCodeAt()

作用:获取指定索引位置字符的ascii

var name = "damu"
var acode = name.charCodeAt(1)  // a
console.log(acode, "ascii") // 97

代码操作:检查客户的用户账号只能由字母和数字组成

// a~z   97 ~ 122
// A~Z   65 ~ 90
// 0~9   48 ~ 57
var name = "admin123"

// 验证账号是否合法的函数
function verify(account) {
  for(var i = 0; i < account.length; i++) {
    if( 
      	(97 <= account.charCodeAt(i) && account.charCodeAt(i) <= 122) ||
      	(65 <= account.charCodeAt(i) && account.charCodeAt(i)<= 90) ||
      	(48 <= account.charCodeAt(i) && account.charCodeAt(i)<= 57) 
    ) {
      console.log("继续循环验证")
    } else {
      console.log("账号中包含了非法字符")
      return  // return一旦执行,函数立即结束
    }
  }
  console.log("这是一个合法账号")
  return true
}

verify(name)

1.5 includes()

作用:判断字符串中是否包含指定的 字符串

var email = "1007821300@qq.com"

var result = email.includes('@qq.com')

console.log(result, "是否qq邮箱") // true

1.6 indexOf() / lastIndexOf()

作用:查询字符串中指定字符的索引位置

var str = "helloworld"

var index = str.indexOf("l")  // 2
var lindex = str.lastIndexOf("l") // 8

代码操作:判断目标字符串中是否有重复字符?

var str = "helloworld"

function verify(s) {
  for(var i = 0; i < s.length; i++) {
    if(s.indexOf(s.charAt(i)) !== s.lastIndexOf(s.charAt(i))) {
      console.log("字符串中存在重复字符")
      return false
    }
  }
  return true
}
verify(str)

1.7 match() / search()

作用:在字符串中查询目标字符串是否存在

  • 更加强大的用途,在以后学习正则表达式之后才会使用
var name = "helloworld"

name.match("hello")   // ["hello", index:0, ...]
name.search("hello")  // 0

name.match("world")   // ["hello", index:5, ...]
name.search("world")  // 5

1.8 startsWith () / endsWith()

作用:判断字符串是否以目标字符串开头 / 结束

var personalPage = "https://blog.csdn.net/xxx"
// 判断个人主页网址是否合法
var result = personalPage.startsWith("https://") // true

var email = "1007821300@qq.com"
// 判断用户是否使用了qq邮箱
var result2 = email.endsWith("@qq.com")  // true

1.9 toLowserCase() / toUpperCase()

作用:将目标字符串全部转换成小写 / 大写

// 用户输入了一个数据:是否结束购买(y/Y)?
var result = "y"  // "Y"

// 判断的时候直接转换一下进行判断
if(result.toUpperCase() === "Y") {
  console.log("用户结束购买流程")
}

// 判断目标数据是否数值类型?
var num = 12
if(typof(num).toLowerCase() === "number") {
  console.log("这是一个数值类型的数据")
}

1.10 replace() / replaceAll()

作用:字符串替换,一般用于敏感数据/关键字替换

var str = "helloworld"

str.replace("l", "*")   // he*loworld

str.replaceAll("l", "*") // he**owor*d

1.11 slice() / substr() / substring()

作用:截取字符串

// 身份证号码:日期获取
var regNo = "410440198011010010"

regNo.slice(6, 14)  // 19801101
regNo.substr(6, 8)  //  19801101
regNo.substring(6, 14) // 19801101

代码操作:获取一个6位数验证码

var rcode = Math.random().toString(36).substr(2, 6)
// '0.0hv7akbt803b'
// substr(2, 6) -> hv7akb

1.12 trim() / trimLeft() / trimRight()

作用:用于剔除字符串两侧的空格

var name = "         admin    "

name.trim()    // "admin"

name.trimLeft()			// "admin         "
name.trimStart()    // "admin         "

name.trimRight()    // "        admin"
name.trimEnd()       // "        admin"

1.13 split()

作用:使用特定字符,拆分字符串;经常和数组的join()配合使用

var fav = "吃饭,游戏,电影,睡觉,打豆豆"

var frr = fav.split(",")	// (5) ['吃饭', '游戏', '电影', '睡觉', '打豆豆']

frr.join(",")  // "吃饭,游戏,电影,睡觉,打豆豆"

1.14 padStart() / padEnd()

作用:给定字符串位数,如果位数不够~使用补充字符来凑

for(var i = 0; i <= 99; i++) {
  console.log("编号:", i.toString().padStart(2, "0"))
}
/*
00
01
02
...
11
12
...
99
*/

2.数学对象

JavaScript语法中提供了一个辅助数学运算的内置对象:Math,包含了大量的辅助属性和函数,可以直接通过类型名称调用

MDN网站地址:关于Math的属性和函数

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math
属性函数是否常用
Math.E自然对数的底数,常量,2.718基本不用
Math.LG1010的对数基本不用
Math.LN22的对数
Math.LOG10E 、Math.LOG2E
基本不用
Math.PI圆周率,常量,3.14159基本不用
Math.abs()abs: absolute,表示获取一个数据的绝对值
Math.acos()三角函数,反余弦值基本不用
Math.asin()三角函数,反正弦值基本不用
Math.atan()三角函数,反正切值基本不用
Math.cos()三角函数,余弦值基本不用
Math.sin()三角函数,正弦值基本不用
Math.tan()三角函数,正切值基本不用
Math.floor()向下取整,如1.2 -> 1; 1.6-> 1; 0.5 -> 0常用
Math.ceil()向上取整,如1.2 -> 2; 1.6 -> 2; 0.5 -> 1常用
Math.trunc()截断小数部分,如1.2-> 1; 1.6-> 1, 0.5 -> 0常用
Math.round()四舍五入,如1.2 -> 1; 1.6 -> 2; 0.5 -> 1常用
Math.max()获取一系列数据中的最大值常用
Math.min()获取一系列数据中的最小值常用
Math.pow(x, y)获取x数据的y次方,指数运算
Math.sqrt(x)获取x数据的平方根
Math.random()获取一个0~1之间的随机数常用

2.1 Math.floor(dat)

作用:对目标数据向下取整

var s = 1.2
var s2 = 1.6
var s3 = -3.5    // 注意

Math.floor(s)   // 1
Math.floor(s2)   // 1
Math.floor(s3)   // -4

2.2 Math.ceil(dat)

作用:对目标数据向上取整

var s = 1.2
var s2 = 1.6
var s3 = -3.5    // 注意

Math.ceil(s)  // 2
Math.ceil(s2)  // 2
Math.ceil(s3)  // -3

2.3 Math.trunc(dat)

作用:直接截断小数并丢弃小数部分,保留整数部分

var s = 1.2
var s2 = 1.6
var s3 = -3.5    // 注意

Math.trunc(s)  // 1
Math.trunc(s2)  // 1
Math.trunc(s3)  // -3

2.4 Math.round(dat)

作用:四舍五入

var s = 1.2
var s2 = 1.6
var s3 = -3.5    // 注意 负数【舍入关系】
var s4 = -3.6

Math.round(s)  // 1
Math.round(s2)  // 2
Math.round(s3)  // -3
Math.round(s4)  // -4

2.5 Math.max() / min()

作用:获取一系列数据中的最大值/最小值

Math.max(1,2,3,4,5,6,7,8,9)
// 9

Math.min(1,2,3,4,5,6,7,8,9)
// 1

Math.max([1,2,3,4,5,6,7,8])
// NaN
// 数组的最大值/最小值,依然需要使用Math.max()/min(),但是需要辅助函数(call/apply/bind)的支持
Math.max.apply(null, [1,2,3,4,5,6,7,8,9])
// 9

2.6 Math.pow(x,y)

作用:获取x的y次方

// 之前计算国王的棋盘,做过数据的累加

// 使用幂运算,可以很方便的得到结果
var result = Math.pow(2, 64) - 1
// 18446744073709552000

2.7 Math.random()

作用:获取0~1之间的随机数

// 1、获取0~1之间的随机数
Math.random()
// 0.0829069892673493

// 2、获取0~10之间的随机数?
Math.random() * 10

// 3、随机数字符串的表示方式
// Math.random().toString()
Math.random().toString(10)
'0.5103483233951225'

// 4、随机数-附带随机字母表示方式
Math.random().toString(36)
'0.6f677cxmv78'

思考:使用数学对象的函数,随机输出骰子的点数【1,2,3,4,5,6】?

Math.ceil(Math.random() * 6)

3.日期对象

JavaScript针对日期时间,提供了一个内置对象Date,主要用于日期和时间的处理

3.1 创建日期对象

创建一个当前日期对象

var date = new Date()

创建一个指定的日期对象

var date = new Date('2022-10-1 00:00:00')

常见的操作函数

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date
函数描述
date.getFullYear()获取年份
date.getMonth()获取月份,月份以0~11表示
date.getDate()获取一个月第几天
date.getDay()获取一周第几天
date.getHours()获取小时
date.getMinutes()获取分钟
date.getSeconds()获取秒钟
date.getMilliSeconds()获取毫秒
date.getTime()获取1970/1/1 0:0:0年到现在的毫秒数
date.setFullYear()设置年份
date.setMonth()设置月份

3.2 日期时间展示

用户访问网页时,网页中显示当前时间

<!DOCTYPE html>
<html lang="zh">

<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>
</head>

<body>
  <div>尊敬的管理员,欢迎访问本系统,现在时间是: <span id="time">xxxx-xx-xx xx:xx:xx</span></div>
  <script>
    // window.onload :等待网页中所有标签加载完成后,再执行事件中的代码
    // 网页加载事件:保障代码运行时,网页标签已经加载完成
    window.onload = function () {


      // 获取当前时间的函数
      function getCurrentTime() {
        // 1、获取当前时间
        var date = new Date()  // var date = Date.now()

        // 2、拼接时间
        var t = date.getFullYear() + "年"
          + (date.getMonth() + 1) + "月"
          + date.getDate() + "日 "
          + date.getHours() + ":"
          + date.getMinutes() + ":"
          + date.getSeconds()

        return t
      }


      // 3、填写到页面中
      var _time = document.getElementById("time")
      _time.innerText = getCurrentTime()
    }
  </script>
</body>

</html>

4.延时函数

JavaScript语法中针对需要经过一定时间再去执行的函数、或者间隔一定时间去执行的函数,提供了两种功能性延时函数:

  • setTimeout(fn, time):代码运行到该函数,等待time毫秒后执行一次fn函数
    • clearTimeout() 清除延时函数
  • setInterval(fn, time):代码运行到该函数,每间隔time毫秒就会执行一次fn函数
    • clearInterval() 清除即使函数

4.1 基本语法

setTimeout()

<body>
  <div id="msg">普天之下莫非王土</div>
  <button id="btn">点击测试setTimetout</button>
  <button id="cancel">清除延时函数</button>
  <script>
    // 1、setTimeout
    var _msg = document.getElementById("msg")
    var _btn = document.getElementById("btn")
    var _cancel = document.getElementById("cancel")

    var time;
    // 点击添加延时延时
    _btn.onclick = function() {
      // 延时函数:2S后执行
      time = setTimeout(function() {
        _msg.innerText = "率土之滨莫非王臣"
      }, 5000)
    }
    // 点击取消延时函数
    _cancel.onclick = function() {
      clearTimeout(time)
    }

  </script>
</body>

setInterval()

// 2、setInterval
var _start = document.getElementById("start")
var _end = document.getElementById("end")

var inter;
_start.onclick = function() {
  inter = setInterval(function() {
    console.log("setInterval执行了...")
  }, 1000)
}

_end.onclick = function() {
  clearInterval(inter)
}

4.2 setTimeout案例

页面中摇动的骰子

<!DOCTYPE html>
<html lang="zh">

<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>
</head>

<body>
  <img src="./images/1.png" alt="" style="width:100px;height:100px;" id="img">
  <button id="btn">开始摇摆</button>
  <script>
    // 1、获取页面需要操作的标签对象 | DOM对象
    var _btn = document.getElementById("btn")
    var _img = document.getElementById("img")

    // 2、单击事件
    _btn.onclick = function () {
      // 设置一个摇摆的图片
      _img.src = "./images/x.gif"

      setTimeout(function () {
        // 随机点数
        var no = Math.ceil(Math.random() * 6)
        // 设置图片
        _img.src = "./images/" + no + ".png"
      }, Math.ceil(Math.random() * 4000) + 1000)
    }
  </script>
</body>

</html>

4.3 setInterval案例

页面中的数字时钟!

<!DOCTYPE html>
<html lang="zh">
<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>
    #time{
      font-size: 120px;
      font-family: "黑体";
    }
  </style>
</head>
<body>
  <p>当前时间:</p>
  <div id="time">0000-00-00 00:00:00</div>
  <script>
    window.onload = function() {

      // 获取当前时间的函数
      function getCurrentTime() {
        var date = new Date()

        return date.getFullYear()
               + "-" + (date.getMonth() + 1).toString().padStart(2, "0")
               + "-" + date.getDate().toString().padStart(2, "0")
               + " " + date.getHours() .toString().padStart(2, "0")
               + ":" +date.getMinutes() .toString().padStart(2, "0")
               + ":" + date.getSeconds().toString().padStart(2, "0")
      }

      // 计时函数执行,给页面添加数据
      var _time = document.getElementById("time")
      setInterval(function() {

        _time.innerText = getCurrentTime()

      }, 1000)
    }
  </script>
</body>
</html>

5.特效-倒计时

<!DOCTYPE html>
<html lang="zh">
<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>
</head>
<body>
  请输入目标时间:
  <input type="text" id="target">
  <button id="btn">开始倒计时</button>
  <div id="show">00 天 00 时 00 分 000</div>

  <script>
    window.onload = function() {

      // 1、获取要操作的标签对象 | DOM对象
      var _btn = document.getElementById("btn")
      var _show = document.getElementById("show")
      var _target = document.getElementById("target")


      // 2、单击按钮
      var time;
      _btn.onclick = function() {
        
        time = setInterval( function() {
          // 间隔80毫秒,执行一次倒计时函数
          var r = getTime()
          if(r){
            _show.innerText = r[0] + "天 " + r[1] + "时 " + r[2] + "分 " + r[3] + "秒 " + r[4]
          }
          
        }, 80)

        // getTime()
      }


      // 封装:获取倒计时时间的函数
      function getTime() {
        // 2-1 计算时差
        var now = new Date()
        var tgt = new Date(_target.value)
        console.log(now, tgt, "倒计时需要的时间数据")

        var distance = tgt - now
        // 两个时间相减,得到这两个日期之间的毫秒数
        // console.log(distance, " 时间差")
        if(distance <= 0) {
          alert("选择的目标时间必须大于当前时间")
          clearInterval(time)
          return
        }


        // 2-2 计算 毫秒数-> ?天 ?时 ?分 ?:?:?:?
        var d = Math.floor(distance /( 1000*60*60*24))
        console.log(d, "剩余天数")

        var h = Math.floor(distance / (1000 * 60 * 60) % 24)
        console.log(h, "剩余小时")

        var m = Math.floor(distance / (1000 * 60) % 60)
        console.log(m, "剩余分钟")

        var s = Math.floor(distance / (1000) % 60)
        console.log(s, "剩余秒钟")

        var ms = distance % 1000
        console.log(ms, "剩余毫秒")

        return [d.toString().padStart(2, 0), 
                h.toString().padStart(2, 0), 
                m.toString().padStart(2, 0), 
                s.toString().padStart(2, 0),
                ms.toString().padStart(3, 0)]
      }

    }
  </script>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值