js 一周的基础 后续持续更新

96 阅读14分钟

1. # js基础

JavaScript是一门世界上最流行的脚本语言

一个合格的后端人员,必须要精通JavaScript

2、历史 ECMAScript可以理解为JavaScript的一个标准

最新版本已经到es6

但是大部分浏览器还只停留在支持es5代码上

3.前端三大件 HTML:超文本标记语言(结构层)

CSS:层叠样式表(样式层)

JavaScript:轻量级弱脚本语言

4.JS的三大核心

BOM-Browser OBjectModel(浏览器对象模型)

私人:提供的一整套操作浏览器相关内容的属性和方法

DOM-Document Object Model (文档对象模型)

私人:提供了一整套操作文档相关内容的属性和方法

ECMAScrpt(简称ES)-JS的语法规范

规定了JS的语法的书写

核心:利用ES 去操作DOM和BOM发生变化

5.js的三种书写方式

行内式 => a 标签 -> 在 href 属性上直接书写 javascript: js代码 ; => 非 a 标签 -> 添加一个行为属性以后, 直接书写 js 代码即可

行内式 js 代码(强烈不推荐)
   a 标签行内式
    => 在 标签的 href 属性上进行书写
    => 要求: 书写一个 javascript: js代码 ;
    => 示例: <a href="javascript: js代码 ;"></a>

  非 a 标签行内式
    => 首先需要添加一个行为属性(以 onclick 为例)
      -> on: 在 ... 上
      -> click: 点击/单击
    => 不需要书写 javascript:;, 直接在属性值的位置书写 js 代码即可
    => 示例: <div onclick="js代码"></div>


第一个js代码
  + 语法: alert('文本内容')
  + 注意:
    => 小括号内如果书写的是纯数字, 那么不需要引号包裹
    => 小括号内如果书写的不是纯数字, 那么需要引号包裹(单引号或者双引号无所谓)
  + 作用: 会在浏览器出现一个弹出提示框, 提示框内的内容就是书写在 () 内的内容

如下:

点我一下试试

点我一下试试看

内嵌式 => 把 js 代码书写在 script 标签内 => 打开页面不需要任何行为, 直接就会执行

内嵌式 js 代码 + 在 html 页面书写一个 script 标签 + 把你需要执行的 js 代码书写在 script 标签内 + 注意: => script 标签内的代码不需要行为, 打开页面就会直接执行 => script 标签可以书写在页面任何位置 -> 推荐书写在 head 的末尾或者 body 的末尾 -> 目前推荐书写在 body 的末尾 => script 标签可以书写多个, 会按照从上到下的顺序依次执行每一个 script 标签内的代码

如下:

外链式

    => 把 js 代码书写在 .js 后缀的文件内
    => 在 html 页面以 script 标签的 src 属性引入
    => 不需要任何行为, 打开页面就会直接执行

外链式 js 代码

  + 把 js 代码书写在一个 .js 后缀的文件内
    => 在文件内直接书写你要执行的 js 代码即可
  + 在 html 页面用 script 标签的 src 属性引入该 js 文件
    => 注意: src 属性 src 属性 src 属性 !!!
  + 注意:
    => script 标签内的代码不需要行为, 打开页面就会直接执行
    => script 标签可以书写在页面任何位置
      -> 推荐书写在 head 的末尾或者 body 的末尾
      -> 目前推荐书写在 body 的末尾
    => script 标签可以书写多个, 会按照从上到下的顺序依次执行每一个 script 标签内的代码
    => script 标签一旦被当做外链式使用的时候, 不能继续被当做内嵌式使用了
      -> 此时书写在标签对内的代码没有意义(此处是外链式链接)

alert('我是一段外链式 js 代码, 你好世界 ^_^')

6.JS定义变量 什么是变量? 在程序的运行过程中用来记录中间值的内容

例子: => 饮料: 50 => 打车: 30 => 吃饭: 160 => 看电影: 80 => 计算比例: -> 饮料: 50 / (50 + 30 + 160 + 80) -> 打车: 30 / (50 + 30 + 160 + 80) -> 吃饭: 160 / (50 + 30 + 160 + 80) -> 看电影: 80 / (50 + 30 + 160 + 80) => 假定一个变量 x, 值是 50 + 30 + 160 + 80 => 计算比例: -> 饮料: 50 / x -> 打车: 30 / x -> 吃饭: 160 / x -> 看电影: 80 / x

  定义变量
    + 语法: var 变量名 = 值
      -> var      定义变量的关键字
      -> 变量名    你自定义的一个名字
      -> 等于号    赋值符号(把右边的内容给到左边的变量)
      -> 值        该变量所保存的内容

  一个 var 关键字使用的几种形式
    1. 定义变量不赋值
      => var 变量名
    2. 定义变量并赋值
      => var 变量名 = 值
    3. 一个 var 定义多个变量
      => var 变量名1, 变量名2, ...
    4. 一个 var 定义多个变量并赋值
      => var 变量名1 = 值1, 变量名2 = 值2, ...
    5. 一个 var 定义多个变量
      => var 变量名1 = 值1, 变量名2, 变量名3 = 值3, ...

  变量保存值
    + 一个变量只能保存一个值, 当你第二次给一个变量赋值的时候
    + 会把第一次赋的值覆盖掉

