JavsScript基础语法01

1. JavaScript的书写位置

JS 有3种书写位置,分别为行内、内嵌和外部。行内式写法如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS的书写位置</title>
</head>
<body>
<!--第一种: 行内式-->
<input type="button" value="点我试试" onclick="alert('Hello World')">
</body>
</html>
  1. 可以将单行或少量 JS 代码写在 HTML 标签的事件属性中(以 on 开头的属性) 如:onclick
  2. 可读性差,在 html 中编写 JS 大量代码时,不方便阅读
  3. 引号易错,引号多层嵌套匹配时,非常容易弄混
  4. 特殊情况下使用

内嵌式写法如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS的书写位置</title>
</head>
<body>
</body>
</html>
<script>
    alert("Hello World");
</script>
  1. 可以将多行 JS 代码写到 script 标签中
  2. 内嵌 JS 是学习时常用的方式

外部JS文件写法如下,先新建一个外部的 JS 文件,并在其中编写 JS 代码,然后在 HTML 中进行引入:
在这里插入图片描述
引入的 HTML 代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS的书写位置</title>
</head>
<body>
</body>
</html>
<!--第三种: 外部js文件 -->
<script src="test.js"></script>
  1. 利于 HTML 页面代码结构化,把大段 JS 代码独立到 HTML 页面之外,既美观,也方便文件级别的复用
  2. 引用外部 JS 文件的 script 标签中间不可以写代码
  3. 适合于 JS 代码量比较大的情况

2. JavaScript注释

为了提高代码的可读性,JSHTML/CSS 一样,也提供了注释功能。JS中的注释主要有两种,分别是 单行注释多行注释。示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>JS中的注释</title>
</head>
<body>

</body>
</html>
<script>
   // 单行注释的注释方式如下:
   // 我是Amo 不想被js引擎执行 注释起来 //用来注释单行文字
   // 一般单行注释的快捷键为: ctrl/command + /
   console.log(1111);  //控制台输出打印
   // 多行注释的注释方式如下:
   // 一般多行注释的快捷键为: ctrl/command + shift + / 不同的编辑器快捷键不同
   /*   1.发送请求获取响应
      2.判断请求是否成功 如果成功 解析数据
   * */
</script>

上述代码运行结果如下:
在这里插入图片描述

3. JavaScript输入输出语句

为了方便信息的输入输出,JS 中提供了一些输入输出语句,其常用的语句如下:

方法 说明 归属
alert(msg) 浏览器弹出警示框 浏览器
console.log(msg) 浏览器控制台打印输出信息 浏览器
prompt(info) 浏览器弹出输入框,用户可以输入 浏览器

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS中的输入输出语句</title>
</head>
<body>

</body>
</html>
<script>
    alert("Hello World");
    console.log("Hello World");
    // 可以使用一个变量来存储用户录入的值
    idCard = prompt("请输入您的身份证号码:");
    console.log(idCard);
</script>

4. 变量

变量就是一个装东西的盒子。变量是用于存放数据的容器。 我们通过 变量名 获取数据,甚至数据可以修改。
在这里插入图片描述
本质:变量是程序在内存中申请的一块用来存放数据的空间。类似我们酒店的房间,一个房间就可以看做是一个变量。为了节省空间,笔者后续给出的示例代码都将省略 HTML/CSS 的代码,变量的使用如下:

<script>
    //var是一个JS关键字,用来声明变量。使用该关键字声明变量后,计算机会自动为变量分配内存空间
    //第一种方式: 先声明 后赋值
    var age; //age 定义的变量名 要符合一定的规则 ==> 教室的门牌号
    age = 10; //赋值 ==>教室中的同学 通过age找到同学
    age = 20; //更新变量 即age被重新赋值
    //第二种: 变量的初始化 即声明变量的同时给它赋值
    var name = "Amo";
    //第三种: 同时声明多个变量
    var school = "重庆大学", address = "重庆市沙坪坝区";
</script>

变量命名规范:

  1. 由字母 (A-Za-z)、数字 (0-9)、下划线 (_)、美元符号 ( $ )组成,如:usrAge, num01, _name
  2. 严格区分大小写。var app; 和 var App; 是两个变量
  3. 不能以数字开头。 18age 是错误的
  4. 不能是关键字、保留字。例如:var、for、while
  5. 变量名必须有意义。 MMD BBD nl → age
  6. 遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。如:myFirstName

4.1 let 和 const命令

ES6 新增了 let 命令,用于声明变量。其用法类似于 var,但是所声明的变量只在 let 命令所在的代码块内有效。示例代码如下:

<script>
    //{}表示代码块
    {
        var a = 1;
        let b = 2;
    }
    console.log(a);
    console.log(b);
</script>

上述代码执行结果如下:
在这里插入图片描述
for 循环的计数器就非常适合 let 命令,示例代码如下:

<script>
    var arr1 = [];
    for (var i = 0; i < 10; i++) {
        arr1[i] = function () {
            return i;
        }
    }
    /*
        上述代码中 变量i是var声明的 即全局范围内有效,每一次循环i的值都会发生改变
        而循环内 被赋值给数组a的函数内部的i指向全局的i 所有数组a的成员中的i指向
        的都是同一个i 导致运行时输出的是最后一轮的i值也就是10。
     */
    console.log(arr1[2]());//10

    var arr2 = [];
    for (let i = 0; i < 10; i++) {
        arr2[i] = function () {
            return i;
        }
    }
    /*
        上面的代码中,变量i是let声明的,当前的i只在本轮循环有效。所以每一次
        循环的i其实都是一个新的变量,于是最后输出的是6。 JavaScript引擎内部
        会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行
        计算。
    */
    console.log(arr2[2]());//2
</script>

上述代码执行结果如下:
在这里插入图片描述
另外,for 循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。示例代码如下:

<script>
    for (let i = 0; i < 3; i++) {
        let i = "abc";
        console.log(i)
    }
</script>

上述代码执行结果如下:
在这里插入图片描述
正确运行以上代码将输出 3次abc 。这表明函数内部的变量 i 与循环变量 i 不在同一个作用域,而是有各自单独的作用域。let 声明变量不存在变量提升,示例代码如下:

<script>
    console.log(foo); //输出undefined
    var foo = 2;

    //let的情况
    console.log(bar);
    let bar = 2;
</script>

上述代码执行结果如下:
在这里插入图片描述
只要块级作用域内存在 let 命令,它所声明的变量就 绑定(binding) 这个区域,不再受外部的影响。示例代码如下:

<script>
    var temp = 123;
    if(true){
        temp = "abc";
        let temp;
    }
</script>

上述代码运行结果如下:
在这里插入图片描述
上面的代码中存在全局变量 temp ,但是块级作用域内 let又声明了一个全局变量 temp,导致后者绑定这个块级作用域,所以在 let 声明变量前,对 temp 赋值会报错。ES6 明确规定,如果区块中存在 letconst 命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。只要在声明之前就使用这些变量,就会报错。总之,在代码块中,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上称为 暂时性死区(temporal dead zone),简称 TDZ。在看看下面这个例子:

<script>
    console.log(typeof y); //undefined
    console.log(typeof x);
    let x;
</script>

上述代码执行结果如下:
在这里插入图片描述
上面的代码中,变量 x 使用 let 命令声明,所以在声明之前都属于 x死区 ,只要用到该变量就会报错。因此 typeof 运行时就会抛出一个 ReferenceError 。作为比较,如果一个变量根本没有被声明,使用 typeof 反而不会报错。这样的设计是为了让大家养成良好的编程习惯,变量一定要在声明之后使用,否则就会报错。有些 死区 比较隐蔽,不太容易发现。示例代码如下:

<script>
    function bar(x = y, y = 2) {
        return [x, y];
    }

    bar();//报错
</script>

上述代码执行结果如下:
在这里插入图片描述
上面的代码中,调用 bar 函数之所以报错(某些实现可能不报错),是因为参数 x 的默认值等于另一个参数 y ,而此时 y 还没有声明,属于 死区 。如果 y 的默认值是 x,就不会报错,因为此时 x 已经声明。另外下面的代码也会报错,与 var 的行为不同。

<script>
    var x = x;
    console.log(x)
    let y = y;
    console.log(y);
</script>

上述代码执行结果如下:
在这里插入图片描述
以上代码出错也是因为暂时性死区,使用 let 声明变量时,只要变量在还没有声明前使用,就会报错。let 不允许在相同作用域内重复声明同一个变量。示例代码如下:

<script>
    var a = 10;
    var a = 20;  // 可以重复声明不报错
    let x = 1;
    let x = 2; //报错
</script>

上述代码执行结果如下:
在这里插入图片描述
const 声明一个只读的常量。一旦声明,常量的值就不能改变。注意 const 具备上面 let 所述的所有特性,如下图所示:
在这里插入图片描述
const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值) 而言,值就保存在变量指向的内存地址中。因此等同于常量。但对于复合类型的数据(主要是对象和数组)而言,变量指向的内存地址保存的只是一个指针(引用),const 只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,这完全不能控制。示例代码如下:

<script>
    const person = {};
    // 为foo添加一个属性
    person.name = "Amo";
    console.log(person.name);
    // 将person指向另一个对象 就会报错
    person = {};
</script>

上述代码执行结果如下:
在这里插入图片描述
补充一点,let 声明变量不会污染全局变量,示例代码如下:

<script>
    // console.log(window.a)
    //let RegExp = 2;
    //console.log(RegExp) // 2
    //console.log(window.RegExp) // ƒ RegExp() { [native code] }

    var RegExp = 3;
    console.log(RegExp)  // 3
    console.log(window.RegExp) // 3
</script>

上面补充的关于一些 ES6 的新特性,参考阮一峰 ES6标准入门一书,一些解释性文字就直接拿过来了,当作学习使用,如有侵权,请联系笔者删除。如果是刚学习 JS 的读者可以先跳过这部分的学习。

