小白学前端06-js入门

177 阅读1小时+

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

前言

  • 这一篇文章我们来讲一波js相关内容
  • 只不过只会讲一些简单的内容多余的并不会讲
  • 目标用js在浏览器弹出的对话框中显示helloword

内容

JavaScript

js简介

什么是语言
  • 计算机就是一个由人来控制的机器, 人让它干嘛, 它就得干嘛.
  • 我们要学习的语言就是人和计算机交流的工具, 人类通过语言来控制, 操作计算机.
  • 编程语言和我们说的中文, 英文本质上没有区别, 只是语法比较特殊.
  • 语言的发展史

-纸带机: 机器语言

-汇编语言: 符号语言

-现代语言: 高级语言

起源

  • JavaScript诞生于1995年, 它的出现主要用于处理网页中的前端验证.
  • 所谓的前端验证, 就是指检查用户输入的内容是否符合一定的规则.
  • 比如用户名的长度, 密码的长度, 邮箱的格式等.

简史

  • javaScript是由网景公司发明, 期初命名LiveScipt,后来由于SUN公式公司的介入更名为javaScript.
  • 1996年微软公司在其最新的IE3浏览器中引入了自己对javaScript的实现Jscript.
  • 于是在市面上存在两个版本的JavaScript, 一个网景公司的javascript, 和微软的JScript.
  • 为了确保不同的浏览器上运行的JavaScript标准一致, 所以几个公司共同定制了JS的标准命名为ECMAScript.

实现

  • ECMAScript是一个标准, 而这个标准需要由各个厂商去实现.
  • 不同的浏览器厂商对该标准会有不同的实现.
  • 我们已经知道ECMAScript是javaScript标准, 所以一般情况下这两个词我们认为是一个意思
  • 但实际上javaScript的含义却要更大一些
  • 一个完整的JavaScript实现应该由以下三个部分构成: ECMAScript DOM BOM

特点

  • 解释型语言
  • 类似于 C 和 Java 的语法结构
  • 动态语言
  • 基于原型的面向对象

js基础

hello_world

js代码需要编写到script标签中

alert()

警告, 会弹出一个窗口

document.write()

  • 向文档(浏览页面)中写入一些东西
  • document.write() 可以向body中输出一个内容

console.log

  • 向控制台输出一个内容
  1. 可以将js代码编写到标签的onclick属性中

  1. 可以将js代码写在超链接的href属性中, 这样当点击超链接时, 会执行js代码
  2. 虽然可以写在标签的属性中, 但是他们属于结构于行为耦合, 不方便维护不推荐使用

你也点我一下

  1. 希望超链接点完后没有反应

  1. 可以将js代码编写到外部js文件中, 然后通过script标签引入写到外部文件中可以在不同的页面同时引用, 也可以利用到浏览器的缓存机制,,推荐使用的方式
  2. script标签一旦用于引入外部文件了, 就不能在编写代码了, 即使编写了浏览器也会忽略 , 如果需要则可以再创建一个新的script标签用于编写内部代码

基本语法

注释:

  • 注释中的内容不会被执行, 但是可以在源代码中查看,
  • 要养成良好的编写注释的习惯, 也可以通过注释来对代码进行一些简单的调试

// 单行注释

/**/ 多行注释

  1. JS中严格区分大小写
  2. JS中每一条语句以分号(;)结尾
    • 如果不写分号, 浏览器会自动添加, 但是会消耗一些系统资源, 而且有些时候, 浏览器会加错分号, 所以在开发中分号必须写
  3. JS中会忽略多个空格和换行, 所以我们可以利用空格和换行对代码进行格式化

字面量和变量

  1. 字面量, 都是一些不可改变的值
  • 比如: 1 2 3 4 5
  • 字面量都是可以直接使用的但是我们一般都不会直接使用字面量
  1. 变量
  • 变量可以用来保存字面量, 而且变量的值是可以任意改变的,
  • 变量更加方便我们使用
  • 很少直接使用字面量
  1. 声明变量
- 在js中使用var关键字来声明一个变量

    
    var a;
    

    为变量赋值

        a = 123;

        //声明和赋值同时进行
        var b = 123;

#### 标识符
  • 在JS中所有的可以由我们自主命名的都可以称为是标识符
  • 例如: 变量没那个, 函数名, 属性名都属于标识符
  • 命名一个标识符需要遵守如下的规则:
    1. 标识符可以含有字母 , 数字, 下划线(_), 刀了符($)
      //合法
      var a_1_$
      
    2. 标识符不能以数字开头
    3. 标识符不能是ES中的关键字后保留字
    4. 标识符一般都采用驼峰命名法
    • 首字母小写, 每个单词开头字母大写, 其余字母小写

      helloWorld

          5. JS底层保存标识符实际上是采用的Unicode编码
      
  • 所以理论上讲, 所有的utf-8中含有的内容都可以作为标识符

数据类型

数据类型指的就是字面量的类型

在JS中一共有六种数据类型

  1. String 字符串
  2. Number 数值
  3. Boolean 布尔值
  4. Null 空值
  5. Undefind 未定义
  6. Object 对象
  • 其中String Number Boolean Null Undefined属于基本数据类型

1. String字符串

  • 在JS中字符串需要使用引号引起来

var str = "hello";

console.log("hello");

  • 使用双引号或单引号都可以, 但是不要混着用
  • 引号不能嵌套, 双引号不能放双引号, 单引号不能放单引号
  • 在字符串中表示一些特殊符号时可以使用反斜杠()作为转义字符, 当表示一些特殊符号时可以使用反斜杠()进行转义
\" 表示"
\' 表示'
\n  表示换行
\t  制表符
\\  表示\

str = "我说:\"今天天气真不错!\"";

//输出字面量 字符串str
alert("str"); //str

//输出变量str
alert(str); //我说:"今天天气真不错!"

2. Number

在JS中所有的数值都是Number类型,

包括整数和浮点数 (小数)

  • 可以使用一个运算符typeof来检查一个变量的类型

语法: typeof 变量

检查字符串是, 会返回String

检查数值时, 会返回number

console.log(typeof a);

  • JS中可以表示的数字的最大值

    Number.MAX_VALUE

    • 如果使用Number表示的数字超过了最大值, 则会返回一个
    • Infinity 表示正无穷
    • -Infinity 表示负无穷
    • 使用typeof检查Infinity也会返回Number
  • NaN 是一个特殊的数字, 表示Not A Number

    • 使用typeof检查一个NaN也会返回一个number
    • Number.MIN_VALUE 大于0的最小值

a = Number.MIN_VALUE;

console.log(a); //5e-324

在JS中整数的运算基本可以保证精确

​ 所以千万不要使用JS进行对精确度要求比较高的运算

3. 布尔值Boolean

  • Boolean 布尔值
  • 布尔值只有两个, 主要用来做逻辑判断

true 表示真

false 表示假

使用typeof检查一个布尔值时, 会返回boolean

var bool = true;
console.log(bool); //true
console.log(typeof bool); //boolean

4. Null和Undefined

  • Null类型的值只有一个, 就是null

    var a = null;

    console.log(a); //null

    console.log(typeof a); //object

  • null(空值)这个值专门用来表示一个为空的对象
  • 使用typeof检查一个null值时, 会返回object
  • Undefined(未定义)类型的值只有一个, 就undefined
  • 当声明一个变量, 但是并不给变量赋值时, 它的值就是undefined
  • 使用typeof检查一个undefined时也会返回undefined

var b = undefined;

console.log(b); //undefined

5. 强制类型转换

  • 指将一个数据类型强制转换为其他的数据类型
  • 类型转换主要指, 将其他的数据类型, 转换为 String Number Boolean
  1. ==将其他的数据类型转换为String==
    • ==方式一:==
      • 调用被转换数据类型的toString()方法
      • 该方法不会影响到原变量, 它会将转换的结果返回
      • 但是注意: null和undefined这两个值没有toString()方法, 如果调用他们的方法会报错
var a = 123;
console.log(typeof a); //Number
console.log(a);  //123

//调用a的toString()方法
//调用xxx的yyy()方法, 就是xxx.yyy()
var b = a.toString();
console.log(typeof b); //string
console.log(b);  //"123"
  • 方式二
    • 调用String()函数, 并将被转换的数据作为参数传递给函数
      //调用String()函数, 来将a转换为字符串
      a = null;
      a = String(a);
      console.log(typeof a);//string
      console.log(a);//"null"
      
    • 使用String()函数做强制类型转换时,
      1. 对于Nuber和Boolean实际上就是调用的toString()方法

      2. 但是对于null和undefined, 就不会调用toString()方法它会将null直接转换为"null"

        会将undefined直接转换为"undefined"

    1. ==将其他的数据类型转换为Number==
      • 调用Number()函数来将a转换为Number类型
        • 字符串 --> 数字
        1. 如果是纯数字的字符串, 则直接转换为数字
          let a = "123";
          a = Number(a);
          console.log(a);//123
          
        2. 如果字符串中有非数字的内容, 则转换为NaN
    
            ```js
            let a = "123abc";
            var = Number(a);
            console.log(a);//NaN
            ```
    
        3. 如果字符串是一个空串或者是一个全是空格的字符串, 则转换为0
    
        - 布尔 --> 数字
    
            true 转成1
    
            false 转成0
    
        -  Null --> 数字 == 0
    
        - undefined --> 数字 == NaN
    
    • 转换方式二
      • 这种方式专门用来对付字符串

      • parseInt() //解析整形

        把一个字符串转换为一个整数

        a ="123px";

        //调用parseInt()函数将a转换为Number

        a = parseInt(a);

        console.log(typeof a);//number

        console.log(a);//123

      • parseFloat()

        parseFloat()作用和parseInt()类似, 不同的是它可以获得有效的小数

        a = "123.456px";

        a = parseFloat(a);

        console.log(typeof a);//number

        console.log(a);//123.456

      • 如果对非String使用parseInt()或parseFloat()

        它会将其先转换为String, 然后再操作

    其他进制的数字

    • 在JS中, 如果需要表示16进制的数字, 则需要以0x开头

      //十六进制

      a = 0x10;

      console.log(a);//16

      a = 0xCafe;//51966

    • 如果需要表示8进制的数字, 则需要以0开头

      //八进制

      a = 070;

      console.log(a);//56

      //像"070"这种字符串有些浏览器会当成8进制解析, 有些会当成10进制解析

      a = 070;

      //可以在parseInt()中传递一个第二个参数, 来指定数字的进制

      a = parseInt(a, 10);

    • 如果需要表示二进制的数字, 则需要以0b开头

      但是不是所有的浏览器都支持

      //二进制数字

      a = 0b10;

      console.log(a);//2

    转换为Boolean

  • 将其他的数据类型转换为Boolean
    • 使用Boolean()函数
      • 数字 ---> 布尔
        • 除了0和NaN, 其余的都是true
      • 字符串 ---> 布尔
        • 除了空串, 其余的都是true
      • null和undefined都会转换为false
      • 对象也会转换为true
  • 调用Boolean()函数来将a转换为布尔值

    let a = 0;

    a = Boolean(a);

    console.log(typeof a);//Boolean

    console.log(a);//false