JS的三个输出语法

  1. alert()
    + 语法: alert(输出的内容)
    + 形式: 弹出一个提示框显示内容
  2. console.log()
    + 语法: console.log(输出的内容)
    + 形式: 在浏览器控制台输出内容
  3. document.write()
    + 语法: document.write(输出的内容)
    + 形式: 直接把内容输出在页面上

  共同点:
    + 当你的小括号内输出的内容被引号包裹的时候, 表示你输出的是一个普通文本内容
    + 当你的小括号内输出的内容没有引号包裹的时候(纯数字除外), 表示你输出的是一个变量

案例:

交换变量 需求:交换两个变量所保存的值

var n = 11
var m = 33
console.log('n : ', n)
console.log('m : ', m)
console.log('------------------------------')

变量的命名规则和规范

  规则(你必须遵守, 不然报错)
    1. 一个变量只能由 数字(0-9) 字母(a-zA-Z) 美元符($) 下划线(_) 组成
    2. 一个变量不能由 数字开头
    3. 严格区分大小写
    4. 不要使用关键字和保留字
      => 关键字: JS 语法内正在使用的关键字
      => 保留字: JS 语法将来要使用的关键字

  规范(建议你遵守)
    1. 变量语义化
      => 尽量使用一些有意义的单词, 或者汉语拼音
    2. 驼峰命名法
      => 当变量由多个单词组成的时候, 第二个单词开始, 首字母大写
      => 当变量由多个单词组成的时候, 每个单词之间使用 下划线(_) 分隔
    3. 不要用中文

JS 的数据类型

    + 基本数据类型
      => 数值 Number
        -> 整数
        -> 浮点数
        -> 科学记数法
        -> 其他进制表示
        -> Infinity
        -> NaN
      => 字符串 String
        -> 所有被引号包裹的内容都是字符串
      => 布尔 Boolean
        -> true
        -> false
      => 空 Undefined
        -> undefined
      => 空 Null
        -> null

检测数据类型 目的: 用来检查变量存储的数据是一个什么数据类型

  typeof 关键字
    只能准确的检测基本数据类型
    语法:
      typeof 要检测的变量
      typeof(要检测的变量)
      返回值(结果):
      以字符串的形式给出你的检测结果

 typeof 返回值必然是一个字符串类型
 只要两个及以上 typeof 连用, 得到的结果一定是 string

  typeof 的返回值
  数值  'number'
  字符串 'string'
  布尔 'boolean'
  Undefined 'undefined'
   Null 'Object'

数据类型转换

    + 把其他数据类型转换成 数值类型
      1. Number()
        => 强制转换, 整体可以转换就是数字
        => 整体不可以转换就是 NaN
      2. parseInt()
        => 一位一位看待
        => 不认识小数点
      3. parseFloat()
        => 一位一位看待
        => 认识小数点
      4. 非加法的数学运算
        => 和 Number 一样都是强制转换
    + 把其他数据类型转换成 字符串类型
      1. String()
        => 什么数据类型都可以转换
      2. toString()
        => 语法: 转换的数据.toString()
        => undefined 和 null 不能转换
      3. 字符串拼接
        => 使用 加号(+) 运算符进行拼接
    + 把其他数据类型转换成 布尔类型
      1. Boolean()
        => 只有五个内容是 false
          -> 数值 NaN
          -> 数值 0
          -> 空字符串 ''
          -> undefined
          -> null