5. 数据类型

在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。简单来说,数据类型就是数据的类别型号。比如姓名 张三 ,年龄 18,这些数据的类型是不一样的。JS 把数据类型分为两类:

5.1 简单数据类型

在这里插入图片描述
示例代码如下:

<script>
    //JS弱类型语言(动态语言) 自动根据=右边变量值的数据类型来判断
    var age = 21; //整数 默认为十进制
    var height = 18;//小数
    console.log(Number.MAX_VALUE)  //JS中数值的最大值
    console.log(Number.MIN_VALUE)  //JS中数值的最小值
    //数字型三个特殊值
    console.log(1 / 0); //Infinity: 代表无穷大,大于任何数值
    console.log(-1 / 0); // -Infinity: 代表无穷小,小于任何数值
    // isNaN: 非数字返回true 数字返回false
    console.log(isNaN(age));  // false 
    //字符串 用双引号或者单引号即可
    var name = "Amo"; // 'Amo'
    console.log(name.length); // 输出字符串长度 3
    var address = "重庆市'沙坪坝区'" // 注意:JS外双内单 外单内双 否则会报错
    var sex = '我是"男"的'
    //字符串拼接 常用到
    var personInfo = "Amo" + "--" + "好帅~"
    console.log(personInfo); //Amo--好帅~ +用来连接
    var num1 = 10;
    console.log("10" + 100); //10100

    //布尔值 要么是true 要么是false 即非真就假
    console.log(true);
    console.log(true + 1);//1 true在参与运算的时候会转换为1 false转换为0

    //一个声明后没有被赋值的变量会有一个默认值undefined
    var company;
    console.log(company); //undefined
    console.log(company + 11);//NaN

    //一个声明变量给null值,里面存的值为空 后续深入讲解
    console.log(11 + null) //null参与运算时转换为0
</script>

5.2 获取变量数据类型

typeof 可用来获取检测变量的数据类型,示例代码如下:

<script>
    var age = 18;
    console.log(typeof age); //number
</script>

不同类型的返回值如下图所示:
在这里插入图片描述

5.3 数据类型转换

使用表单、prompt 获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。通俗来说,就是把一种数据类型的变量转换成另一种数据类型,通常会实现 3 种方式的转换:

转换为字符串类型
转换为数字型
转换为布尔型

转换为字符串,如下图所示:
在这里插入图片描述
隐式转换是我们在进行算数运算的时候,JS 自动转换了数据类型。转换为数字型(重点),如下图所示:
在这里插入图片描述
转换为布尔型,如下图所示:
在这里插入图片描述
代表空、否定的值会被转换为false ,如 0/NaN/null/undefined 其余值都会被转换为 true

5.4 模板字符串