运算符 +-*/

  • 运算符也叫操作符

    通过运算符可以对一个或多个值进行运算, 并获取运算结果

    比如: typeof就是一个运算符, 可以来获得一个直的类型, 它会将该值得类型以字符串的形式返回

    var a = 123;

    typeof a;

  • 算数运算符

    • 当对非number类型的值进行计算时, 会将这些值转换为Number然后再运算
      • 任何值和NaN做运算都得NaN
      • 任何值和字符串相加都会转换为字符串

        我们可以利用这一特点, 来将一个任意的数据类型转换为String

        我们只需要为任意的数据类型+ 一个 "" 即可将其转换为String这是一种隐式的类型转换,由浏览器自动完成,他实际上也是调用String()函数

        c = c + "";

    ​ 加可以对两个值进行加法运算, 并将结果返回

    ​ 如果对两个字符串进行加法yunsuan,则会做拼串

    ​ 会将两个字符串拼接为一个字符串,并返回

    - 可以对两个值进行减法运算, 并将结果返回
    
    • - 可以对两个值进行乘法运算
      

      /

    • 可以对两个值进行除法运算

      %

    • 可以对两个值取余

  • 任何值做 - * / 运算时都会自动转换为Number

    ​ 我们可以利用这一特点做隐式类型转换

    ​ 可以通过一个值 -0 *1 /1 来将其转换为Number

    ​ 原理和Number()函数一样但是, 使用起来更加简单

一元运算符

  • 一元运算符只需要一个操作数

    +正号

    ​ 正号不会对数字产生任何影响

    -负号

    ​ 负号可以对数字进行符号取反

    对于非Number类型的值

    ​ 它会先转换为Number, 然后再运算

    ​ 可以对一个其他的数据类型使用+, 来将其转换为number它的原理和Number()函数一样

自增和自减

自增

  • 通过自增可以使变量在自身的基础上增加1

  • 对于一个变量自增以后, 原变量的值会立即自增1

  • 自增分成两种: 后++(a++) 和 前++(++a)

     无论是a++ 还是 ++a, 都会立即使原变量的值自增1
    

    ​ 不同的是a++ 和 ++a的值不同

    a++的值等于原变量的的值(自增前的值)

    ++a的值等于原变量的新值(自增后的值)

    //使a自增1

    a++

自减

  • 通过自减可以使变量在自身的基础上减1

  • 自减分成两种: 后--(a--) 和前--(--a)

     无论是a-- 还是 --a, 都会立即使原变量的值自减1
    

    ​ 不同的是a++ 和 ++a的值不同

    a--的值等于原变量的的值(自减前的值)

    --a的值等于原变量的新值(自减后的值)

逻辑运算符

  • JS中为我们提供了三种逻辑运算符

! 非

  • !可以用来对一个值进行非运算

  • 所谓非运算就是对一个布尔值进行取反操作

  • 如果对一个值进行两次取反, 它不会变化

  • 如果对非布尔值进行取反, 则会将其转换为布尔值, 然后再取反,

     所以我们可以利用该特点, 来讲其他数据类型转换为布尔值
                                                                                                                                                                                                                
    

    可以为任意数据类型取两次反, 来将其转换为布尔值

    原理和Boolean()函数一样

    var a = "hello";

    a == !!a;

    console.log(a);//true

    var b = 10;

    console.log(!b);//false

    var a = true;

    console.log("a = " + !a);//false

    && 与(且)

    • &&可以对符号两侧的值进行与运算并返回结果
    • 运算规则
      • 两个之中只要一个值为false就会返回false,

        • 只有两个值都为ture时, 才会返回true

        • JS中的"与"属于短路的与,

          ​ 如果第一个值为false则不会看第二个值

        例子:

        ​ //第一个值为true, 会检查第二个值

        ​ true && alert("看我出不出来!");

        ​ //第一个值为false, 则不会检查第二个值

        ​ false && alert("看我出不出来!!");

        || 或

      • || 可以对符号两侧的值进行或运算并返回结果

        • 两个值中只要有一个true, 就返回true

        • 如果两个值都为false, 才返回false

        • JS中的"或"属于短路的或,

          ​ 如果第一个值为true则不会看第二个值

          例子:

          //第一个值为false, 则会检查第二个值

          false || alert("123");// 会执行

          //第一个值为true, 则不会检查第二个值

          true || alert("123");//不会执行

  • && || 非布尔值的情况
    • 对于非布尔值进行与或运算时,

      ​ 会将其转换为布尔值, 然后再运算, 并且返回原值

      • 与运算:

        ~ 如果第一个值为true, 则必然返回第二个值

        ~ 如果第一个值为false, 则直接返回第一个值

      • 或运算:

        ~ 如果第一个值为true, 则直接返回第一个值

        ~ 如果第一个值为false, 则返回第二个值

      //true && true

      //与运算: 如果两个值都为true, 则返回后边的

      var result = 5 && 6;//返回6

      //与运算: 如果两个值中都有false, 则返回靠前的false

      //false && true

      result = 0 && 2;//返回0

赋值运算符

=

​ 可以将符号右侧的值赋值给符号左侧的变量

+=

a += 5//等价于a = a + 5;

-=

a -= 5//等价于a = a - 5;

*=

/=

%=

关系运算符

  • 通过关系运算符可以比较两个值之间的大小关系

  • 如果关系成立它会返回true, 如果关系不成立则返回false

    (>)大于号

    • 判断符号左侧的值是否大于右侧的

    • 如果关系成立, 返回true, 如果关系不成立则返回false

      console.log(5 > 10);//false

    (>=)大于等于

    • 判断符号的左侧的值是否大于或等于右侧的值

      console.log(5 >= 5);//true

    (<)小于号

    (<=)小于等于

  • 非数值的情况

    console.log(1 > true);//false

    console.log(1 >= true);//true

  • 任何值和NaN做任何比较都是false

  • 如果符号两侧的值都是字符串时, 不会将其转换为数字进行比较

    ​ 而会分别比较字符串中字符的Unicode编码

//比较两个字符串时, 比较的是字符串的字符编码

console.log("a" < "b");//true

//比较中文时没有意义

console.log("戒" > "我"); //true

Unicode编码表

  • 在字符串中使用转义字符输入Unicode编码

    \u四位编码

console.log("\u1234");//可以输出Unicode编码

  • 在网页中使用Unicode编码(是十六进制的)
    • &#编码; 这里的编码需要的是10进制

相等运算符

  • 相等运算符用来比较两个值是否相等

    • 如果相等会返回true, 否则返回false

      console.log(1 == 1);//true

      当使用==来比较两个值时, 如果值得类型不同,

      ​ 则会自动进行类型转换, 将其转换为相同类型的值,

      ​ 然后再比较

      特殊:

      console.log(null == 0); //false

  • undefined 衍生自null

  • 所以这两个值做相等判断时, 会返回true

  • NaN不和任何值相等, 包括它本身

    console.log(NaN == "1"); //false

    console.log(NaN == NaN); //false

    ==判断一个函数是否是NaN==

      - 可以通过isNaN()函数来判断一个值是否是NaN
      - 如果该值是NaN则返回true, 否则返回false
    

let b = NaN;

isNaN(b); true

==不相等==

  • 不相等用来判断两个值是否不相等如果不相等返回true, 如果相等返回false
  • 使用 != 来做不相等运算
  • 不相等也会对变量进行自动的类型转换, 如果转换后相等它也会返回false

    console.log(10 != 5); true

===

​ ==全等==

  • 全等用来判断两个值是否全等, 它和相等类似, 不同的是它不会做自动的类型转换
     如果两个值的类型不同直接返回false
    

    console.log("123" === 123);//false

!==

​ ==不全等==

  • 不全等用来判断两个值是否全等, 它和不等类似, 不同的是它不会做自动的类型转换
     如果两个值的类型不同直接返回true
    

条件运算符

  • 条件运算符也叫三元运算符
    • 语法

      条件表达式?语句1:语句2;

      • 执行的流程:

        ​ 1. 条件运算符在执行时, 首先对条件表达式进行求值, 2. 如果该值为true, 则执行语句1,并返回执行结果 3. 如果该值为false, 则执行语句2, 并返回执行结果 4. 如果条件表达式的求值结果是一个非布尔值

         会将其转换为布尔值然后再运算
                                                                                                                                                                                                                                                                                                                                                                                                                     
        

        true?alert("语句1"):alert("语句2");

        var a = 30;

        var b = 20;

        a > b ? alert("a大"):alert("b大");

        //获取a和b中的最大值

        var max = a > b ? a : b;

        //获取a b c 中的的大值

        max = max > c ? max : c;

        //一行代码

        //这种写法不推荐使用, 不方便阅读

        let max = a > b ? (a > c ? a : c) : (b > c ? b : c);

运算符的优先级

  1. 逗号(,)运算符
  • 使用(,)可以分割多个语句, 一般可以在声明多个变量时使用

    //使用(,)运算符同时声明多个变量

    var a, b, c;

    //可以同时声明多个变量并赋值

    var a=1, b=2, c=3;

  1. 就和数学中一样, 在JS中运算符也有优先级
  • 比如: 先乘除后加减
  • 在JS中有一个运算符优先级的表
    • 在表中越靠上优先级级越高, 优先级越高越优先计算
    • 如果优先级一样, 则从左往右计算
    • 但是这个表我们并不需要记忆, 如果遇到优先级不清楚
      • 可以使用()来改变优先级

优先级表

代码块

  1. 我们的程序是由一条一条语句构成的
    • 语句是按照自上向下的顺序一条一条执行的
    • 在JS中可以使用{}来为语句进行分组
      • 同一个{}中的语句我们称为是一组语句
      • 他们要么都执行要么都不执行,
      • 一个{}中的语句也称为一个代码块
  2. JS中的代码块, 只具有分组的作用, 没有其他的用途
     - 代码块的内容, 在外部是完全可见的
    

{

alert("hello");

alert("hello");

alert("hello");

}

流程控制语句

  • JS中的程序是从上到下一行一行执行的

  • 通过流程控制语句可以控制程序执行流程,

    ​ 使程序可以根据一定的条件来选择执行

  • 语句的分类:

    1. 条件判断语句
    2. 条件分支语句
    3. 循环语句

==条件判断语句==

  • 使用条件判断语句可以在执行某个语句之前进行判断

    ​ 如果条件成立才会执行语句, 条件不成立则语句不执行

  • if语句

  • 语法一:

    if(条件表达式)

    语句

    如果条件表达式的值为true, 则执行if后的语句

    如果条件表达式的值为false, 则不会执行if后的语句

    ​ if语句只能控制紧随其后的那个语句

    ​ 如果希望if语句可以控制多条语句,

    ​ 可以将这些语句统一放到代码块中

    if语句后的代码块不是必须的, 但是在开发中尽量写上代码块, 即使if后只有一条语句

  • 语法二:

    if(条件表达式){

    ​ 语句...

    }else{

    ​ 语句...

    }

    if...else...语句

    ​ 当该语句执行时, 会先对if后短的条件表达式进行求值判断,

      - 如果该值为true, 则执行if后的语句
      - 如果该值为false, 则执行else后的语句
    
  • 语法三:

    if(条件表达式){

    语句

    }else if(条件表达式){

    ​ 语句...

    }else if(条件表达式){

    ​ 语句...

    }else{

    ​ 语句...

    }

    if...else if...else

    ​ 当该语句执行时, 会从上到下依次对条件表达式进行求值判断

    ​ 如果值为true, 则执行当前语句

    ​ 如果值为false, 则继续向下判断

    ​ 如果所有的条件都不满足, 则执行最后一个else后的语句

    ​ 该语句中, 只会有一个代码块被执行, 一旦代码块执行了, 则直接结束语句