**** 数据类型转换 - 转数值****

    + 把其他数据类型转换成数值类型

  1. Number()
    + 语法: Number(你要转换的数据)
    + 返回值(结果): 转换好的数值类型数据
    + 转换规则:
      => 把你要转换的内容当做一个整体
      => 如果可以转换成一个合法数字, 那么就是这个数字
      => 如果不能转换成一个合法数字, 那么就是 NaN
    + 布尔 true 会转换成 1
    + 布尔 false 会转换成 0

  2. parseInt
    + 语法: parseInt(你要转换的数据)
    + 返回值(结果): 转换好的数值类型数据
    + 转换规则:
      => 不管你要转换的是什么, 都一位一位的看待
      => 如果第一位就不能转换成合法数字, 那么直接给出结果 NaN, 停止转换
      => 如果第一位可以, 那么保留, 继续看第二位
      => 以此类推, 直到不能转换或者结束为止
    + 注意: 不认识小数点

  3. parseFloat()
    + 语法: parseFloat(你要转换的数据)
    + 返回值(结果): 转换好的数值类型数据
    + 转换规则:
      => 和 parseInt 一模一样
      => 只不过多认识了一个 小数点

  4. 非加法的数学运算
    + 转换规则: 和 Number 方法一模一样, 强制转换

数据类型转换 - 转字符串

    + 把其他数据类型转换成字符串类型
  1. String()
    + 语法: String(你要转换的数据)
    + 返回值(结果): 转换好的字符串类型数据
    + 所有数据类型都能转换

  2. toString()
    + 语法: 你要转换的数据.toString()
    + 返回值(结果): 转换好的字符串类型数据
    + 注意: 不能转换 undefined 和 null

  3. 字符串拼接
    + 使用加法(+) 运算符进行运算
    + 在 JS 内加法有两个意义
      => 只要符号任意一边是 字符串, 那么就会进行字符串拼接
      => 只有两边都是数值或者布尔的时候, 才会进行数学运算

数据类型转换 - 转布尔

    + 把其他数据类型转换成布尔类型数据

  1. Boolean
    + 语法: Boolean(你要转换的数据)
    + 返回值(结果): 转换好的布尔类型数据
    + 在 JS 内, 只有五个内容转换完毕以后是 false, 其余全是 true
      => 数值 NaN
      => 数值 0
      => 空字符串 ''
      => undefined
      => null

运算符

    + 进行运算的符号
    + 大致分为几类
      => 算数运算
      => 赋值运算
      => 比较运算
      => 逻辑运算
      => 自增自减运算
  • 算数运算符
  •   + 主要进行数学运算的符号
    
    1. +
      => 含义1: 进行字符串拼接, 只要符号任意一边是字符串类型
      => 含义2: 进行数学运算, 只有符号两边都是布尔或者数字的时候
    
    2. -
    
    3. *
    
    4. /
    
    5. %
      => 计算两个数字的余数, 不能整除的一部分内容
    
    6. **
      => 底数 ** 指数
      => 谁 ** 的多少次方
    

运算符 - 赋值运算符 + 进行赋值操作的符号

  1. =
    => 右边的内容给到左边的变量

  2. +=
    => 加号(+) 和 赋值(=) 合作
    => n += 10
    => 等价于
    => n = n + 10

  3. -=

  4. *=

  5. /=

  6. %=

运算符 - 比较运算符 + 所有的比较运算符结果都是 布尔值

  1. > 大于
  2. < 小于
  3. >= 大于等于
    -> 符号左边 大于或者等于 右边为 true
  4. <= 小于等于
    -> 符号左边 小于或者等于 右边为 true

  5. == 等于
    -> 符号两边在不考虑数据类型的情况下, 只要值相等即为 true

  6. === 等等于
    -> 必须符号两边 值和数据类型 都一样, 才能得到 true

  7. != 不等于
    -> 比较符号两边的内容在不考虑数据类型的情况下, 值是否不等

  8. !== 不等等
    -> 比较符号两边的内容是否不全等