模板字符串(template string) 是增强版的字符串,用反引号( `)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板字符串</title>
</head>
<body>
<div id="box"></div>
</body>
</html>
<script>
    // 需求: 现在我想要将ul>li 标签写入id为box的盒子中
    const oBox = document.querySelector("#box")
    let id = "desc";
    let desc = "Amo so cool~";
    // 传统的方法字符串拼接 一旦拼接字符串太长多 容易乱
    //oBox.innerHTML = "<ul><li id='" + id + "'>" + desc + "</li></ul>"
    // 使用模板字符串拼接
    oBox.innerHTML = `
        <ul>
            <li id="${id}">${desc}</li>
        </ul>
    `;
    let x = 1;
    let y = 2
    //大括号内可以放入任意的JS表达式 可以进行计算以及引用对象属性。
    console.log(`${x} + ${y * 2} = ${x + y * 2}`);
</script>

上述代码执行结果如下:
在这里插入图片描述
关于 模板字符串 还有一些更复杂的操作,可以参考阮一峰的ES6 标准入门 一书。

6. 运算符

运算符(operator) 也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号。JavaScript 中常用的运算符有:

  1. 算术运算符
  2. 递增和递减运算符
  3. 比较运算符
  4. 逻辑运算符
  5. 赋值运算符

6.1 算术运算符

算术运算使用的符号,用于执行两个变量或值的算术运算。在这里插入图片描述
要注意的一个点是 浮点数的精度问题,浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。示例代码如下:

<script>
    let result = 0.1 + 0.2;
    console.log(result);
    console.log(0.07 * 100);
</script>

上述代码执行结果如下:
在这里插入图片描述
所以:不要直接判断两个浮点数是否相等 !

6.2 递增和递减运算符

如果需要反复给数字变量 添加或减去1,可以使用 递增(++)递减(--) 运算符来完成。在 JavaScript 中,递增(++)递减(--) 既可以放在变量前面,也可以放在变量后面。放在变量前面时,我们可以称为 前置递增(递减) 运算符,放在变量后面时,我们可以称为 后置递增(递减) 运算符。注意:递增和递减运算符必须和变量配合使用。 示例代码如下:

<script>
    // 1.前置递增运算符和后置递增运算符单独参与运算的时候无差别
    let num1 = 1;
    num1++;
    console.log(num1);//2
    let num2 = 1;
    ++num2;
    console.log(num2);//2

    //2.参与复合运算的时候
    let num3 = 10;
    //先自+1 在求和 ==> num3=10+1 ==> num3+10 ==>21
    console.log(++num3 + 10);//21

    let num4 = 10;
    //先返回原值求和 后自加 ==> num4+10 ==> 20 最后结果
    // 后自增: num4=10+1=11 但是这个值已经不参与运算了
    console.log(num4++ + 10); //20
</script>

6.3 比较运算符

比较运算符(关系运算符) 是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值 true/false 作为比较运算的结果。
在这里插入图片描述
等号的比较要特别注意,如下图所示:
在这里插入图片描述
示例代码如下:

<script>
    console.log(18 == "18"); //true
    console.log(18 === "18"); // false
</script>

6.4 逻辑运算符

逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值。后面开发中经常用于多个条件的判断。
在这里插入图片描述
逻辑与 &&,两边都是true才返回true,否则返回false。
在这里插入图片描述
逻辑或 ||,两边都是false才返回false,否则返回true。
在这里插入图片描述
逻辑非 (!) 也叫作取反符,用来取一个布尔值相反的值,如true 的相反值是 false。示例代码如下:

<script>
    let isOk = true;
    console.log(!isOk);//false
</script>

短路运算(逻辑中断):当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值。示例代码如下:

<script>
    // 1.逻辑与 表达式1&&表达式2&&表达式3...
    // 有0则返回0 否则返回最后一个非0数字
    console.log(123 && 456); // 456
    console.log(0 && 456); // 0
    console.log(123 && 456 && 789); // 789

    // 2.逻辑或 表达式1||表达式2||表达式3...
    // 返回第一个非0数字
    console.log(123 || 456); // 123
    console.log(0 || 456);  // 456
    console.log(123 || 456 || 789); // 123
</script>

6.5 赋值运算符

用来把数据赋值给变量的运算符。
在这里插入图片描述

6.6 运算符优先级

在这里插入图片描述

6.7 5种方法交换两个变量的值

<script>
    // 第一种写法: 使用第三方变量
    let a = 10;
    let b = 20;
    console.log(`交换变量值之前a为:${a} b为:${b}`);
    let temp = a;
    a = b;
    b = a;
    console.log(`交换变量值之后a为:${a} b为:${b}`);
    console.log("******************************");
    // 第二种写法: 算术运算符的方式
    let x = 10;
    let y = 20;
    console.log(`交换变量值之前x为:${x} y为:${y}`);
    let sum = x + y;
    x = sum - x;
    y = sum - x;
    console.log(`交换变量值之后x为:${x} y为:${y}`);
    console.log("******************************");
    // 第三种写法: 位运算的方式
    let m = 10;
    let n = 20;
    console.log(`交换变量值之前m为:${m} n为:${n}`);
    m = m ^ n;
    n = m ^ n;
    m = m ^ n;
    console.log(`交换变量值之后m为:${m} n为:${n}`);
    console.log("******************************");
    // 第四种写法: 解构赋值
    let i = 10;
    let j = 20;
    console.log(`交换变量值之前i为:${i} j为:${j}`);
    [i, j] = [j, i];
    console.log(`交换变量值之后i为:${i} j为:${j}`);
    console.log("******************************");
    // 第五种写法: 一句话搞定
    let c = 10;
    let d = 20;
    console.log(`交换变量值之前c为:${c} d为:${d}`);
    c = (c + d) - (d = c);
    console.log(`交换变量值之后c为:${c} d为:${d}`);
</script>

上述代码执行结果如下所示:
在这里插入图片描述

6.8 变量的解构赋值

在上述交换两个变量的时候,我们提到了 解构赋值 的概念。ES6允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这被称为 解构(Destructuring). 示例代码如下:

<script>
    // 以前为变量赋值只能直接指定值
    let a = 1, b = 2, c = 3;
    console.log(a, b, c);
    // ES6允许这样写
    let [l, m, n] = [1, 2, 3];//可以从数组中提取值 按照对应位置对变量赋值
    console.log(l, m, n);
</script>

本质上这种写法属于 模式匹配,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。

<script>
    let [foo, [[bar], baz]] = [1, [[2], 3]];
    console.log(foo, bar, baz) // 1 2 3

    let [, , third] = ["amo", "jerry", "paul"];
    console.log(third); //paul

    let [x, , y] = [1, 2, 3];
    console.log(x, y); // 1 3

    let [head, ...tail] = [1, 2, 3, 4];
    console.log(head, tail);// 1 [2,3,4]

    let [a, b, ...c] = ["amo"];
    //如果解构不成功 变量的值就等于undefined
    console.log(a, b, c); // amo undefined []
    let [m] = [];
    let [i, j] = [1]; //这两种解构都属于不成功
    console.log(m, i, j); //undefined 1 undefined
</script>

上述代码执行结果为:
在这里插入图片描述
另一种情况是 不完全解构,即等号左边的模式只匹配一部分的等号右边的数组,这种情况下,解构依然可以成功。示例代码如下:

<script>
    let [x, y] = [1, 2, 3];
    console.log(x, y); // 1 2
    let [a, [b], c] = [1, [2, 3], 4];
    console.log(a, b, c)  // 1 2 4
    //上面两个例子都属于不完全解构,但是可以成功。
    let [m, n] = 1;
    console.log(m, n);
</script>

上述代码执行结果如下:
在这里插入图片描述
对于 Set 结构,也可以使用数组的解构赋值。示例代码如下:

<script>
    let [x, y, z] = new Set(["Amo", "Jerry", "Paul"]);
    console.log(x, y, z); // Amo Jerry Paul
</script>

事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。解构赋值 还允许指定默认值,示例代码如下:

<script>
    let [a = true] = [];
    console.log(a);
    let [x, y = "b"] = ["a"];
    console.log(x, y); // a b
    //ES6内部使用严格相等运算符(===)判断一个位置是否有值,所以,如果
    //一个数组成员不严格等于undefined,默认值是不会改变的
    let [m, n = "b"] = ["a", undefined];
    console.log(m, n); // a b
    let [b = 1] = [undefined]; //这里是undefined理解为没值 则默认值为1
    console.log(b); // 1
    let [l = 1] = [null];
    console.log(l); // null
</script>

如果默认值是一个表达式,那么这个表达式是 惰性 求值的,即只有在用到时才会求值。示例代码如下:

<script>
    function f() {
        console.log("aaa");
    }

    let [x = f()] = [1];
    console.log(x); // 因为x能取到值,所以函数f根本不会执行
    //默认值可以引用解构赋值的其它变量,但该变量必须已经声明
    let [a = 1, b = a] = [];
    console.log(a, b);
    let [m = 1, n = m] = [2];
    console.log(m, n);
    let [j = 1, k = j] = [1, 2];
    console.log(j, k);
    let [o = p, p = 1] = [];
    console.log(o, p);
</script>

上述代码执行结果如下:
在这里插入图片描述

6.9 对象的解构赋值

解构不仅可以用于数组,还可以用于对象。示例代码如下:

<script>
    let {name, age} = {name: "Amo", age: 18}
    console.log(name, age) // Amo 18
</script>

上述代码执行结果如下:
在这里插入图片描述
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定。而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。示例代码如下:

<script>
    let {name, age} = {age: 18, name: "Amo"};
    console.log(name, age); // Amo 18

    let {address} = {sex: "男", hobby: "唱歌"};
    console.log(address) // undefined 
</script>

如果变量名与属性名不一致,示例代码如下:

<script>
    let {foo: baz} = {foo: "aaa", bar: "bbb"};
    console.log(baz) // aaa

    let obj = {first: "hello", last: "world"};
    let {first: f, last: l} = obj;
    console.log(f, l); // hello world
    //实际上,对象的解构赋值是下面形式的简写
    let {a: a, b: b} = {a: "aaa", b: "bbb"};
    console.log(a, b); // aaa bbb
    //也就是说,对象的解构赋值的内部机制是先查找到同名属性,然后在赋值给对应的变量。
    //真正被赋值的是后者,而不是前者
    let {name: age} = {name: "amo", address: "重庆市沙坪坝区"}
    console.log(age); // amo
</script>

与数组一样,解构也可以用于嵌套结构的对象。示例代码如下:

<script>
    let obj = {
        p: [
            "hello",
            {y: "world"}
        ]
    }
    let {p: [x, {y}]} = obj;
    console.log(x, y); // hello world
</script>

注意,这时 p 是模式,不是变量,因此不会被赋值。如果 p 也要作为变量赋值,可以写成下面这样。

<script>
    let obj = {
        p: [
            "Hello",
            {y: "World"}
        ]
    };
    let {p, p: [x, {y}]} = obj;
    console.log(x, y, p);
</script>

上述代码执行结果如下:
在这里插入图片描述
下面是另一个例子。

<script>
    let node = {
        loc: {
            start: {
                line: 1,
                column: 5
            }
        }
    }
    let {loc, loc: {start}, loc: {start: {line}}} = node;
    console.log(line);
    console.log(start);
    console.log(loc);
</script>

上述代码执行结果如下:
在这里插入图片描述
下面是嵌套赋值的例子:

<script>
    let obj = {};
    let arr = [];
    ({foo: obj.prop, bar: arr[0]} = {foo: 123, bar: true});
    console.log(obj);
    console.log(arr);
    //对象指定默认值
    let {x = 3} = {};
    console.log(x);
    let {a, b = 5} = {a: 1};
    console.log(a); //1
    console.log(b); //5
    let {m: n = 3} = {};
    console.log(n); //3
    let {i: j = 3} = {i: 5};
    console.log(j); //5 默认值生效的条件是,对象的属性值严格等于undefined
    //对象的解构赋值可以很方便地将现有对象的方法赋值到某个变量
    let {log, sin, cos} = Math;
    //由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
    let arr2 = [1, 2, 3];
    let {0: first, [arr2.length - 1]: last} = arr2;
    console.log(first, last); // 1 3
</script>

上述代码执行结果如下:
在这里插入图片描述

6.10 字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。示例代码如下:

<script>
    const [a, b, c, d, e] = "hello";
    console.log(a, b, c, d, e);
    //类似数组的对象都有一个length属性,因此还可以对这个属性进行解构赋值
    let {length: len} = "hello";
    console.log(len);//5
</script>

上述代码执行结果如下:
在这里插入图片描述

7. 流程控制

在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能。简单理解:流程控制就是来控制代码按照一定结构顺序来执行。 流程控制主要有三种结构,分别是顺序结构分支结构循环结构,代表三种代码执行的顺序。
在这里插入图片描述

7.1 顺序流程控制

顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。
在这里插入图片描述

7.2 分支流程控制

由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果。
在这里插入图片描述
JS 语言提供了两种分支结构语句:if 语句、switch 语句。if 语句语法结构如下:

// 条件成立执行代码,否则什么也不做
if (条件表达式) {
    // 条件成立执行的代码语句
}

在这里插入图片描述
示例代码如下:

<script>
    let age = 20;
    if (age > 18) {
        console.log("成年了,可以上网打撸了!");
    }
</script>

上述代码执行结果为:
在这里插入图片描述
if else 语句(双分支语句),语法结构如下:

// 条件成立  执行if里面代码,否则执行else里面的代码
if (条件表达式) {
    // [如果] 条件成立执行的代码
} else {
    // [否则] 执行的代码
}

在这里插入图片描述
如果某一年是闰年,那么这一年的2月份就有29天,否则这一年的2月份就有28天。应用 if…else 语句判断2020年2月份的天数。代码如下:

<script>
    let year = 2020;
    let month = 0;
    //判断指定年是否是闰年
    if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) {
        month = 29;
    } else {
        month = 28;
    }
    console.log(`2020年2月份的天数为${month}`);
</script>

上述代码执行结果为:
在这里插入图片描述
if else if 语句(多分支语句) 语法结构如下:

// 适合于检查多重条件。
if (条件表达式1) {
    语句1} else if (条件表达式2)  {
    语句2} else if (条件表达式3)  {
   语句3....
} else {
    // 上述条件都不成立执行此处代码
}

在这里插入图片描述
将某学校的学生成绩转化为不同等级,划分标准如下:
① 优秀大于等于90分
② 良好大于等于75分
③ 及格大于等于60分
④ 不及格小于60分
假设Amo的考试成绩是85分,输出该成绩对应的等级。其关键代码如下:

<script>
    let score = 85;
    if (score < 60) {
        console.log("不及格");
    } else if (score < 74) {
        console.log("及格");
    } else if (score < 90) {
        console.log("良好");
    } else {
        console.log("优秀");
    }
</script>

上述代码执行结果为:
在这里插入图片描述
if 语句不但可以单独使用,而且可以嵌套应用,即在 if 语句的从句部分嵌套另外一个完整的 if 语句。基本语法格式如下:

if (表达式1){
    if(表达式2){
        语句1
    }else{
        语句2
    }
}else{
    if(表达式3){
        语句3
    }else{
        语句4
    }
}

例如,Amo的高考总分是620,英语成绩是120。假设重点本科的录取分数线是600,而英语分数必须在 130 以上才可以报考外国语大学,应用 if语句 的嵌套判断该考生能否报考外国语大学,代码如下:

<script>
    const totalScore = 620;
    const englishScore = 120;
    if (totalScore > 600) {
        if (englishScore > 130) {
            console.log("能报考外国语大学!");
        } else {
            console.log("该考生可以报考重点本科,但不能报考外国语大学!");
        }
    } else {
        if (totalScore > 500) {
            console.log("该考生可以报考普通本科");
        } else {
            console.log("该考生只能报考专科");
        }
    }
</script>

上述代码执行结果为:
在这里插入图片描述三元表达式,语法结构如下:

表达式1 ? 表达式2: 表达式3;
  1. 如果表达式 1 为 true ,则返回表达式 2 的值,如果表达式1为 false,则返回表达式3的值
  2. 简单理解: 就类似于 if else(双分支) 的简写 示例代码如下:
    <script>
        let x = 4 > 5 ? 1 : 2;
        console.log(x); // 2
    </script>
    

switch 分支流程控制,switch 语句也是多分支语句,它用于基于不同的条件来执行不同的代码。当要针对变量设置一系列的特定值的选项时,就可以使用 switch。语法格式如下:

switch (表达式){
    case 常量表达式1:
        语句1;
        break;
    case 常量表达式2:
        语句2;
        break;case 常量表达式n:
        语句n;
        break;
    default:
        语句n+1;
        break;
}

参数说明:

  1. 表达式:任意的表达式或变量。
  2. 常量表达式:任意的常量或常量表达式。当表达式的值与某个常量表达式的值相等时,就执行此 case 后相应的语句。如果表达式的值与所有的常量表达式的值都不相等,则执行 default 后面相应的语句。
  3. break:用于结束 switch 语句,从而使 JavaScript 只执行匹配的分支。如果没有了 break 语句,则该匹配分支之后的所有分支都将被执行,switch 语句也就失去了使用的意义。

switch 语句的执行流程如下图所示:
在这里插入图片描述
default 语句可以省略。在表达式的值不能与任何一个 case 语句中的值相匹配的情况下,JavaScript 会直接结束 switch 语句,不进行任何操作。case 后面常量表达式的数据类型必须与表达式的数据类型相同,否则匹配会全部失败,而去执行 default 语句中的内容。某公司年会举行抽奖活动,中奖号码及其对应的奖品设置如下:

1 代表 一等奖,奖品是 华为手机
2 代表 二等奖,奖品是 光波炉
3 代表 三等奖,奖品是 电饭煲
④ 其他号码代表 安慰奖,奖品是 16G-U盘

假设Amo抽中的奖号为3,输出该员工抽中的奖项级别以及所获得的奖品。代码如下:

<script>
    let grade = "";  //定义表示奖项级别的变量
    let prize = ""; //定义表示奖品的变量
    let code = 3; //定义表示中奖号码的变量值为3
    switch (code) {
        case 1:
            grade = "一等奖";
            prize = "华为手机";
            break;
        case 2:
            grade = "二等奖";
            prize = "光波炉";
            break;
        case 3:
            grade = "三等奖";
            prize = "电饭煲";
            break;
        default:
            grade = "安慰奖";
            prize = "16G-U盘";
            break;
    }
    document.write(`该员工获得了${grade}<br/>奖品是${prize}`)
</script>

上述代码执行结果为:
在这里插入图片描述
在程序开发的过程中,使用 if 语句还是使用 switch 语句可以根据实际情况而定,尽量做到物尽其用,不要因为 switch 语句的效率高就一味地使用,也不要因为 if 语句常用就不应用 switch 语句。要根据实际的情况,具体问题具体分析,使用最适合的条件语句。一般情况下对于判断条件较少的可以使用 if 条件语句,但是在实现一些多条件的判断中,就应该使用 switch 语句。

8. 循环

8.1 while循环

while 循环语句也称为前测试循环语句,它是利用一个条件来控制是否要继续重复执行这个语句。while 循环语句与 for 循环语句相比,无论是语法还是执行的流程,都较为简明易懂。while循环语句的语法格式如下:

while(表达式){
   语句
}

参数说明:

  1. 表达式:一个包含比较运算符的条件表达式,用来指定循环条件。
  2. 语句:用来指定循环体,在循环条件的结果为 true 时,重复执行。

while 循环语句之所以命名为前测试循环,是因为它要先判断此循环的条件是否成立,然后才进行重复执行的操作。也就是说,while 循环语句执行的过程是先判断条件表达式,如果条件表达式的值为true,则执行循环体,并且在循环体执行完毕后,进入下一次循环,否则退出循环。while 循环语句的执行流程如下图所示。
在这里插入图片描述
例如,应用 while 语句输出1~10 这10个数字的代码如下:

<script>
    let i = 1;
    while (i <= 10) {
        console.log(i);
        i++;
    }
</script>

上述代码执行结果如下:
在这里插入图片描述

8.2 do…while循环

do…while 循环语句也称为后测试循环语句,它也是利用一个条件来控制是否要继续重复执行这个语句。与 while 循环所不同的是,它先执行一次循环语句,然后再去判断是否继续执行。do…while 循环语句的语法格式如下:

do{
    语句
} while(表达式);

参数说明:

  1. 语句:用来指定循环体,循环开始时首先被执行一次,然后在循环条件的结果为 true 时,重复执行。
  2. 表达式:一个包含比较运算符的条件表达式,用来指定循环条件。

do…while 循环语句执行的过程是:先执行一次循环体,然后再判断条件表达式,如果条件表达式的值为 true,则继续执行,否则退出循环。也就是说,do…while 循环语句中的循环体至少被执行一次。do…while 循环语句的执行流程如下图所示。
在这里插入图片描述
do…while 循环语句同 while 循环语句类似,也常用于循环执行的次数不确定的情况下。do…while 语句结尾处的 while 语句括号后面有一个分号;,为了养成良好的编程习惯,建议读者在书写的过程中不要将其遗漏。例如,应用 do…while 语句输出 1~10 这10个数字的代码如下:

<script>
    let j = 1;
    do {
        console.log(j);
        j++;
    } while (j <= 10);
</script>

do…while 语句和 while 语句的执行流程很相似。由于do…while 语句在对条件表达式进行判断之前就执行一次循环体,因此do…while 语句中的循环体至少被执行一次,下面的代码说明了这两种语句的区别。

<script>
    let i = 1;   //声明变量
    while (i > 1) {    //定义while语句,指定循环条件
        document.write("i的值是" + i); //输出i的值
        i--;   //变量i自减1
    }
    let j = 1;  //声明变量
    do {     //定义do...while语句
        document.write("j的值是" + j);  //输出变量j的值
        j--;      //变量j自减1
    } while (j > 1);
</script>

上述代码执行结果如下:
在这里插入图片描述

8.3 for循环

for 循环语句也称为计次循环语句,一般用于循环次数已知的情况,在 JavaScript 中应用比较广泛。for循环语句的语法格式如下:

for(初始化表达式;条件表达式;更新表达式){
    语句
}

参数说明:

  1. 初始化表达式:初始化语句,用来对循环变量进行初始化赋值。
  2. 条件表达式:循环条件,一个包含比较运算符的表达式,用来限定循环变量的边限。如果循环变量超过了该边限,则停止该循环语句的执行。
  3. 更新表达式:用来改变循环变量的值,从而控制循环的次数,通常是对循环变量进行增大或减小的操作。
  4. 语句:用来指定循环体,在循环条件的结果为 true 时,重复执行。

for 循环语句执行的过程是:先执行初始化语句,然后判断循环条件,如果循环条件的结果为 true,则执行一次循环体,否则直接退出循环,最后执行更新表达式,改变循环变量的值,至此完成一次循环。接下来将进行下一次循环,直到循环条件的结果为 false,才结束循环。for 循环语句的执行流程如下图所示。
在这里插入图片描述
例如,应用 for 语句输出 1~10 这10个数字的代码如下:

<script>
    for (let i = 1; i <= 10; i++) {
        console.log(i);
    }
</script>

在使用 for 语句时,也一定要保证循环可以正常结束,也就是必须保证循环条件的结果存在为 false 的情况,否则循环体将无休止地执行下去,从而形成死循环。为使读者更好的了解for语句的使用,下面通过一个具体的实例来介绍 for 语句的使用方法。应用 for 循环语句计算 100以内所有奇数的和 ,并在页面中输出计算后的结果。代码如下:

<script>
    let sum = 0;
    for (let i = 1; i <= 100; i++) {
        if (i % 2 != 0) {
            sum += i;
        }
    }
    console.log(`1-100的奇数和为${sum}`);
</script>

8.4 循环语句的嵌套

在一个循环语句的循环体中也可以包含其它的循环语句,这称为循环语句的嵌套。上述 3 种循环语句 (while循环语句、do…while循环语句和for循环语句) 都是可以互相嵌套的。如果循环语句 A 的循环体中包含循环语句 B,而循环语句 B 中不包含其他循环语句,那么就把循环语句 A 叫做外层循环,而把循环语句 B 叫做内层循环。用嵌套的 for循环 语句输出乘法口诀表。代码如下:

<script>
    let i, j;   //声明变量
    document.write("<pre>");    //输出<pre>标记
    for (i = 1; i < 10; i++) {  //定义外层循环
        for (j = 1; j <= i; j++) { //定义内层循环
            if (j > 1) document.write("\t");  //如果j大于1就输出一个Tab空格
            document.write(j + "x" + i + "=" + j * i); //输出乘法算式
        }
        document.write("<br>");  //输出换行标记
    }
    document.write("</pre>");   //输出</pre>标记
</script>

上述代码执行结果如下:
在这里插入图片描述

8.5 continue和break

continue 语句用于跳过本次循环,并开始下一次循环。continue 语句只能应用在 while、for、do…while 语句中。例如,在 for 语句中通过 continue 语句输出 10以内不包括5 的自然数的代码如下:

<script>
    for (let i = 1; i <= 10; i++) {
        if (i == 5) {
            continue
        } //如果i等于5就跳过本次循环
        document.write(i + "\n");    //输出变量i的值
    }
</script>

上述代码执行结果如下:
在这里插入图片描述
当使用 continue 语句跳过本次循环后,如果循环条件的结果为 false,则退出循环,否则继续下一次循环。在上面的 switch 语句中已经用到了 break 语句,当程序执行到 break 语句时就会跳出switch 语句。除了 switch 语句之外,在循环语句中也经常会用到break 语句。在循环语句中,break 语句用于跳出循环。break 语句通常用在for、while、do…while或switch 语句中。例如,在 for 语句中通过 break 语句跳出循环的代码如下:

<script>
    for (let i = 1; i <= 10; i++) {
        if (i == 5) break;   //如果i等于5就跳出整个循环
        document.write(i + "\n");  //输出变量i的值
    }
</script>

上述代码执行结果如下:
在这里插入图片描述

原创文章 43 获赞 749 访问量 4万+

猜你喜欢

转载自blog.csdn.net/xw1680/article/details/106046694
今日推荐