条件分支语句

  1. 条件分支语句也叫==Switch语句==

语法:

​ switch(条件表达式){

​ case 表达式:

​ 语句...

​ break;

​ case 表达式:

​ 语句...

​ break;

​ default:

​ 语句...

​ break;//使用break可以来退出switch语句

}

执行流程:

​ - switch...case...语句

​ - 在执行时会依次将case后的表达式的值和switch后的条件表达式的值进行全等比较

​ - 如果比较结果为true, 则从当前case处开始执行代码

​ 当前case后的所有的代码都会执行, 我们可以在case的后边跟着一个break关键字

​ 这样可以确保只会执行当前case后的语句, 而不会执行其他的case

  • 如果比较结果为false, 则继续向下比较
    • 如果所有的比较结果都为false, 则只执行default后的语句

switch语句和if语句的功能实际上有重复的, 使用switch可以实现if的功能,

同样使用if也可以实现switch的功能, 所以我们使用时可以根据自己的习惯选择

循环语句

  • 循环语句:

    通过循环语句可以反复的执行一段代码多次

1.while循环

  • 语法

    while(条件表达式){

    ​ 语句...

    }

  • while语句在执行时,
    • 先对条件表达式进行求值判断
      • 如果值为true, 则执行循环体,

        ​ 循环体执行完毕以后, 继续对表达式进行判断

        ​ 如果为true, 则继续执行循环体

        如果值为false, 则终止循环

        //像这种将条件表达式写死为true的循环, 叫做死循环

        //该循环不会停止, 除非浏览器关闭,死循环在开发中慎用

        //可以使用break, 来终止循环

        let n = 1;

        while(true){

        ​ alert(n++);

        ​ //判断n是否是10

        ​ if(n == 10){

        ​ //退出循环

        ​ break;

        ​ }

        }

        //创建一个循环, 往往需要三个步骤

        //1. 创建初始化变量

        var i = 0;

        //2. 在循环中设置一个条件表达式

        while(i < 10){

        ​ //3. 定义一个更新表达式, 每次更新初始化变量

        ​ i++;

        }

2. do...while循环

  • 语法:

    do{

    ​ 语句...

    }while(条件表达式)

  • 执行流程: do...while语句在执行时, 会先执行循环体. 循环体执行完毕以后, 再对while后的条件表达式进行判断 如果结果为true, 则继续执行循环体, 执行完毕继续判断以此类推 如果结果为false, 则终止循环
    • 实际上这两个语句功能类似, 不同的是while是先判断后执行, 而do...while会先执行后判断,

      do...while可以保证循环体至少执行一次.

      ​ 而while不能