逻辑运算符 + 进行逻辑运算的符号

  1. && 与(且)
    => 符号两边的表达式都为 true 的时候, 最终结果为 true
   
    => 只要符号任意一边的结果为 false, 最终结果就是 false

    => 同真为真, 一假则假
     配合if判断来决定


     && 与(且)
     符号两边的表达式都为ture的时候 最终的结果为true
     只要符号任意一边的结果为false 最终的结果就是false
     同真为真  一假为假  
     特殊作用:短路表达式  
     当运算符左边为ture时候  才会执行右边的代码
     如果运算符左边为false  那么右边的代码不会执行

    => 特殊作用: 短路表达式
      -> 当运算符左边为 true 的时候, 才会执行右边的代码
      -> 如果运算符左边为 false, 那么右边的代码不会执行

  2. || 或
    => 符号两边的表达式任意一边是 true 的时候, 最终结果就是 true
    => 只有符号两边都是 false 的时候, 最终结果才是 false
    => 一真为真, 同假则假
    => 特殊作用: 短路表达式
      -> 当运算符左边为 true 的时候, 右边的代码不会执行
      -> 当左边为 false 的时候, 右边的代码才会执行

     

  3. !  非(取反
    => 本身如果是 true, 那么结果就是 false
    => 本身如果是 false, 那么结果就是 true
    => 特殊作用: 双取反转布尔

自增自减运算符 + 一元运算符的一种

  ++(为例)
    => 前置加加: 符号在前面, ++变量
    => 后置加加: 符号在后面, 变量++

    => 共同点:
      -> 只要执行了, 一定会让改变的值改变(+1)
     
    => 区别: 在于参与运算的时候
      -> 前置++: 会先把变量本身的值改变(+1), 用改变后的值参与运算
      -> 后置++: 会先把变量本身的值参与运算, 然后改变变量本身的值(+1)


  --
    => 前置减减: 符号在前面, --变量
    => 后置减减: 符号在后面, 变量--
    => 共同点:
      -> 只要执行了, 一定会让改变的值改变(-1)
    => 区别: 在于参与运算的时候
      -> 后置--: 会先把变量本身的值参与运算, 然后改变变量本身的值(-1)

条件分支语句 - if

    + 意义: 根据条件来决定是否执行代码, 或者执行哪一段代码
    + 注意: 一个条件分支语句只能执行一次67890


  1. if 语句
    + 语法: if (条件) { 代码段 }
    + 意义: 当 条件为 true 的时候, {} 内的代码执行, 条件为 false 的时候, {} 内的代码不执行

  2. if else 语句
    + 语法: if (条件) { 代码段 } else { 代码段 }
    + 意义: 当 条件为 true 的时候, if 后面的 {} 执行
            当 条件为 false 的时候, else 后面的 {} 执行
    + 注意: 两个 {} 能且只能执行一个

  3. if ... else if 语句
    + 语法: if (条件1) { 代码段1 } else if (条件2) { 代码段2 } ...
    + 意义:
      => 按照顺序, 依次判断条件, 哪一个条件为 true, 执行哪一个条件后面的 {}
      => 当任何一个条件满足的时候, 后面的就不在执行了
    + 注意: 多个 {} 内的代码最多只能执行一个

  4. if ... else if ... else 语句
    + 语法: if (条件1) { 代码段1 } else if (条件2) { 代码段2 } ... else { 代码段 }
    + 意义:
      => 按照顺序, 依次判断条件, 哪一个条件为 true, 执行哪一个条件后面的 {}
      => 当任何一个条件满足的时候, 后面的就不在执行了
      => 当所有条件都不满足的时候, 执行 else 后面的 {}
    + 注意: 多个 {} 能且只能执行一个

案例:

  案例1: 判断一个正整数是不是偶数
    + 能被2整除的就是 偶数
    + 如何判断一个正整数是不是被 2 整除
    + 和 2 进行取余运算

  if 语句的 () 里面
    + 不管你写什么内容, 都会按照 布尔值 来进行判断
    + 在书写某些条件的时候, 可以进行适当的简化
   

 var a = 19
 
 if( a % 2===0){
 
 console.log('我是偶数')
 
 }else{  console.log('我是奇数')  
 
 }



//  案例2:
//     + 根据成绩(0 ~ 100) 在控制台输出内容
//       => 90 以上输出 A
//       => 80 ~ 89 输出 B
//       => 70 ~ 79 输出 C
//       => 60 ~ 69 输出 D
//       => 60 以下输出 E
// 准备变量

 var b = 90

//  if 条件判断

 if ( b >=90 ) {

   console.log('优秀')

 } else if (b>=80) {

    console.log('B')

 } else if (b>=70){

   console.log('C')
 } else if (b>=60) {

  console.log('d')

 } else if (b<=50) {

   console.log('E')

 }

**** 三元表达式(三元运算/三目运算/三目)****

  语法:
    + 条件 ? 对 : 不对
  意义: 对 if else 语句的简写形式
  注意: 执行代码的位置只能执行一句话

  作用:
    1. 利用三元表达式执行代码
    2. 利用三元表达式给给变量赋值

// 1. 利用三元表达式执行代码
// var n = 17
//  条件    ?   条件为 true 执行   :  条件为 false 执行
// n % 2 === 0 ? console.log('偶数') : console.log('奇数')


// 2. 利用三元表达式给给变量赋值
// var gender = 男(女)
// var sex = 1 // => 1
// var gender = sex === 0 ? '女' : '男'
// console.log(gender)

// var gender = ''
// if (sex === 0) {
//   gender = '女'
// } else {
//   gender = '男'
// }

案例

//   prompt()
//   语法: prompt(提示文本)
//   表现: 在浏览器出现一个弹出层
//         包含一个输入框, 包含一个确定, 一个取消按钮
//   返回值:
//     如果用户点击的是 确定, 那么返回值就是 文本框输入的内容
//     如果用户点击的是 取消, 那么就是 null
//   注意: 当你点击确定的时候, 返回值必然是一个 string 类型
// var res = prompt('请填写您的身份证号码')
// console.log(res)
// console.log(typeof res)


// 约定: 因为目前所学技能有限, 我们只考虑用户输入的是 18位数字 或者 点击取消
// 约定: 只输入身份证的后四位
// 1. 利用 prompt 采集用户的身份证号
var res = prompt('请输入身份证号的后四位')
console.log(res)


// 2. 判断他点击的是确定还是取消
// 点击确定的时候, 是一个 18位的数字字符串, 转换为布尔就是 true
// 点击取消的时候, 是一个 null, 转换为布尔就是 false
// 如果是 false, 那么我什么都不需要做

if (res) {
 
  // 代码能执行到这里, 说明 res 被转换为了 true, 用户输入了一个 18位数字字符串, 并点击了确定

  // 3. 把 18 位数字的 倒数第二位 拆出来

  var sex = parseInt(res % 100 / 10)

  var gender = sex % 2 === 0 ? '女士' : '先生'

  alert('欢迎光临 xxx ' + gender)
}

if 案例

    + 根据 年月日 三个条件
    + 来判断是当年的第几天

/*
  分析:
    + 年: 考虑平年还是闰年, 因为 2 月天数不一样
      => 先不管
      => 全部叠加完毕, 最后决定是否补一天
    + 日: 不用管
    + 月

  分析月:
    + 如果 month === 2, 叠加 1 月整月天数
    + 如果 month === 3, 叠加 1 月 2 月 整月天数
    + 如果 month === 4, 叠加 1 月 2 月 3 月 整月天数

  问题: 什么样的情况需要叠加 1 月的整月 ?
    => month > 1 就需要叠加
  问题: 什么样的情况需要叠加 2 月的整月 ?
    => month > 2 就需要叠加
  问题: 如何能让一段代码叠加完 1 月再次叠加 2 月 ?
    => 把代码写成两段
*/

var year = prompt('请输入年份') - 0
var month = prompt('请输入月份') - 0
var date = prompt('请输入日期') - 0

// 准备一个变量, 用于累计结果
var day = date

// 月份叠加完毕
if (month > 1) day += 31
// 当你开始叠加 2 月的整月天数的时候, 不能单纯的叠加 28// 如果是 闰年, 叠加 29 天, 如果是 平年, 叠加 28 天
if (month > 2) day += year % 4 === 0 && year % 100 !== 0 || year % 400 === 0 ? 29 : 28
if (month > 3) day += 31
if (month > 4) day += 30
if (month > 5) day += 31
if (month > 6) day += 30
if (month > 7) day += 31
if (month > 8) day += 31
if (month > 9) day += 30
if (month > 10) day += 31
if (month > 11) day += 30

console.log(`第 ${ day } 天`)

条件分支语句 - switch

  基础语法:
    switch (要判断的内容) {
      case 情况1:
        情况1满足的时候执行的代码
        break
      case 情况2:
        情况2满足的时候执行的代码
        break
      default:
        所有情况都不满足的时候执行的代码
    }

  注意:
    1. switch 一般不进行范围的判断, 而是准确某些值的判断
    2. switch 语句内, 判断的内容和 case 必须值和数据类型都一样, 才叫做满足
    3. switch 可以不写 default
      => 如果不写, 所有 case 都不满足的时候没有代码执行
    4. switch 语句可以不写 break
      => 如果不写, 会发生 break 穿透效果

  break 穿透
    + 从第一个满足条件的 case 开始
    + 如果没有 break
    + 后面的条件不在判断, 直接执行代码
    + 直到遇到 break 或者 switch 结束为止

* ** 案例: 成绩案例**

    + 根据成绩(0 ~ 100) 在控制台输出内容
      => 90 以上输出 A
      => 80 ~ 89 输出 B
      => 70 ~ 79 输出 C
      => 60 ~ 69 输出 D
      => 60 以下输出 E
*/

var score = 55.56

// 1. 用成绩 / 10
// 2. 保留整数部分
//    剩下的只有 10 9 8 7 6 5 4 3 2 1 0
switch (parseInt(score / 10)) {
  case 10:
  case 9:
    console.log('A')
    break
  case 8:
    console.log('B')
    break
  case 7:
    console.log('C')
    break
  case 6:
    console.log('D')
    break
  default:
    console.log('E')
}

编程思维的 "开端" - 循环

  1. 循环的意义:
    + 重复的做一个事情
    + 循环三要素
      => 开始
      => 结束
      => 步长
    + 三个要素都可以控制循环的次数
    + 循环为我们提供的内容
      => 重复执行代码的能力
      => 一组有规律的数字

** while 循环语法**

    while (条件) {
      重复执行的代码
    }
    + 意义: 根据条件来决定 {} 内的代码是否执行
    + 过程:
      => 首先, 进行条件判断
      => 如果条件为 false, 结束这个循环
      => 如果条件为 true, 执行 {} 内的代码
      => {} 内代码执行完毕, 再次条件判断
      => ...
    + 注意: 必须要书写步长

简单的示例

 1. 准备循环的开始
var n = 1

// 2. 书写循环, 条件位置就是循环的结束
while (n <= 5) {
  console.log('我围着操场跑了一圈', n)

  // 3. 改变初始变量(步长的设置)
  n++
}

console.log('循环结束后的后续代码')

do while 循环

  语法:
    do {
      重复执行的代码
    } while (条件)
    + 过程:
      => 不管条件是否满足, 先执行一遍代码
      => 开始进行条件判断
      => 如果条件为 false, 结束循环
      => 如果条件为 true, 那么再次执行一遍代码
      => 再次进行条件判断
      => ...

  区别:
    + 当初始变量在条件以内的时候, whiledo while 没有区别
    + 当初始变量在条件以外的时候
      => while 一次都不执行
      => do while 循环会执行一次

// 简单的小案例
do {
  // 出现一段代码去采集用户输入的内容
  var pwd = prompt('请输入密码')
} while (pwd !== '123456')

console.log('页面正常打开了')

for 循环

  语法:
    for (定义初始变量; 条件判断; 修改初始变量) {
      重复执行的代码
    }

    定义初始变量
    for (; 条件判断; ) {
      重复执行的代码
      修改初始变量
    }

  案例1:
    + 将 1000 ~ 2000 之间所有的闰年输出在页面上
    + 每四个一换行

  分析:
    1. 你重复做的事情是什么 ?
      => 在页面上输出一个年份数字
      => document.write('内容')
    2. 你是否需要一组有规律的数字支持 ?
      => 1000 ~ 2000 之间的数字


// 每四个一换行
// 换行: document.write('<br>')
// 每当你输出了 4 个年份, 输出一次 br

// 准备变量当做计数器
var count = 0

for (var i = 1000; i <= 2000; i += 4) {
  // i 是 1000 ~ 2000 之间的每一个 4 的倍数
  // 需要判断 i 是闰年才输出(闰年一定是 4 的倍数, 4 的倍数不一定是闰年)

  // 判断是闰年才要
  if (i % 100 !== 0 || i % 400 === 0) {
    document.write(i + ' ')

    // 这里的代码执行一次, 表示我输出了一个 年份, 计数器++
    count++

    // 当计数器是 4 的倍数的时候, 输出一个换行
    if (count % 4 === 0) document.write('<br>')

  }
 
}

console.log(count)


  案例2:
    + 求水仙花数字
    + 水仙花数字(三次自幂数)
      => 要求:
        -> 是一个三位数
        -> 每一位的三次方之和 和 这个数字相等
      => 例子: 153
        -> 1 * 1 * 1 + 5 * 5 * 5 + 3 * 3 * 3
        -> 1 125 27
        -> 153

  分析:
    1. 你要重复执行的操作 ?
      => 判断一个数字的 每一位的三次方之和 是否和这个数字相当
    2. 你是否需要一组有规律的数字 ?
      => 需要, 100 ~ 999
*/


for (var i = 100; i <= 999; i++) {
  // i 就是 100 ~ 999 之间的所有数字

  // 重复要做的事情
  // 1. 把当前这个 i 拆开三位数字
  var a = parseInt(i / 100)
  var b = parseInt(i % 100 / 10)
  var c = i % 10

  // 2. 判断是否为三次自幂数, 决定是否输出
  if (a ** 3 + b ** 3 + c ** 3 === i) {
    console.log(i, ' 是三次自幂数')
  }
}

循环嵌套

    + 在一个循环内书写另一个循环
    + 注意: 里外层循环不要用一个控制变量

for (var i = 1; i <= 3; i++) {
  // 当 i === 1 的时候, j 循环 3 次
  // 当 i === 2 的时候, j 循环 3 次
  // 当 i === 3 的时候, j 循环 3 次
  for (var j = 1; j <= 3; j++) {

    console.log(i, ' ---- ', j)

  }
}
/*
  九九乘法表
*/

// 写一个三角形
for (var i = 1; i <= 9; i++) {
  for (var j = 1; j <= i; j++) {
    document.write(`<span>${ j } * ${ i } = ${ i * j }</span>`)
  }
  document.write('<br>')
}

**函数

什么是函数 

    + 是一个 JavaScript 内的数据类型, 叫做 Function
    + 是一个复杂数据类型
    + 私人: 是一个 "盒子", 承载的是一段代码
    + 函数的两个阶段
      => 把 代码 装进 "盒子" 的过程 - 函数定义阶段
      => 把 "盒子" 内的代码执行的过程 - 函数调用阶段

  函数的定义阶段(如何定义一个函数)
    + 声明式定义函数
      => 语法: function 函数名() { 代码段 }
        -> function     定义函数的关键字
        -> 函数名        你给这个函数定义的名字(遵循变量的命名规则和规范)
        -> ()           必须写, 书写参数的位置(欠着)
        -> {}           函数体, 存放的就是代码段
    + 赋值式函数(函数表达式)
      => 语法: var 变量 = function () {}

  函数调用阶段(如何将函数内的代码执行)
    + 两种定义函数的方式不一样, 但是调用方式一样
    + 语法: 函数名()

  函数调用上的区别
    + 两种定义函数的方式
      => 调用方式一样
      => 调用时机不一样
    + 声明式函数: 可以在声明以前调用, 也可以在声明以后调用
    + 赋值式函数: 只能在声明以后调用, 之前调用会报错 xxx is not a function


// 声明式函数
function fn() {
  for (var i = 1; i <= 9; i++) {
    for (var j = 1; j <= i; j++) {
      document.write(`${ j } * ${ i } = ${ i * j } `)
    }
    document.write('<br>')
  }
}

console.log(fn)

// 赋值式函数
var fn2 = function () {
  for (var i = 1; i <= 9; i++) {
    for (var j = 1; j <= i; j++) {
      document.write(`${ j } * ${ i } = ${ i * j } `)
    }
    document.write('<br>')
  }
}

console.log(fn2)

函数的参数

    + 形参
      => 书写在函数定义阶段的小括号内
      => 就是一个只能在函数内使用的变量(遵循变量命名规则和规范)
      => 可以书写多个, 多个之间使用 逗号(,) 分隔
      => 值由函数调用阶段的实参决定
    + 实参
      => 书写在函数调用阶段的小括号内
      => 就是一个真实的值, **按照顺序** 依次给函数的形参赋值
      => 可以书写多个, 多个之间使用 逗号(,) 分隔

function fn(n) {
  for (var i = 1; i <= n; i++) {
    for (var j = 1; j <= i; j++) {
      document.write(`${ j } * ${ i } = ${ i * j } `)
    }
    document.write('<br>')
  }
}

// 本次调用 n 为 9, 九九乘法表
fn(9)
// 本次调用 n 为 7, 7 * 7
fn(7)

函数的返回值

    + 在函数内使用 return 关键字来给函数定义 返回值
*/


// function fn() {
//   // 给 fn 这个函数制作了一个 返回值 叫做 100
//   // 将来你只要调用 fn 函数, 就能得到 100 这个结果
//   return 100
// }
// // 此时 res 接受的就是 fn 函数调用后的 返回值(结果)
// // fn 函数内 return 的内容就会赋值给 res
// var res = fn()
// console.log(res)

打断函数

    + 在函数内使用 return 关键字打断函数
    + 书写在 return 关键字后面行的内容不再执行了

  return 有两个作用
    1. 给函数制作一个返回值
    2. 打断函数


  函数小案例: 封装一个函数, 判断一个数字是不是质数


// 判断一个数字是不是质数的函数
// 是否需要参数: 需要1个, 就是要判断的数字
// 是否需要返回值: 需要, 判断的结果, 最好是一个布尔值
// function isPrime(n) {
//   // 判断 n 是否是一个质数
//   for (var i = 2; i <= n / 2; i++) {
//     if (n % i === 0) break
//   }

//   // 如果是质数, 返回一个 true
//   // 如果不是质数, 返回一个 false
//   if (i <= n / 2) {
//     // 说明不是质数, 返回 false
//     return false
//   } else {
//     // 说明是质数, 返回 true
//     return true
//   }
// }



function isPrime(n) {
  // 判断 n 是否是一个质数
  for (var i = 2; i <= n / 2; i++) {
    if (n % i === 0) break
  }

  // 如果是质数, 返回一个 true
  // 如果不是质数, 返回一个 false
  // 如果 i > n / 2 的结果是 true, 返回 true
  // 如果 i > n / 2 的结果是 false, 返回 false
  // 直接返回 i > n / 2 的结果
  return i > n / 2
}
var r1 = isPrime(102)
console.log(r1)

 /*
  函数小案例: 封装一个函数, 求两个数字的最大公约数
*/

// 是否需要参数 : 需要两个
// 是否需要返回值: 需要
function fn(a, b) {
  // 1. 求 a 和 b 的最大公约数
  var max = a > b ? a : b
  var min = a > b ? b : a

  while (max % min !== 0) {
    var tmp = max % min
    max = min
    min = tmp
  }

  // 2. 把计算结果当做该函数的返回值
  // 代码执行到这里, 说明 min 就是最大公约数
  return min
}

var res = fn(19, 17)
console.log(res)

认识作用域

约定: 作用域相关知识点内, 变量一词表示的是 包含变量名和函数名

  作用域
    + 一个变量可以生效使用的范围

  作用域分类
    + 全局作用域
      => 一个 html 页面打开, 就是一个全局作用域
      => 叫做 window
    + 私有作用域(函数作用域)
      => **只有函数生成私有作用域**

  作用域上下级关系
 
    + 定义在哪一个作用域内的函数, 就是哪一个作用域的子级作用域

  提供了三个机制
    + 变量定义机制
      => 定义在哪一个作用域下的变量就是哪一个作用域的私有变量
      => 只能在该作用域及其后代作用域内使用
      => 不能再父级作用域使用
    + 变量访问机制
     
      => 当你需要访问一个变量的值的时候
      => 首先在自己作用域内查找, 如果有直接使用, 停止查找
      => 如果没有, 自动去到父级作用域查找, 如果有直接使用, 停止查找
      => 如果还没有, 在去到父级作用域查找
      => 以此类推, 直到全局作用域(window) 都没有, 那么报错 xxx is not defiend
    + 变量赋值机制
      => 当你需要给一个变量赋值的时候
      => 首先在自己作用域内查找, 如果有直接赋值, 停止查找
      => 如果没有, 自动去到父级作用域查找, 如果有直接赋值, 停止查找
      => 如果还没有, 在去到父级作用域查找
      => 以此类推, 直到全局作用域(window) 都没有
      => 把这个变量定义为全局变量, 在进行赋值

认识变量的三个行为

  变量定义
    + 带有 var 关键字或者 function 关键字
    + 函数的形参

  变量访问
    + 当你需要拿到一个变量的值的时候
    + console.log(num)

  变量赋值
    + 有赋值符号
    + 实参和形参的交互

变量定义机制

    + 定义在哪一个作用域的变量, 就是哪一个作用域的私有变量
    + 只能在该作用域及其后代作用域内使用
    + 不能再父级作用域使用

变量访问机制

    + 当你需要访问一个变量的值的时候
    + 首先在自己作用域内查找, 如果有直接使用, 停止查找
    + 如果没有, 去到父级作用域查找, 如果有直接使用, 停止查找
    + 如果还没有, 继续需要父级作用域查找
    + 以此类推, 直到全局作用域(window)都没有, 那么报错 xxx is not defined

** 变量赋值机制**

    + 当你需要给一个变量赋值的时候
    + 首先在自己作用域内查找, 如果有直接赋值, 停止查找
    + 如果没有, 直接去到父级作用域查找, 如果有直接赋值, 停止查找
    + 如果还没有, 在去到父级作用域查找
    + 以此类推, 直到全局作用域(window) 都没有
    + 会把这个变量定义为全局变量在进行赋值

递归函数

    + 是一种函数的调用方式, 一种高阶的函数调用方式
    + 什么是递归函数 ?
      => 一个函数自己调用了自己
      => 并且正确设置了返回条件

  递归函数的书写技巧
    1. 写一个函数
    2. 先写折返点
    3. 未到达折返点的样子, 不要忘记 return

认识对象数据类型

  对象
    + 一类内容中的真实个例
    + 一种 JS 的数据类型 Object

  对象数据类型 Object
    + 是一个复杂数据类型
    + 私人: 是一个 "盒子", 是一个承载 数据 的盒子
    + 是一个无序的数据集合
    + 是一个 键值对 的集合

  对象数据类型的创建
    1. 字面量方式创建对象
      + 语法:
        => 创建一个空对象: var obj = {}
        => 创建一个带有数据的对象: var obj = { 键值对, 键值对, ... }
          -> 键值对      键: 值
    2. 内置构造函数方式创建
      + 语法:
        => 创建空对象: var obj = new Object()


  对象内对于 键(key) 的要求
    1. 推荐使用符合变量命名规则和规范的名字
    2. 可以使用纯数字当做 键名
      -> 当你的键名是纯数字的时候, 会排列在最前面
    3. 可以使用任何特殊符号
      -> 要求: 当你使用特殊符号的时候, 在书写的时候需要被引号包裹
      

** 持续更新中,,,**