3. for循环

  • for语句, 也是一个循环语句, 也称为for循环

    在for循环中, 为我们提供了专门的位置用来放三个表达式:

    1. 初始化表达式
    2. 条件表达式
    3. 更新表达式

      for循环的语法:

      ​ for(①初始化表达式;②条件表达式;④更新表达式){

      ​ ③语句...

      ​ }

      for循环的执行流程:

      ​ ①执行初始化表达式, 初始化变量(初始化表达式只会执行一次

      ​ ②执行条件表达式, 判断是否执行循环

      ​ 如果为true, 则执行循环③

      ​ 如果为false, 终止循环

      ​ ④执行更新表达式, 更新表达式执行完毕, 继续重复②

    • 在for循环中的三个部分都可以省略, 也可以写在外部
      • 如果在for循环中不写任何的表达式, 只写两个分号(;)
      • 此时循环是一个死循环会一直执行下去, 慎用

        for(;;){

        ​ alert("hello");

        }

break和continue

  • break关键字可以用来退出switch或循环语句

    -- 不能在if语句中使用break和continue

    -- break关键字, 会立即终止离他最近的那个循环语句

    可以为循环语句创建一个label. 来标 识当前的循环

    label:循环语句

    使用break语句是, 可以在break后跟着一个label.

    ​ 这样break将会结束指定的循环, 而不是最近的

    例子:

    ​ break ourter;

  • ==continue==关键字可以用来跳过当次循环

    • 同样continue也是默认只会对离他最近的循环起作用

对象

  1. 对象的介绍

    JS中的数据类型

    • String 字符串
    • Number 数值
    • Boolean 布尔值
    • Null 空值
    • Undefined 未定义
      • 以上五种属于基本数据类型

        只要不是上边5种, 全都是对象

    • Object 对象

      基本数据类型都是单一的值"hello" 123 true

       值和值之间没有任何的联系
      

      如果使用基本数据类型的数据, 我们所创建的变量都是独立, 不能成为一个整体

      对象属于一种复合的数据类型, 在对象中可以保存多个不同的数据类型的属性

      对象的分类:

      1. 内建对象
        • 由ES标准中定义的对象, 在任何ES的实现中都可以使用
        • 比如: Math String Number Boolean Function...
      2. 宿主对象
        • 由JS的运行环境提供的对象, 目前来讲主要指由浏览器提供的对象
        • 比如BOM DOM
      3. 自定义对象
        • 由开发人员自己创建的对象
  2. 对象的基本操作

  • 创建对象

    使用new关键字调用的函数, 是构造函数construcor

    ​ 构造函数是专门用来创建对象的函数

    var obj = new Object();

    console.log(obj);

    使用typeof检查一个对象时, 会返回一个object

  • 在对象中保存的值称为属性

    向对象添加属性

    语法: 对象.属性名 = 属性值;

  • 读取对象中的属性

    语法: 对象.属性名

    如果读取对象中没有的属性, 不会报错而是会返回undefined

  • 修改对象的属性

    语法: 对象.属性名 = 新值

    obj.name = "tom";

    console.log(obj.name);

  • 删除对象的属性

    语法: delete 对象.属性名

    delete.obj.name

  • 属性名和属性值

    向对象中添加属性

    属性名:

    • 对象的属性名不强制要求遵守标识符的规范

      obj.name = "孙悟空";

  • 如果要使用特殊的属性名, 不能采用.的方式来操作

    需要使用另一种方式:

    ​ 语法: 对象["属性名"] = 属性值

    读取是也需要采用这种方式

    使用[]中可以直接传递一个变量, 这样变量的值是多少就会读取那个个属性

    obj["123"] = 789;

    obj["nihao"] = "你好";

    console.log(obj["123"]);

  • 属性值

    ​ JS对象的属性值, 可以是任意的数据类型

    ​ 甚至可以是一个对象

    创建一个对象

    var obj2 = new Object();

    obj.name = "猪八戒";

    //将obj2设置为obj的属性

    obj.test = obj2;

in 运算符
  • 通过该运算符可以检查一个对象中是否含有指定的属性

     如果有则返回true, 没有则返回false
    
  • 语法:

    ​ "属性名" in 对象

    //检查obj中是否含有test2属性

    console.log("test2" in obj);

  • 基本数据类型和引用数据类型

    基本数据类型

    String Number Boolean Null Undefind

    引用数据类型

    Object

    ==JS中的变量都是保存到栈内存中的==

    ​ 基本数据类型的值直接在栈内存中存储

    ​ 值与值之间是独立存在, 修改一个变量不会影响其他变量

    ​ 对象是保存到堆内存中的, 每创建一个新的对象, 就会在队内存中开辟一块新的空间

    ​ 而变量保存的是对象的内存地址(对象的引用), 如果两个变量保存的是同一个对象引用,

    当一个通过一个变量修改属性时, 另一个也会收到影响

Object

​ - 当比较两个基本数据类型的值时, 就是比较值.

​ - 而当比较两个应用类型的数据类型时, 它比较的对象的内存地址, 如果两个对象是一模一样的, 但是地址不同, 它也会返回false

console.log(obj3 == obj4);//false

  • 对象字面量
    • 使用对象字面量来创建一个对象

      var obj = {};

    • 使用对象字面量时, 可以在创建对象时, 直接指定对象中的属性

      语法: {属性名: 属性值, 属性名: 属性值....}

      • 对象字面量的属性名可以加引号也可以不加, 建议不加,

      • 如果要使用一些特殊的名字, 则必须加引号

      • 属性名和属性值是一组一组的名值对结构,

        名和值之间使用:连接, 多个名值对之间使用, 隔开

        如果一个属性之后没有其他的属性了就不要写

      let obj2 = {name:"猪八戒",

      ​ age:28 };

  • 使用工厂方法创建对象
    • 通过该方法可以大批量的创建对象

      function createPerson(){
          //创建一个新的对象
          var obj = new Object();
          obj.name = "孙悟空";
          obj.age = 18;
          obj.gender = "男";
          obj.sayName = function(){
              alert(this.name);
          }
          //将新对象返回
          return obj;
      }
      var obj2 = createPerson("孙悟空", 28, "男");
      var obj3 = createPerson("沙和尚", 28, "男");
      var obj4 = createPerson("猪八戒", 28, "男");
      
      
      
    • 使用工厂方法创建的对象, 使用的构造函数都是Object

      ​ 所以创建的对象都是Object这个类型

      ​ 就导致我们无法区分出多种不同类型的对象

    • 构造函数

      • 创建一个构造函数, 专门用来创建Person对象的
        • 构造函数就是一个普通的函数, 创建方式和普通函数没有区别,
        • 不同的是构造函数习惯首字母大写
        • 构造函数和普通函数的区别就是调用的方式不同
          • 普通函数是直接调用, 而构造函数需要使用new关键字来调用

函数

函数的简介

函数function

  • 函数也是一个对象

  • 函数中也可以封装一些功能(代码), 在需要时可以执行这些功能(代码)

  • 函数中可以保存一些代码在需要的时候调用

  • 使用typeof检查一个函数对象时, 会返回function

    //==我们在实际开发中很少使用构造函数来创建一个函数对象==

    //创建一个函数对象

    //可以将要封装的代码以字符串的形式传递给构造函数

    var fun = new Function("console.log('hello')");

    //封装到函数中的代码不会立即执行

    //函数中的代码会在函数调用的时候执行

    //调用函数 语法: 函数对象()

    //当调用函数时, 函数中封装的代码会按照顺序执行

    fun();

  • 使用 函数声明 来创建一个函数

    语法:

    • function 函数名([形参1, 形参2...形参N]){

      ​ }

  • 使用 函数表 达式来创建一个函数

    var 函数名 = function([形参1, 形参2...形参N]){

    ​ 语句.....

    }

    var fun3 = function(){

    ​ console.log("我是匿名函数中封装的代码");

    };

  • 函数的参数

    定义一个用来求两个数和的函数

    ​ 可以在函数的()中来指定一个或多个形参(形式参数)

    ​ 多个形参之间使用,隔开, 声明形参就相当于在函数内部声明了对应的变量, 但是并不赋值

    function sum(a, b){

    ​ console.log(a+b);

    }

    //在调用时, 可以在()中指定实参(实际参数)

    ​ 实参将会赋值给函数中对应的形参

    sum(1, 2);

    • 调用函数解析器不会检查实参的类型
    • 所以要注意, 是否有可能会接收到非法的参数, 如果有可能则需要对参数进行类型的检查
    • 调用函数时, 解析器也不会检查实参的数量
      • 多余的实参不会被赋值
      • 如果实参的数量少于形参的数量, 则没有对应实参的形参将是Undefined
  • 函数的返回值

    • 可以使用return 来设置函数的返回值

      语法:

      ​ return 值;

      return后的值将会作为函数执行的结果返回

      ​ 可以定义一个变量来接收该值的结果

      在函数中return后的语句都不会执行

      ,

      如果return语句不跟任何值就相当于返回一个undefined

      如果函数中不写return, 则也会返回undefined

      return后可以跟任意类型的值 //调用函数

      //变量result的值就是函数执行结果

      //函数返回什么result的值就是什么

      var result = sum(4, 5, 6);

  • 实参可以是任意的数据类型也可以是对象

    当我们的参数过多时, 可以将参数封装到一个对象中,然后通过对象传递

    • 实参可以是一个对象, 也可以是一个函数

      mianji()

      • 调用函数
      • 相当于使用函数的返回值 mianji
      • 函数对象
      • 相当于直接使用函数对象
  • 返回值的类型

    //使用break可以退出当前的循环

    //continue用于跳过当次循环

    //使用return可以结束整个函数

  • 返回值可以是任意的数据类型

    ​ - 也可以是一个对象, 也可以是一个函数

- 立即执行函数

//函数对象()

立即执行函数

- 函数定义完, 立即被调用, 这种函数叫做立即执行函数
- 立即执行函数往往只会执行一次
(function(){

​    alert("我是一个匿名函数~~~");

})()

(function(a, b){
    console.log("a = "+ a);
    console.log("b = "+ b);
})(123, 456);

方法

  • 对象的属性值可以是任何的数据类型, 也可以是个函数

    obj = new Object;

    obj.sayName = function(){

    };

    obj.sayName;

  • 函数也可以称为对象的属性,
    • 如果一个函数作为一个对象的属性保存,
    • 那么我们称这个函数是这个对象的方法
    • 调用函数就说调用对象的方法(method)
    • 但是它只是名称上的区别没有其他的区别

枚举对象中的属性

//枚举对象中的属性

//使用for ... in 语句

语法:

​ for(var 变量in 对象){

​ }

for ... in 语句 对象中有几个属性, 循环体就会执行几次

for(var n in obj){

​ console.log(n);

​ console.log(obj[n]);

}

作用域(Scope)

  • 作用域指一个变量的作用范围
  • 在js中一共有两种作用域:
    1. 全局作用域

    • 直接编写在script标签中的JS代码, 都在全局作用域

    • 全局作用域在页面打开时创建, 在页面关闭时销毁

    • 在全局作用域中有一个全局对象Window, 函数作用域

      ​ 它代表的是一个浏览器的窗口, 它由浏览器创建我们可以直接使用

    • 在全局作用域中:

      ​ 创建的变量都会作为Window对象的属性保存

      ​ 创建的函数都会作为window对象的方法保存

    • 全局作用域中的变量都是全局变量

      在页面的任意部分都可以访问得到 var a = 10;

      console.log(window.a);//10

      function fun(){

      ​ console.log("我是fun的函数");

      }

      window.fun()//我是fun的函数

  • 变量的声明提前
    • 使用var关键字声明的变量, 会在所有代码执行之前被声明(但是不会被赋值)
    • 但是如果声明变量时不使用var关键字, 则变量不会被声明提前
  • 函数的声明提前
    • 使用函数声明形式的函数function 函数(){}

    它会在所有的代码执行之前就被创建, 所以我们可以在函数声明前调用函数

    • 使用函数表达式创建的函数, 不会被声明提前, 所以不能在声明前调用
//函数声明, 会被提前创建
function fun(){
    console.log("我是一个fun函数");
}

//函数表达式, 不会被提前创建
var fun2 = function(){
    console.log("我是fun2函数");
};
  • 函数作用域

    • 调用函数时创建函数作用域, 函数执行完毕以后, 函数作用域销毁

    • 每调用一次函数就会创建一个新的函数作用域, 她们之间是互相独立的

    • 在函数作用域中可以访问到区局作用域的变量, 在全局作用域中无法访问到函数作用域中的变量

    • 当在函数作用域操作一个变量时, 它会先在自身作用域中寻找, 如果有就直接使用,

      如果没有则向上一级作用域中寻找, 直到找到全局作用域,

      如果全局作用域中依然没有找到, 则会报错

    • 在函数中要访问全局变量可以使用widow对象

    • ==在函数作用域中也有声明提前的特性==

      ​ 1. 使用var关键字声明的变量, 会在函数中所有的代码执行之前被声明

      ​ 2. 函数声明也会在函数中所有代码执行之前执行 3. 在函数中, 不使用var声明的变量都会成为全局变量 4. 定义形参就相当于在函数作用域中声明了变量

    • 构造函数

      ​ 创建一个构造函数, 专门用来创建Person对象的

      • 构造函数就是一个普通的函数, 创建方式和普通函数没有区别
      • 不同的是构造函数习惯首字母大写

      构造函数和普通函数的区别就是调用方式的不同

      普通函数是直接调用, 而构造函数需要使用new关键字来调用

      • 构造函数执行流程:
        1. 立刻创建一个新的对象
        2. 将新建的对象设置为函数中的this, 在构造函数中可以使用this来引用新建的对象
        3. 逐行执行函数中的代码
        4. 将新建的对象作为返回值
        • 使用同一个构造函数创建的对象, 我们称之为一类对象, 也将一个构造函数称为一个类

        • 我们将通过一个构造函数创建的对象, 称为是该类的实例

          this的情况:

          1. 当以函数的形式调用时, this是window
          2. 当以方法的试试调用时, 谁调用方法this就是谁
          3. 当以构造函数的形式调用时, this就是新创建的那个对象
        
      function Person(){
      
      }
      
      var per = new Person();
      console.log(per);
      
      function Dog(){
      
      }
      dog = new Dog();
      /*使用instanceof可以检查一个对象是否是一个类的实例
      语法: 对象 instanceof 构造函数
      如果是, 则返回true, 否则返回false
      */
      
      
      • 所有的对象都是Object的后代
      • 所以任何对象和Object做instanceof检查时都会返回true
    • 构造函数修改

      创建一个Person构造函数

      • 在person构造函数中, 为每一个对象都添加了一个sayName
        • 目前我们的方法是在构造函数内部创建的,

          ​ 也就是构造函数每执行一次就会创建一个新sayName方法

        • 也就是所有实例的sayName都是唯一的.

        • 这样就导致了构造函数执行一次就会创建一个新的方法, 执行10000次就会创建10000个新的方法,而一万个方法都是一模一样的

          这是完全没有必要的, 完全可以使所有对象共享一个方法

          function Person(name, age, gender){
              this.name = name;
              this.age = age;
              this.gerder = gerder;
              //向对象
          }
          
          //将sayName方法在全局作用域中定义
          /*将函数定义在全局作用域, 污染了全局作用域的命名空间
              而且定义在全局作用域中也很不安全
          */
          function fun(){
              alert("Hello大家好, 我是:"+ this.name);
          };
          
          //创建一个Person的实例
          var = new Person("孙悟空", 18, "男");
          

  • 原型对象

    原型 prototype

    • 我们所创建的每一个函数, 解析器都会向函数中添加一个属性prototype

    • 这个属性对应着一个对象, 这个对象就是所谓的原型对象

    • 如果函数作为普通函数调用prototype没有任何作用

    • 当函数以构造函数调用时, 它所创建的对象中都会有一个隐含的属性, 指向该构造函数的原型对象, 我们可以通过_proto___来访问该属性

    • 原型对象就相当于一个公共的区域, 所有同一个类的实例都可以访问到这个原型对象

      • 我们可以将对象中共有的内容, 统一设置到原型对象中
    • 当我们访问对象的一个属性或方法时, 它会先在自身中寻找, 如果有则直接使用,

      ​ 如果没有则会去原型对象中寻找, 如果找到则直接使用

    function Person(){}
    
    //向Person的原型中添加属性a
    
    Person.prototype.a = 123;
    //向Person的原型中添加一个方法
    MyClass.prototype.sayHello = function(){
        alert("hello");
    }
    
    var per = new Person();
    
    console.log(Person.prototype);
    
    //使用in检查对象中是否含有某个属性时, 如果对象中没有但是原型中有也会返回true
    console.log("name" in mc);//true
    
    //可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性
    //使用该方法只有当对象自身中含有属性时, 才会返回true
    mc.hasOwnProperty("name");//false
    
  • 原型对象也是对象, 所以它也有原型.

    ​ 当我们使用一个对象的属性或方法是, 会先在自身中寻找,

      - 自身中如果有, 则直接使用,
      - 如果没有则去原型对象中寻找, 如果原型对象中有, 则使用
      - 如果没有则去原型对象的原型中寻找, 直到找到Object对象的原型,
      - Object对象的原型没有原型, 如果在Object中依然没有找到,则返回undefined
    
    console.log(mc.__proto__.proto__.hasOwnProperty());//true
    

debug

this

解析器在调用函数每次都会向函数内部传递进一个隐含的参数

这个隐含的参数就是this, this指向的是一个对象,

这个对象我们称为函数执行的上下文对象

  • 根据函数的调用方式的不同, this会指向不同的对象

    ​ 1. 以函数的形式调用时, this永远都是widow

      2. 以方法的形式调用时, this就是调用方法的那个对象
      3.//在事件的响应函数中, 响应函数是给谁绑定的this就是谁
    
  • for循环会在页面加载完成之后立即执行
    • 而响应函数会在超链接被点击时才执行
    • 点响应函数执行时, for循环早已执行完毕

toString()

当我们直接在页面中打印一个对象时, 实际上是输出对象的toSring() 方法的返回值

如果我们希望在输出对象时不输出[object object], 可以为对象添加一个toString()方法

per.toSring = function(){
    return "我是一个快乐的小Person"
};

垃圾回收(GC)

  • 就像人生活的时间长了会产生垃圾一样, 程序运行过程中也会产生垃圾

    这些垃圾积攒过多以后, 会导致程序运行的速度过慢,

    所以我们需要一个垃圾回收的机制, 来处理程序运行过程中产生的垃圾

  • 当一个对象没有任何的变量或属性对它进行引用, 此时我们将永远无法操作该对象,

    此时这种对象就是一个垃圾, 这种对象过多会占用大量的内存空间, 导致程序运行空间过慢

    所以这种垃圾必须进行清理

  • 在JS中拥有自动的垃圾回收机制, 会自动将这些垃圾对象从内存中销毁

    我们不需要也不能进行垃圾回收的操作

  • 我们需要做的只是要将不再使用的对象设置为null即可

数组

数组简介

内建对象

宿主对象

自定义对象

数组 (Array)

  • 数组也是一个对象

  • 它和我们普通对象的功能类似, 也是用来存储一些值的

  • 不同的是普通对象是使用字符串作为属性名的,

    ​ 而数组是使用数字来作为索引操作元素

  • 索引:

    从0开始的整数就是索引

  • 数组的存储性能比普通对象要好, 在开发中我们经常使用数组来存储一些数据

//创建数组对象
var arr = new Array();
//使用typeof检查一个数组时, 会返回object
console.log(typeof arr);//object
/*
    向数组中添加元素
    语法: 数组[索引] = 值
*/

/*
    读取数组中的元素
    语法: 数组[索引]
*/

/*
    获取数组的长度
    可以使用length属性来获取数组的长度(元素的个数)
    语法: 数组.length
    
    对于连续的数组, 是用length可以获取到数组的长度(元素的个数)
    对于非连续的数组, 使用length会获取到数组的最大索引+1
    尽量不要创建非连续的数组
*/
//修改length
//如果修改的length大于原长度, 则多出的部分会空出来
//如果修改的length小于原长度, 则多出的元素会被删除
arr.length = 10;

//向数组的最后一个位置添加元素
arr[arr.length] = 70;

//使用字面量来创建数组
var arr = [];

//使用字面量创建数组时, 可以在创建时就指定数组中的元素
var arr = [1, 2, 3];

//创建一个数数组中只有一个元素10
var arr[10];
//创建一个长度为10的数组
arr2 = new Array(10);
//数组中的元素可以是任意数据类型
//也可以是对象
//也可以是一个函数
arr[0]();
//数组中也可以放数组, 如下这种数组我们称为二维数组
arr = [[], [], []];

数组的四个方法

  1. push()
  • 该方法可以向数组的末尾添加一个或多个元素, 并返回数组的新长度
  • 可以将要添加的元素作为方法的参数传递 var arr = []; ​ 这样这些元素将会自动添加到数组的末尾
  • 该方法会将数组新的长度作为返回值返回 2. pop()
    • 该方法可以删除数组的最后一个元素, 并将删除的元素作为返回值返回
  1. unshift()
    • 向数组的开头添加一个或多个元素, 并返回新数组的长度
    • 向前边插入元素以后, 其他的元素索引会依次调整
  2. shift()
    • 可以删除数组的第一个元素, 并将被删除的元素作为返回值
  3. slice()
    • 可以用来从数组中提取指定的元素
    • 该方法不会改变元素组, 而是将截取到的元素封装到一个新数组中返回
    • 参数:
         1. 截取开始位置的索引, 包含开启索引
             2. 截取结束位置的索引, 不包含结束索引
        - 第二个参数可以省略不写, 此时会截取从开始索引往后的所有元素
      
      • 索引可以传递一个负值
        -1倒数第一个
        -2倒数第二个
        
  4. splice()
    • 可以用于删除数组中指定的元素

    • 使用splice()会影响到原数组, 会将指定元素从原数组中删除, 并将被删除的元素作为返回值返回

    • 参数:

      ​ 第一个, 表示开始位置的索引

      ​ 第二个, 表示删除的数量

      ​ 第三个及以后...

      ​ 可以传递一些新的元素, 这些元素会自动插入到开始位置索引前边

      arr.splice(0, 2);

  5. concat()可以连接两个或多个数组, 并将新的数组返回
    • 该方法不会对原数组产生影响

      arr.concat(arr2);

  6. join()
    • 该方法可以将数组转换为一个字符串
    • 该方法不会对原数组产生影响, 而是将转换后的字符串作为结果返回
    • 在join()中可以指定一个字符串作为参数, 这个字符串将会成为数组中元素的连接符

      如果不指定连接符, 则默认使用逗号作为连接符

      result = arr.join("-")

  7. reverse()
    • 该方法用来翻转数组(前边的去后边, 后边的去前边)
    • 该方法会直接修改原数组
  8. sort()
  • 可以用来对数组进行排序
  • 也会影响原数组, 默认会按照Unicode编码进行排序
    arr = ["b", "d", "e", "a", "c"];
    arr.sort();//a,b,c,d,e
    
  • 即使对于纯数字数组, 使用sort()排序时, 也会按照Unicode编码来排序, 所以对数字进行排序时, 可能会得到错误的结果
    • 我们可以自己来指定排序的规则

      我们可以字sort()添加一个回调函数, 来指定排序规则,

      ​ 回调函数中需要定义两个形参,

      ​ 浏览器会分别使用数组中的元素作为实参去调用回调函数

      • 浏览器会根据回调函数的返回值来决定元素的顺序

        ​ 如果返回一个大于0的值, 则元素会交换位置

        ​ 如果返回一个小于0的值, 则元素位置不变

        ​ 如果返回一个0, 则认为两个元素相等, 也不交换位置

      • 如果需要升序排列, 则返回a-b

        ​ 如果需要降序排列, 则返回b-a

        > ```js
        > arr = [5, 4];
        > arr.sort(function(a, b){
        >  //前边的大
        >     if(a > b){
        >         return 1;
        >     }else if(a < b){
        >         return -1;
        >     }else{
        >         return 0;
        >     }
        > });
        > a-b//升序
        > b-a//降序
        > ```
        

数组的遍历

  • 所谓的遍历数组, 就是将数组中所有的元素都取出来

forEach

一般我们都是使用for循环去遍历数组, JS中还为我们提供了一种, 方法用来遍历数组

forEach()

  • 这个方法只支持IE8以上的浏览器
  • forEach()方法需要一个函数作为参数
  • 这个方法只支持IE8以上的浏览器

    IE8及以下的浏览器均不支持该方法, 所以如果需要兼容IE8则不要使用forEach

    还是使用for循环来遍历

    • 像这种函数, 由我们创建但是不由我们调用的, 我们称为回调函数
    • 数组中有几个元素函数就会执行几次, 每次执行时, 浏览器会将遍历到的元素以实参的形式传递进来, 我们可以来定义形参, 来读取这些内容
    • 浏览器会在回调哈数中传递三个参数:
      1. 第一个参数当前正在遍历的元素
      2. 第二个参数就是当前正在遍历的元素的索引
      3. 第三个参数, 就是正在遍历的数组
        arr.forEach(function fun(value, index, obj){
          console.log("a = "+a);
        });
        

call和apply

  • 这两个方法都是函数对象的方法, 需要通过函数对象来调用

  • 当对函数调用call()和apply()都会调用函数执行

  • 在调用call和apply()可以将一个对象指定为第一个参数

    ​ 此时这个对象将会成为函数执行时的this

  • call()方法可以将实参在对象之后依次传递

  • apply()方法需要将实参封装到一个数组中统一传递

  • this的情况:

    1. 以函数的形式调用时, this永远都是window
    2. 以方法的形式调用时, this是创建的那个对象
    3. 以构造函数的形式调用时, this是新创建的那个对象
    4. 使用call和apply调用时, this是指定的那个对象

      fun.apply();

      var obj = {};

      fun.call(obj);

arguments

在调用函数时, 浏览器每次都会传递进两个隐含的参数:

  1. 函数的上下文对象this
  2. 封装实参的对象arguments
    • arguments是一个类数组对象, 它也可以通过索引来操作数据, 也可以获取长度

    • 在调用函数时, 我们所传递的实参都会在arguments中保存

    • arguments.length可以用来获取实参的长度

    • 即使我们不定义形参, 也可以通过arguments来使用实参

      ​ 只不过比较麻烦

      ​ arguments[0] 表示第一个实参

      ​ arguments[1] 表示第二个实参

    • 它里边有一个属性叫做callee

      ​ 这个属性对应一个函数对象, 就是当前正在指向的函数的对象

      console.log(arguments.callee);

Date对象

  • Data对象
  • 在JS中使用Date对象来表示一个时间

    //创建一个Data对象

    //如果直接使用构造函数创建一个Date对象, 则会封装为当前代码执行的时间

    var d = new Date();

    console.log(d);//2021年8月3日21:40:51

    //创建一个指定时间的对象

    //需要在构造函数中传递一个表示时间的字符串作为参数

    var d2 = new Date("12/03/2016 11:10:30");

  • getDate()

    获取当前对象时几日

  • getDay()
    • 获取当前日期对象时周几

    • 会返回一个0-6的值

      ​ 0表示周日

      ​ 1表示周一

  • getMonth()
    • 会后去当前时间对象的月份

    • 会返回一个0-11的值

      ​ 0表示1月

      ​ 1表示2

  • getFullYear()
    • 获取当前日期对象的年份
  • get Time()
    • 获取当前日期对象的时间戳
    • 时间戳, 指的是从格林威治标准时间的1970年1月1日, 0时0分0秒, 到当前日期所花费的毫秒数(1秒 = 1000毫秒)

      var time = d2.getTime()

      console.log(time/1000/60/60/24/360);

      //利用时间戳来测试代码执行的性能

      //获取当前的时间戳

      time = Date.now();

      console.log(time);

Math

  • Math 和其他的对象不同, 它不是一个构造函数

    ​ 它属于一个工具类不用创建对象, 它里边封装了数学运算相关的属性和方法

    • 比如:

      Math.PI 表示的圆周率 console.log(Math.PI);//大写的都是常量

  • abs()可以用来计算一个数的绝对值

    console.log(Math.abs(-1));//1

  • Math.ceil()

    • 可以对一个数进行向上取整, 小数位只要有值就自动进一

      console.log(Math.ceil(1.4));//2

  • Math.floor()

    • 可以对一个数进行向下取整, 小数部分会被舍掉

      console.log(Math.floor(1.4));//1

  • Math.round()

    • 可以对一个数进行四舍五入取整
  • Math.random()

    • 可以生成一个0-1之间的随机数
    • 生成一个0-10的随机数
      for(var i=0; i<100; i++){
          console.log(
              Math.round(
                  Math.random()*10;
              );                           
          }
      
    • 生成一个x-y之间的随机数

      Math.round(math.random()*(y-x)+x)

  • max() 可以获取多个数组的最大值

  • min() 可以获取多个数中的最小值

    var max = Math.max(1, 2, 3); //3

  • Math.pow

    获取x的y次幂

    console.log(Math.pow(1, 2)); //1

  • Math.sqrt()

    • 可以对一个数进行开方运算

包装类

  • 基本数据类型

String Number Boolean Null Undefined

  • 引用数据类型

​ object

  • 在JS中为我们提供了三个包装类, 通过这三个包装类可以将基本数据类型的数据转换为对象
    1. String()
      • 可以将基本数据类型字符串转换为String对象
    2. Number()
      • 可以将基本数据类型的数字转换为Number对象
    3. Boolean()
      • 可以将基本数据类型的布尔转换为Boolean对象
      • 但是注意, 我们在实际应用中不会使用基本数据类型的对象
      • 如果使用基本数据类型的对象, 在做一些比较时可能会带来一些不可预期的结果

        创建一个Number类型的对象

        var num = new Number(3);

        console.log(typeof num);//object

    ​ 方法和属性只能添加给对象, 不能添加给基本数据类型
          - 当我们对一些基本数据类型的值去调用属性和方法时,
          - 浏览器会临时使用包装类将其转换为对象, 然后再调用对象的属性和方法
          - 掉用完了, 再将其转换为基本数据类型
    

字符串的方法

  • 在底层字符串是以字符数组的形式保存的

    var str = "Hello";

    console.log(str[0]); //H

  • length属性
    • 可以用来获取字符串的长度
  • charAt()
    • 可以返回字符串中指定位置的字符
    • 根据索引获取指定的字符

    var result = str.charAt(0);

    console.log("result = "+ result );//H

  • charCodeAt()
    • 获取指定位置字符的字符编码(Unicode编码)
  • formCharCode()
    • 可以根据字符编码去获取字符

      re = String.formCharCode(72);

      console.log(re);//H

  • concat()
    • 可以用来连接两个后多个字符串
    • 作用和加号一样

      result = str.concat("你好");

      console.log(rsult);//Hello你好

  • indexof()
    • 该方法可以检索一个字符串中是否含有指定内容
    • 如果字符串中含有该内容, 则会返回其第一次出现的索引
      • 如果没有找到指定的内容, 则会返回-1
    • 可以指定一个第二个参数, 指定开始查找的位置

      result = str.indexOf("H");

      console.log(result);//0

  • lastIndexOf();
    • 该方法的用法和indexOf()一样

      不同的是indexOf是从前往后找

      而lastIndexOf是从后往前找

  • slice()
    • 可以从字符串中截取指定的内容
    • 不会影响原字符串, 而是将截取到的内容返回
    • 参数:

      第一个, 开始位置的索引 (包括开始位置)

      第二个, 结束位置的索引 (不包括结束位置)

      • 如果省略第二个参数, 则会截取到后边所有的
      • 也可以传递一个负数作为参数, 负数的话将会从后边计算

        str = "abc";

        str.slice(0, 1);//a

    • substring()
      • 可以用来截取一个字符串, 与slice()类似
      • 参数:
        • 第一个, 开始位置的索引 (包括开始位置)
        • 第二个, 结束位置的索引 (不包括结束位置)
        • 不同的是这个方法不能接收负值作为参数
          • 如果传递了一个负值, 则默认使用0
        • 而且他还自动调整参数的位置, 如果第二个参数小于第一个, 则自动交换
    • substr()
      • 用来截取字符
      • 参数:
          1. 截取开始位置的索引
          2. 截取的长度(个数)
        

        str = "abc";

        re = str.substr(0, 2);

        console.log(re);//ab

    • split()
      • 可以将一个字符串拆分为一个数组
      • 参数:
        • 需要一个字符串作为参数, 将会根据该字符串去拆分数组
        • 如果传递一个空串作为参数则会将每个字符都拆分为数组中的一个元素

          str = "abc";

          str.split("");//[a, b, c]

    • toUpperCase()
      • 将一个字符串转换为大写并返回

        result = str.toUpperCase();

        console.log(result);//ABC

    • toLowerCase()
      • 将一个字符串转换为小写并返回

正则表达式

  • 正则表达式简介
  • 正则表达式用于定义一些字符串的规则
    • 计算机可以根据一个正则表达式, 来检查一个字符是否符合规则

    • 或则将字符串中符合规则的内容提取出来

    • 语法:

      var 变量 = new RegExp("正则表达式", "匹配模式");

      使用typeof检查正则对象, 会返回Object

      var reg = new RegExp("a"); 这个正则表达式可以来检查一个字符串中是否含有a

      • 在构造函数中可以传递一个匹配模式作为第二个参数, 可以是
        • i 忽略大小写
        • g 全局匹配模式 //创建正则表达式的对象

      var reg = new RegExp();

    • 正则表达式的方法:

      test()

      • 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则
        • 如果符合则会返回true, 否则返回false
  • 使用字面量来创建正则表达式
    • 语法: var 变量 = /正则表达式/匹配模式
    • 使用字面量的方式创建更加简单
    • 使用构造函数创建更加灵活

      //创建一个正则表达式, 检查一个字符串中是否有a或b

      • 使用 | 表示或者的意思

        reg = /a|b/;

    • 创建一个正则表达式检查一个字符中是否有字母
      • 中括号里面的内容也是或的关系

      • [ab] == a|b;

      • [a-z] 任意小写字母

      • [A-Z] 任意大写字母

      • [A-z] 任意字母

        //检查一个字符串中农是否含有abc或adc或aec

        reg = /abc|adc|aec/;== /a[ade]c/

        console.log(reg.test("aec"));

    • [^ ] 除了
      reg = /[^ab]/;
      

      console.log(reg.test("ab"));//false

  • 字符串和正则相关的方法
  • split()
    • 可以将一个字符串拆分为一个数组
    • 方法中可以传递一个正则表达式作为参数, 这样方法将会根据正则表达式去拆分字符串
    • 这个方法即使不指定全局匹配, 也会全都拆分

      根据任意字母来将字符串拆分

      var result = str.split(/[A-z]/);

  • search()
    • 可以搜索字符串中是否含有指定内容
    • 如果搜索到指定内容, 则会返回第一次出现的索引, 如果没有则会返回-1
    • 它可以接受一个正则表达式作为参数, 然后会根据正则表达式去检索字符
    • serach()只会查找第一个, 即使设置全局匹配也没用

      //搜索字符串中是否含有abc 或aec 或afc

      result = str.search(/a[bef]c/);

  • match()
    • 可以根据正则表达式, 从一个字符串中将符合条件的内容提取出来
    • 默认情况下我们的match只会找到第一个符合要求的内容, 找到之后就停止检索, 我们可以设置正则表达式为全局匹配模式, 这样就会匹配到所有的内容
    • 可以为一个正则表达式设置多个匹配模式, 且顺序无所谓
    • match()会将匹配到的内容封装到一个数组中返回, 即使只查询到一个结果

      result = str.match(/[A-z]/g);//a, b, c

  • replace()
    • 可以将字符串中指定的内容替换为新的内容
    • 默认只会替换第一个
    • 参数:
      1. 被替换的内容, 可以接受一个正则表达式作为参数

      2. 新的内容

        result = str.replace(/a/ig, "b");

正则表达式语法

量词

  • 通过量词可以设置一个内容出现的次数
  • 量词只对它前边的一个内容起作用
  • {n} 正好出现n次
  • {m, n} 出现m-n次
  • {m, } m次以上
  • +至少一个, 相当于{1, }
  • *0个或多个, 相当于{0, }
  • ?0个或1个, 相当于{0, 1}

var reg = /a{3}/;

var reg = /a{3}b{3}/;

//出现一到三次

reg = /ab{1, 3}c/;

//至少一个

reg = /ab+c/;

  • 检查一个字符串是否以a开头
    • ^ 表示开头
    • $ 表示结尾

      reg = /^a/;//匹配开头的a

      reg = /a$/;//匹配结尾的a

  • 如果在正则表达式中同时使用^ $则要求字符串必须玩去符合正则表达式的要求

    reg = /^a$/;

    console.log(reg.test("aaa"));//false

    //以a开头或者以a结尾

    reg = /^a|a$/;

  • 检查一个字符串中是否含有点.
    • . 表示任意字符
    • 在正则表达式中使用\作为转义字符
    • . 表示.
      \\表示\
      
    • 注意: 使用构造函数时, 由于它的参数是一个字符串, 而\是字符串中的转义字符
    • 如果要使用\则需要使用\来代替

\w

  • 任意字母, 数字, _ 相当于 [A-z0-9_]

\W

  • 除了字母, 数字, _ [^A-z0-9_]

\d

  • 任意的数字

\D

  • 除了数字

\s

  • 空格

\S

  • 除了空格

\b

  • 单词边界

    reg = /\bchild\b/

\B

  • 除了单词边界

reg = /\w/;

  • 去除掉字符串中前后的空格

  • /\s*|\s*$/g 匹配开头和结尾的空格

    str = " hello ";

    str = str.replace(/\s*|\s*$/g, "");

DOM

DOM简介

  • 浏览器已经为我们提供文档节点 对象这个对象是window属性
  • 可以在页面中直接使用, 文档节点代表的是整个网页

    //获取到button对象

    var btn = document.getElementById("btn");

    //修改按钮的文字

    btn.innerHTML = "nihO";

  • 事件
    • 事件, 就是文档或浏览器窗口中发生的一些特定的交互瞬间.
    • javaScript与HTML之间的交互是通过事件实现的
    • 对于Web应用来说, 有下面这鞋代表性事件: 点击某个元素, 将鼠标移动至某个元素上方, 按下键盘上某个键,等等
    • 事件, 就是用户和浏览器之间的交互行为
    • 我们可以在事件对于的属性中设置一些js代码
      • 这样当事件被触发时, 这些代码将会执行
      • 这种写法我们称为叫做结构和行为耦合, 不方便维护,
      • 不推荐使用
    • 可以为按钮的对应事件绑定处理函数的形式来响应事件
      • 这样当事件被触发时, 其中对应的哈数将会被调用

        //获取对象

        var btn = document.getElementById("btn");

        btn.onclick = function(){

        };

  • 文档的加载
    • 浏览器在加载一个页面时, 是按照自上向下的顺序加载的
    • 读取到一行就运行一行, 如果将script标签写到页面的上边,
    • 在代码执行时, 页面还没有加载, 页面没有加载DOM对象也没有加载
      • 会导致无法获取到DOM对象
    • 将js代码编写到页面的下部就是为了, 可以在页面加载完毕以后再执行js代码
    • onload事件会在整个页面加载完成之后才触发
      • 该事件对应的响应函数将会在页面加载完成之后执行
      • 这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了

        为window绑定一个onlaoad事件

        window.onload = function(){

        }

  • dom查询
    • 获取元素节点

      • 通过document对象调用
        1. getElementById()
          • 通过id属性获取一个元素节点对象
        2. getElementsByTagName()
          • 通过标签名获取一组元素节点对象
        3. getElementsByName
          • 通过name属性获取一组元素节点对象
    • innerHTML用于获取元素内部的HTML代码
      • 对于自结束, 标签这个属性没有意义
    • innerText
      • 该属性可以获取到元素内部的文本内容
      • 它和innerHTML类似, 不同的是它会自动将html去除
    • 如果需要读取元素节点属性
      • 直接使用元素.属性名
        • 例子: 元素.id 元素.name 元素.value
        • 注意: class属性不能采用这种方式.
          • 读取class属性时需要使用 元素.className

    - 获取元素节点的子节点

    • 通过具体的元素节点调用
      1. getElementsByTagName()
        • 方法, 返回当前节点的指定标签后代节点
      2. childNodes
        • 属性, 表示当前节点的所有子节点
        • childNodes属性会获取包括文本节点在内的所有节点
        • 根据DOM标签空白也会当成文本节点
        • 注意: 在IE8及以下的浏览器中, 不会将空白文本当撑字节点
      3. firstChild
        • 属性, 表示当前节点的第一个子节点(包括空白文本)
      4. lastChild
        • 属性, 表示当前节点的最后一个子节点
      5. children
        • 属性可以可以获取当前元素的所有子元素
      6. firstElementChild
        • 获取当前元素的第一个子元素
        • 支持IE8及以下的浏览器
        • 如果需要兼容他们尽量不要使用
  • 获取父节点和兄弟节点

  • 通过节点的调用
    1. parentNode
      • 属性, 表示当前节点的父节点
    2. previousSibling
      • 属性, 表示当前节点的前一个兄弟节点(也可能获取到空白的文本)
    3. nexrSibling
      • 属性, 表示当前节点的后一个兄弟节点
  • dom查询的剩余方法
    • 获取body标签

      var body = document.getElementsByTagName("body")[0];

    • 在document中有一个属性body, 它保存的是body的引用

      var body = document.body;

    • document.documentElement保存的是html根标签
    • document.all 表示页面中的所有元素
    • 根据class属性值查询一组元素节点对象
      • document.getElementByClassName()可以根据class属性值获取一组元素节点对象
      • 但是该方法不支持IE8及以下的浏览器

        var box1 = document.getElementByClassName("box1");

    • document.querySelector()
      • 需要一个选择器的字符串作为参数, 可以根据一个CSS选择器来查询一个元素节点对象
      • 虽然IE8中没有getElementByClassName()但是可以用document.querySelector()来代替
      • 使用该方法总会返回唯一的一个元素, 如果满足条件的元素有多个, 那么它只会返回第一个

        document.querySelector(".box, div");

    • document.querySelectorAll()
      • 该方法和document.querySelector()用法类似, 不同的是它会将符合条件的元素封装到一个数组中返回
      • 即使符合条件的元素只有一个, 它也会返回数组

dom增删改

  • document.createElement()
    • 可以用于创建一个元素节点对象
    • 它需要一个标签名作为参数, 将会根据改标签名创建元素节点对象.
    • 并将创建好的对象作为返回值

      var li = document.createElement("li");

  • document.createTextNode()
    • 可以用来创建一个文本节点对象
    • 需要一个文本内容作为参数, 将会根据该内容创建文本节点, 并将新的节点返回

      var text = document.createTextNode("广州");

  • appendChild()
    • 向一个父节点中添加一个新的子节点
    • 用法: 父节点.appendChild(子节点);
  • insertBefore()
    • 可以在指定的子节点前插入新的子节点
    • 语法:
      • 父节点.insertBefore(新节点, 旧节点);
  • replaceChild()
    • 可以使用指定的子节点替换已有的子节点
    • 语法: 父节点.replaceChild(新节点, 旧节点);
  • removeChild()
    • 可以删除一个子节点
    • 语法: 父节点.removeChild(子节点);

      city.removeChild(bj);

  • 使用innerHTML也可以完成DOM的增删改的相关操作
  • 一般我们会两种方式结合使用

- 使用dom操作css

  • 通过JS修改元素的样式

    语法: 元素.style样式名 = 样式值

    box1.style.width = "100px";

  • 注意: 如果CSS的样式名中含有-,

    这种名称再JS中是不合法的比如background-color

    需要将这种样式名修改为驼峰命名法

    去掉-, 然后将-后的字母大写 如: backgroundColor

  • 我们通过style属性设置的样式都是内联样式
    • 而内联样式有较高的优先级, 所以通过JS修改的样式往往会立即显示
    • 但是如果在样式中写了!important, 则此时样式会有最高的优先级
      • 即使通过JS也不能覆盖该样式此时将会导致JS样式修改失败, 所以尽量不要为样式添加!important
  • 读取box1的样式
    • 语法: 元素.style.样式名
    • 通过style属性设置和读取的都是内联样式
    • 无法读取样式表中的样式
  • 获取元素当前显示的样式
    • 语法: 元素.currentStyle.样式名

    • 它可以用来读取当前元素正在显示的样式

      alert(box1.currentStyle.width);

    • 如果当前元素没有设置该样式, 则获取它的默认值

      currentStyle只有IE浏览器支持, 其他的浏览器都不支持

  • 在其他的浏览器中可以使用
    • getComputedStyle()这个方法来获取当前元素的样式
    • 这个方法是window的方法, 可以直接 使用
    • 需要两个参数
      • 第一个: 要获取的样式
      • 第二个: 可以传递一个伪元素, 一般都传null

        getComputedStyle(box1, null);

    • 该方法会返回一个对象, 对象中封装了当前元素对应的样式
      • 可以通过对象.样式名来读取样式
      • 如果获取的样式没有设置, 则会获取到真实的值,而不是默认的值
      • 比如: 没有设置width, 它不会获取到auto, 而是一个长度
      • 但是该方法不支持IE8及以下的浏览器
      • 通过currentStyle和getComputedStyle()获取到的样式都是只读的

其他样式的相关属性

  1. clientWidth
  2. clientHeight
    • 这两个属性可以获取元素的可见宽度和高度
    • 这些属性都是不带px的, 返回的都是一个数字 可以直接进行计算
    • 会获取元素的高度和宽度, 包括内容区和内边距
    • 这些属性都是只读的, 不能修改
  3. offsetWidth
  4. offsetHeight
    • 获取元素的整个的宽度和高度, 包括内容区, 内边距和边框
  5. offsetParent
    • 可以用来获取当前元素的定位父元素
    • 会获取到离当前元素最近的开启了定位的祖先元素
    • 如果所有的祖先元素都没有开启定位则返回body
  6. offsetLeft
    • 当前元素相对于其定位元素的水平偏移量
  7. offsetTop
    • 当前元素相对于其定位元素的垂直偏移量
  8. scrollWidth
  9. scrollHeight
    • 可以获取元素整个滚动区域的高度
  10. scrollLeft
    • 可以获取水平滚动条滚动的距离
  11. scrollTop
    • 可以获取垂直滚动条滚动的距离
  • 获取滚动条滚动的距离
    • chrome认为浏览器的滚动条是body的, 可以通过body.scrollTop来获取
    • 火狐等浏览器认为浏览器的滚动条是html的

      //兼容的写法

      var st = document.body.scrollTop || document.documentElement.scrollTop;

      ​ var sl = document.body.scrollLeft || document.documentElement.scrollLeft;

  • 当满足scrollHeight - scrollTop == clientHeight;
  • 说明垂直滚动条滚动到底了
  • 当满足scrollWidth - scrollLeft == clientWidth;
  • 说明水平滚动条滚动到底了
  1. onscroll
    • 该事件会在元素的滚动条滚动时触发
  2. disabled属性可以设置一个元素是否禁用
    • 如果设置为true, 则元素禁用
    • 如果设置为false, 则元素可用

事件对象

  • 当事件的响应函数被触发时, 浏览器每次都会将一个事件对象作为实参传递进响应函数
    • 在事件对象中封装了当前事件相关的一切信息, 比如: 鼠标的坐标, 键盘哪个按键被按下, 鼠标滚轮滚动的方向
    • 在IE8中, 响应函数被触发时, 浏览器不会传递事件对象
      • 在IE8及以下的浏览器中, 是将事件对象作为window对象的属性保存的
        //处理兼容性问题
        if(!event){
           event = window.event;
        }
        //第二种
        event = event || window.event;
        
  1. onmousemove
    • 该事件将会在鼠标在元素中移动时被触发
  2. clientX可以获取鼠标指针的水平坐标
  3. clientY可以获取鼠标指针的垂直坐标
    • clientX和clientY
      • 用于获取鼠标在当前的可见窗口的坐标
      • div的偏移量, 是相对于整个页面的
  4. pageX和pageY可以获取鼠标相对于当前页面的坐标
    • 但是这两个属性在IE8中不支持, 所以如果需要兼容IE8, 则不要使用
  5. target
    • event中的target表示的触发事件的对象
  • 拖拽box1

    ​ - 拖拽的流程

​ 6. 当鼠标在被拖拽的元素上按下时, 开始拖拽onmousedown

​ 7. 当鼠标移动时被拖拽元素跟随鼠标移动onmousemove

  1. 当鼠标松开时, 被拖拽元素固定在当前位置onmouseup

事件的冒泡(bubble)

  • 所谓的事件冒泡就是事件的向上传导, 当后代元素上的事件被触发时, 其祖先元素上的相同事件也会被触发
  • 在开发中大部分情况冒泡都是有用的, 如果不希望发生事件冒泡可以通过事件对象来取消冒泡

    //取消冒泡

    //可以将事件对象的cancelBubble设置为true, 即可取消冒泡

    event.cancelBubble = true;

  • 事件的委派
    • 指将事件统一绑定给元素的共同的祖先元素, 这样当后代元素, 上的事件触发时, 会一直冒泡到祖先元素
    • 我们希望只绑定一次事件, 即可应用到多个元素上 ,即使元素是后添加的
    • 我们可以尝试将其绑定给元素的共同的祖先元素
  • 事件的绑定
    • 使用 对象.事件 = 函数 的形式绑定响应函数
    • 它只能同时为一个元素的一个事件绑定一个响应函数
    • 不能绑定多个, 如果绑定了多个, 则后边会覆盖掉前边的
  • addEventListener()
    • 通过这个方法也可以为元素绑定响应函数
    • 参数:
      1. 事件的字符串, 不要on
      2. 回调函数, 当事件触发时, 该函数会被调用
      3. 是否在捕获阶段触发事件, 需要一个布尔值, 一般都传false

        btn01.addEventListenner("click", function(){}, false);

    • 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数
    • 这样当事件被触发时, 响应函数, 将会按照函数的绑定顺序执行
    • 这个方法不支持IE8及以下的浏览器
  • attachEvent()
    • 在IE8中可以使用attachEvent()来绑定事件
    • 这个方法也可以同时为一个事件绑定多个处理函数
      • 不同的是他是后绑定先执行, 执行顺序和addEventListener()
    • 参数:
      1. 事件的字符串, 要on
      2. 回调函数
  • 定义一个函数, 用来为指定的元素绑定响应函数
    //addEventListener()中的this, 是绑定事件的对象
    //attachEvent()中的this, 是window
    //需要统一两个方法this
    /*
    参数:
        obj 要绑定事件的对象
        eventStr 事件的字符串(不要on)
        callback 回调函数
    
    */
    function bind(obj, eventStr, callback){
        
        if(obj.addEventListener){
            //大部分浏览器兼容的方式
            obj.addEventListener(eventstr,         callback, false);
        }else{
           //this是由谁调用方式决定
            //callback.call(obj)
            
            //IE8及以下
            
            obj.attachEvent(eventStr,             function(){
                //在匿名函数中掉用回调函数
                callback.call(obj);
            });
        }
        
    }
    
    
  • 事件的传播
    • 关于事件的传播网景公司和微软公司有不同的理解
    • 微软公司认为事件应该是由内向外传播, 也就是当事件触发时, 应该先触发当前元素上的事件, 然后再向当前元素的祖先元素上传播, 也就是说事件应该在冒泡阶段执行
    • 网景公司认为事件应该是由外向内传播的, 也就是当事件触发时, 应该先触发当前元素的最外层的祖先元素的事件, 然后再向内传播给后代元素
    • W3C综合了两个公司的方案, 将传播分成了三个阶段
      1. 捕获阶段
        • 在捕获阶段时从最外层的祖先元素, 向目标元素进行事件的捕获, 但是默认此时不会触发事件
      2. 目标阶段
        • 事件捕获到目标, 捕获结束开始在目标元素上触发事件
      3. 冒泡阶段
        • 事件从目标元素向它的祖先元素传递,依次触发祖先元素上的事件
        • 如果希望在捕获阶段就触发事件, 可以将addEventListener()的第三个参数设置为true
          • 一般情况下我们不会希望在捕获阶段触发事件, 所以这个参数一般都是false
        • IE8及以下的浏览器中没有捕获阶段
  • 拖拽

    • 当我们拖拽一个网页中的内容时, 浏览器会默认去搜索引擎中搜索内容,
    • 此时会导致拖拽功能的异常, 这个是浏览器提供的默认行为
    • 但是这招对IE8不起作用
    • IE: 当调用元素的setCapure()方法以后, 这个元素将会把下一次所有的鼠标按下相关的事件捕获到自身上
    • releaseCapture()取消捕获
    • setCapture()
      • 只有IE支持, 但是在火狐中调用不会报错

滚轮的事件

  1. event.wheelDelta
    • event.wheelDelta 可以获取鼠标滚轮滚动的方向
    ​ - 向上滚是120向下滚是-120
  • wheelDelta这个值我们不看大小, 只看正负
  • wheelDelta这个属性火狐中不支持
  • 火狐中使用event.detail来获取滚动的方向
  • 向上滚是-3 向下滚是3

onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发

​ * 但是火狐不支持该属性

​ *

​ * 在火狐中需要使用DOMMouseScroll来绑定滚动事件

  • 当滚轮滚动时, 如果浏览器有滚动条, 滚动条会随之滚动
  • 这是浏览器的默认行为, 如果不希望发生, 则可以取消默认行为 return false;
  • 使用addEventListener()方法绑定响应函数, 取消默认行为时不能使用return false
    • 需要使用event.prevetDefault();
    • 但是IE8不支持event.preventDefault();这个玩意, 如果直接调用会报错

键盘事件

  1. onkeydown
    • 键盘被按下
    • 对于onkeydown来说如果一直按着某个键不松手, 则事件会一直触发
    • 当onkeydown连续触发时, 第一次和第二次之间的间隔会稍微长一点其他的会非常快
      • 这种设计是为了防止误操作的发生
    • 在文本框中输入内容, 属于onkeydown的默认行为
    • 如果在onkeydown中取消了默认行为, 则输入的内容不会出现在文本框中
  2. onkeyup
    • 键盘被松开
  • 键盘事件一般都会绑定给一些可以获取到焦点的对象, 或者是document
  1. keyCode
    • 可以通过keyCode来获取按键的编码
    • 通过它可以判断那个按键被按下
    • 除了keyCode, 事件对象中还提供了几个属性
    • altKey
    • ctrlKey
    • shiftKey
      • 这三个用来判断alt ctrl 和 shift是否被按下
      • 如果按下则返回true, 否则返回false
    • 判断y和ctrl是否同时被按下
      if(event.keyCode === 89 && event.ctrlKey  === 17){
          console.log("ctrl和y都被按下了");
      }
      

BOM

  • 浏览器对象模型

  • BOM可以使我们通过JS来操作浏览器

  • 在BOM中为我们提供了一组对象, 用来完成对浏览器的操作

    - BOM对象

    Window

    • 代表的是整个浏览器的窗口, 同时window也是网页中的全局对象

      Navigator

    • 代表当前浏览器的信息, 通过该对象可以来识别不同的浏览器

    • navigator.appName返回浏览器名称

    • 由于历史原因, Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了

    • 一般我们只会使用userAgent来判断浏览器的信息

    • 不同的浏览器会有不同的userAgent

    • 谷歌浏览器的userAgent

      Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36

      • 在IE11中已经将微软和IE相关的标识都去除了, 所以我们基本已经不能通过UserAgent来识别一个浏览器是否是IE了
      • 如果通过UserAgent不能判断, 还可以通过一些浏览器中特有的对象, 来判断浏览器中信息
        • 比如ActiveXObject

          alert(window.ActiveXObject);//这个方法被IE发现了

          alert("ActiveXObject" in window);//所以用这个方法来抓IE

      Location

    • 代表当前的浏览器的地址栏信息, 通过Location可以获取地址栏信息, 或者操作浏览器切换页面

      //如果直接打印location, 则可以获取到地址栏的信息, (当前页面完整的路径)

      alert(location);

      //更换路径

      //如果直接将location属性修改为一个完整的路径, 或相对路径, 则我们的页面会自动跳转到该路径, 并且会生成相应的历史记录

      location = "www.baidu.com";

    • assign()

      • 用来跳转到其他的页面, 作用和直接修改location一样

        location.assign("www.baidu.com");

    • reload()

      • 用于重新加载当前页面, 作用和刷新按钮一样
      • 如果在方法中传递一个true, 作为参数, 则会强制清空缓存刷新页面

        location.reload(true);

        //在括号中传一个true, 可以开启强制清空缓存

    • replace()

      • 可以使用一个新的页面替换当前页面, 调用完毕也会跳转页面
      • 不会生成历史记录, 不能使用回退按钮回退

      History

    • 代表浏览器的历史记录, 可以通过该对象来操作浏览器的历史记录

    • 由于隐私原因, 该对象不能获取到具体的历史记录, 只能操作浏览器向前或者向后翻页

    • 而且该操作只在当次访问时有效

    • lenght

      • 属性, 可以获取到当次访问的链接数量

        alert(history.length);

    • back()

      • 可以用来回退到上一个页面,作用和浏览器的回退按钮一样

        history.back()

    • forward()

      • 可以跳转到下一个页面, 作用和浏览器的前进按钮一样

        history.forward();

      • go()
        • 可以用来跳转到指定的页面

        • ta需要一个整数作为参数

          1: 表示向前跳转一个页面

          2: 表示向前跳转两个页面

          -1: 表示向后跳转一个页面

          -2: 表示向后跳转两个页面

      Screen

    • 代表用户的屏幕的信息, 通过该对象可以获取到用户的显示器的相关的信息

    • 这些BOM对象在浏览器中都是作为window对象的属性保存的,

      • 可以通过window对象来使用, 也可以直接使用

        console.log(window.navigator);

        console.log(navigator);

定时器简介

  • JS的程序的执行速度是非常快的
    • 如果希望一段程序, 可以每间隔一段时间执行一次, 可以使用定时调用
  • setInterval()
    • 定时调用
    • 可以将一个函数,每隔一段时间执行一次
    • 参数:
      1. 回调函数, 该函数会隔一段时间被调用一次
      2. 每次调用间隔的时间, 单位是毫秒
    • 返回值:
      • 返回一个Number类型的数据
      • 这个数字用来作为定时器的唯一标识
    • clearInterval()可以用关闭一个定时器
      • 方法中需要一个定时器的标识作为参数, 这样将关闭标识对应的定时器

      • 如果参数是一个有效的定时器的标识, 则停止对应的定时器

      • 如果参数不是一个有效的标识, 则什么也不做

          ```js
          var num = 1;
          var timer = setInterval(function(){
              count.innerHTML = num++;
          }, 1000);
        clearInterval(timer);
        
  • 延时调用
    • 延时调用一个函数不马上执行, 而是隔一段时间以后再执行, 而且只会执行一次
    • 延时调用和定时调用的区别, 定时调用会执行多次, 而延时调用只会执行一次
    • 延时调用和定时调用实际上是可以互相代替的, 在开发中可以根据自己的需要去选择
      var num = 1;
      setTimeout(function(){
          console.log(num++);
      }, 3000)
      
      //使用clearTimeout()来关闭一个延时调用
      clearTimeout(timer);
      

类的操作

  • 通过style属性来修改元素的样式, 浏览器就需要重新渲染一次页面, 这样的执行性能是比较差的
  • 我希望一行代码, 可以同时修改多个样式
  • 我们可以通过修改元素的class属性来间接的修改样式
  • 这样一来, 我们只需要修改一次, 即可同时修改多个样式
    • 浏览器只需要重新渲染页面一次, 性能比较好
    • 并且这种方式, 可以使表现和欣慰进一步的分离

      box.className = "b2";

      //不覆盖前面类的方式, 前面的空格不要忘记加

      box.className += " b2";

JSON

JS中的对象只有JS自己认识, 其他的语言 JSON就是一个特殊格式的字符串, 这个字符串可以被任意的语言所识别 并且可以转换为任意语言的对象, JSON在开发中主要用来数据的交互 JSON

  • JavaScript Object Notation JS对象表示法
  • JSON和JS对象的格式一样, 只不过JSON字符串中的属性名必须加双引号, 其他的和JS语法一致
    • JSON分类
      1. 对象
      2. 数组
    • JSON中允许的值
      1. 字符串
      2. 数值
      3. 布尔值
      4. null
      5. 对象
      6. 数组

        //创建一个JSON对象

        var obj = '{"name": "孙悟空", "age": 18, "gender": "男"}';

        var arr = '[1, 2, 3, "hello", true]';

        var obj2 = '{arr}: [1, 2, 3]';

将JSON字符串转换为JS中的对象

  • 在JS中, 为我们提供了一个工具类, 就叫JSON
  • 这个队形可以帮助我们将一个JSON转换为JS对象, 也可以将一个JS对象转换为JSON

json 转 js对象

  • JSON.parse()
    • 可以将JSON字符串转换为js对象, 会将该字符串转换为JS对象并返回

      var obj1 = '{"name": "孙悟空", "age": 18, "gender": "男"}';

      var o = JSON.parse(obj1);

      console.log(o.gender);//男

js对象 转 JSON JSON.stringify()

  • 可以将一个JS对象转换为JSON字符串
  • 需要一个js对象作为参数, 会返回一个JSON字符串

    var obj2 = {name: "孙悟空", age: 18, gender: "男"};

    var str = JSON.stringify(obj2);//'{"name": "孙悟空", "age": 18, "gender": "男"}';

JSON对象在IE7及以下的浏览器中不支持, 所以在这些浏览器中调用时会报错 eval() 这个函数可以用来执行一段字符串形式的代码并将执行结果返回 如果使用eval()执行的字符串中含有{}, 它会将{}当成是代码块 如果不希望将其当成代码块解析, 则需要在字符串前后各加一个() eveal()这个函数的功能很强大, 可以执行一个字符串中的js代码,

  • 但是在开发中尽量不要使用,首先它的执行性能比较差, 然后它还具有安全隐患

如果需要兼容IE7及以下的JSON操作, 则可以通过引入一个外部的js文件来处理

dome演示

<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0,user-scalable=no,maximum-scale=1.0, minimum-scale=1.0'>
<title>Document</title>
</head>
<body>

  <!-- script标签写在最底部有利于页面的显示 -->
  <script>
    alert("helloword");
  </script>
</body>
</html>
  • 最终效果

第5天01.png

后记

  • js的使用感受: js是一门弱类型的语言不需要定义它的类型, 所以来说比较的灵活
  • 然后js自带垃圾回收器
  • js的原型是让人比较头痛的
  • js高级程序设计, jsdom艺术, js忍者秘籍, js不可不知的秘密12部, 这些书都是要看的(虽然我还没怎看)
  • 现代js教程这个网站教学口碑不错
  • 自学需要非常自律大家加油吧
  • 内容还有很多此篇讲不完的