js

JavaScript基础

document.write()

该代码用于向页面的body标签中写入内容 
注: document是“文档”的意思 代表的就是当前打开的html页面
注: . 在JS中,表示的是 “的” 的意思 
注: write 表示“写入”的意思 
总结起来就是:“向当前的文档中写入内容” 
()里面就是要写入的内容,注意使用双引号包裹

变量

简介

变量是JS中的一个“容器”。用来装载一些数据。
特点: 每当有代码使用到这个变量,就会使用这个变量容器中的数据。

定义

定义一个变量:如下定义
var a = 10;
含义: 在内存中开辟了一个空间,这个空间的名字叫做a, 并在这个空间中存放了一个内容10.

名称定义规范

1 整体由 数字、 字母、 下划线(_)、 美元符号($) 组成 
2 不可以以数字开头
3 不可以使用关键字、保留字作为变量名称
4 JS变量名称严格区分大小写(对大小写敏感)

变量的小特点

1 变量在被使用的时候是不可以加双引号的 
2 变量在被使用的时候使用的是所保存的值
3 变量只可以保存一个值
4 等号(=)不是比较的意思 是赋值的意思 把等号右边的 交给等号左边 左边通常是变量
错误示范: 1 = 1;

数据类型

数据类型指的是一门语言中对不同数据的类型划分。
JS中的数据类型一共有6种。分为两大类: 基本类型、 引用类型

基本数据类型

字符串、数字、布尔、undefined、null

引用类型(先不讲)

字符串
字符串的定义规则: 使用单引号、双引号作为字符串的开启和结束标记
注:不可以使用一个单引号加一个双引号 或者 一个双引号加一个单引号去定义字符串。这是不合法的

问题:如何在一个字符串中出现单引号或者双引号
转义 在字符串中的单引号或者双引号之前 使用\
嵌套 如果想要在字符串中出现单引号,那就使用双引号去定义字符串 反之亦然

数字
数字就是数学中的数字。
按照不同的进制:
    十进制: 10、 123、 123.333      逢10进1
    八进制: 077、 012     注:以0开头 不可以出现8和8以上的数字    逢8进1
    二进制: 0b1010101001  注:以0b开头 不可以出现2和2以上的数字   逢2进1 
    十六进制: 0xfff       注:以0x开头 单个位数的最大值为f        逢16进1
特殊的数字: 
    NaN  表示不是一个数
    Infinity 表示无穷大
布尔值
布尔数据类型只有两个值: true false
undefined
只有一个值 就是undefined
null
只有一个值 就是null

判定数据类型

方式1: typeof 值
方式2: typeof(值)

JS中的注释

单行注释: // 
多行注释: /**/

JS的书写位置

1 script标签里
2 .js文件中 通过script标签的src引入

注: 拥有src属性的script标签内的代码将不会被执行

运算符

数学运算符

+  
    含义1: 连字符 
    在表达式中具备字符串时,就会当作连字符处理 
    含义2: 数学中的加法
- 
    数学中的减法
* 
    数学中的乘法
/
    数学中的除法
%
    数学中的求模(取余)
简写形式:
    a += 10;
    a = a + 10;
    
    a -= 10;
    a = a - 10;

    a *= 10;
    a = a * 10;

    a /= 10;
    a = a / 10;

    a %= 10;
    a = a % 10;

关系运算符:

>     大于
>=    大于等于
<     小于
<=    小于等于
==    相等(只比较值 不比较数据类型)
===   全等(既比较值 也比较数据类型)
!=    不相等(只比较值 不比较数据类型)
!==   不全等(既比较值 也比较数据类型)

逻辑运算符

&& 逻辑与
|| 逻辑或
! 逻辑非
&& 两侧有假就假 都真才真
|| 两侧有真就真 都假才假
! 只能够写在某一个变量的左侧 会对它进行取反操作 最终结果为true或者false

其他知识点:

console.log() 会将内容打印在控制台中, 并显示

自增运算符 自减运算符

自增运算符: ++
自减运算符: --
含义: 让一个变量保存的数 +1 或者 -1 再赋予变量自身
可以出现的位置: 变量的前面和后面
如果出现在前面: ++变量
变量的使用会先+1 再参与运算
如果出现在后面: 变量++
变量的使用会先使用原值, 再++
    var a = 10; 
    var b = a-- + --a;
    // 代码的执行顺序
    // 1 定义一个变量a 保存10
    // 2 先执行等号右侧  a--  此时使用的值是10 a变为9   继续运算 发现 --a a又出现了 a已经是9 因为--在前面 所以先-1 变为8 再使用8 进行运算
    var b = 10 + 8
    console.log(b);

分支判定

为了让程序拥有"自主选择" 能力,我们加入了分支判定功能 可以让程序决定执行哪一段代码,不执行哪一段代码,从而实现程序结果的多样化.

if语句

语法1: 
    if (表达式) { 代码段 } else { 代码段 }
以上写法: 当表达式为真时,执行if代码段 当表达式结果为假时,执行else代码段 
语法2:
    if (表达式) {代码段}
以上写法: 当表达式为真时,执行if代码段 当表达式结果为假时,不执行任何内容
语法3:
    if (表达式1) {代码段1} else if (表达式2) {代码段2} else if (表达式3) {代码段3} ...
以上写法:
    当表达式1为真时,执行代码段1 执行完毕 跳出分支判断 
    当表达式1为假时,去判定表达式2,为真时,执行代码段2 
    当表达式2为假时,去判定表达式3,为真时,执行代码段3
    当表达式3为假时,继续往后判定 直到遇见为真的表达式 就执行对应的代码段 或者都不符合,就不会进入分支代码。
语法4:
    if (表达式1) {代码段1} else if (表达式2) {代码段2} else {代码段3}
    当表达式1为真时 执行代码段1 否则判定表达式2 为真时执行代码段2 否则 执行代码段3
注:
    整个if语句由3部分组成
        if () {}
        else if () {}
        else {}
        除了第一部分必须有之外,其余部分都可以省略。
        第三部分只能出现一次,第二部分可以出现多次。

switch语句

语法:
    switch (表达式) {
        case 结果1:
            code...
        break;
        case 结果2:
            code...
        break;
        case 结果3:
            code...
        break;
        case 结果4:
            code...
        break;
        case 结果5:
            code...
        break;
        case ……
            code...
        break;
        default:
            code...
        break;
    }
执行规则:
    当表达式的结果为对应的case结果时,执行对应的代码。
    case 后面的内容最终必须时固定的值,不可以是范围表达式。
    break的作用是停止代码,跳出switch语句。
    default的作用是当任何case都没有对应上,执行!
    在比较case的值时,使用的是全等比较
注: 如果没有break,则会出现“落空”现象。 落空现象:指的是会执行下一个case语句中的代码的现象。

三元运算符

也叫做三目运算符
指的是对if else语句的一种简化方式
语法:
    条件 ? 结果1 : 结果2
规则:
    当条件为真时,使用结果1
    否则,使用结果2

循环结构

当有大量的重复性的代码时,我们可以使用循环语句来解决。

while循环

语法:
    while (条件) {
        code...
    }
注: 一定记得在语句中改变条件表达式中的变量 否则会死循环

do while循环

语法:
    do {
        code...
    } while (条件);
注: 一定记得在语句中改变条件表达式中的变量 否则会死循环
注:无论条件是否达成,都会执行一次语句

for 循环

语法:
    for (初始化; 条件; 改变初始化条件) {
        code...
    }
注:改变初始化条件不一定是 i++。 i += 2也是可以的
注:该语法有变种写法,但是不推荐使用
注:循环变量在for循环结束之后依旧可用

其它知识点

prompt(提示文字) 弹出一个输入框 并显示提示文字 返回值是用户输入的内容 值的数据类型为字符串
alert(提示文字) 弹出一个警告框 并显示提示文字 

# 自增自减运算符
++  等价于 + 1
--  等价于 - 1
特点: ++ 和 --运算符 既可以出现在变量的前面也可以出现在变量的后面
区别:
    如果出现在变量的前面,先变化 再运算
    如果出现在变量的后面,先运算 在变化

分支结构

为了让程序变得更“聪明”。增加了分支结构判定。

if 语句

语法:
    if (expression) {
        code...
    } else if (expression1) {
        code...
    } else if (expression2) {
        code...
    } else {
        code...
    }
说明;
    if 语句中,可以分为三部分 1 if 语句 2 else if语句 3 else语句
    1 必须出现 2 可以出现多次 可以出现一次 可以不出现 3 可以出现一次 可以不出现
    () 表示判定条件 里面的内容 最终是一个布尔值 
    分支结构中,最终代码执行一条分支中的代码。其余的分支不会执行

switch语句

语法:
    switch (expression) {
        case value1:
            code...
        break;
        case value2:
            code...
        break;
        case ...
            code...
        break;
        default:
            code...
        break;
    }
    swtich 是 开关的意思
    expression 是表达式 最终也是一个布尔值
    case 表示分支 可以出现多次
        value只能是固定的值 不可以是范围表达式
    如果expression的结果与某一个case的value全等 则会执行对应的代码
    break:打断代码,可以不出现,这种情况下会出现“落空”/“穿透”现象
    default: 表示当expression的结果没有与任何一个case的value匹配 则会执行default的代码

三元运算符

是一种对if else语句结构的简化
    if else
        if (expression) {
            code1
        } else {
            code2
        }
    三元:
        语法: expression ? value1: value2
        当表达式的结果为真时,使用value1,否则使用value2
        expression ? code1 : code2;

循环结构

循环就是重复

while循环

语法:
    while (expression) {
        code...
    }
执行规则:
    先对expression判定 如果为真 进入循环 执行code 
    当code执行完毕 再判定expression 如果为真 继续进入循环 code...
    当code执行完毕 再判定expression 如果为真 继续进入循环 code...
    当code执行完毕 再判定expression 如果为真 继续进入循环 code...
    当code执行完毕 再判定expression 如果为真 继续进入循环 code...
    当code执行完毕 再判定expression 如果为真 继续进入循环 code...
    ...
    直到expression不成立 跳出循环 
注: 千万注意,一定要在某一次循环中,将expression变为false

do while循环

语法:
    do {
        循环体
    } while (expression);
执行规则:
    先执行一次循环体的内容 
    再对expression进行判定
    如果为真,继续循环,如果为假,跳出循环
注: 千万注意,一定要在某一次循环中,将expression变为false
注: 无论expression第一次的时候是真还是假,都会执行一次循环体的内容

for 循环

语法:
    for (初始条件1; 判定条件2; 修改初始值4) {
        循环体3
    }
执行规则:
    第一次执行: 1 2 3 4 
    之后的每一次执行: 2 3 4 
变种1: 将初始条件放到for循环前面
变种2: 将修改初始值放入循环体的末尾
变种写法, 知道可以这么写,千万不要这么用
循环变量:在循环结束之后,依旧可用

今日

break

break关键字,用于打断循环的执行。
我们已经见过的break就是switch case语句中的break。如果执行完case中的代码遇见了break,则跳出分支结构。如果没有遇见break,则会继续往下“落空”。继续执行下一个case代码。
额外知识点: 可以通过 x: 在for关键字之前 给当前循环添加一个标记 x表示这个标记的名称
当break使用时,可以在break后面跟一个x来表示break打断的时哪层循环。

continue

continue关键字,用于跳过当前层循环,进入下一次循环

注: continue和break只能够用在循环体内

函数

函数就是一个工具,可以将代码放在里面,随时执行。
注:函数是一等公民

函数的定义

第一种定义方式: 函数声明
function 函数名() {
    要执行的代码   
}
第二种定义方式: 函数表达式
var 变量 = function() {
    要执行的代码
}
注: 第二种方式的本质 其实是定义了一个变量,并将这个函数的地址交给该变量。于是,函数名就是这个变量名。

函数的调用

函数声明定义出来的函数,调用时,既可以在函数之前,也可以在函数之后。
函数表达式定义的函数,调用时,只能够在后面调用。

预解析

JS引擎执行代码的阶段: 通读代码 执行代码
在通读代码阶段,引擎会先查看是否有语法错误,如果有,就报错。如果没有,则在这个过程中,就会将代码中所有的通过var声明的变量和通过function声明的函数提升到代码的最前面。这个提升行为,就是发生在预解析阶段。
所以,切记,以后读代码的第一反应,就是变量和函数的提升。

函数的参数

函数整体由 关键字 函数名 形参列表 函数体组成
形参列表中,可以放置“形式参数”。简称:“形参”。
    // 定义一个函数,计算两个数字的和
    function sum(num1, num2) {
        // 形参num1 "代表" 将来函数执行的时候,要传递的一个参数
        // 形参num2 "代表" 将来函数执行的时候,要传递的另一个参数
        console.log(num1 + num2);
    }
    // 函数执行了
    sum(1, 2); // 输出3

当函数执行的时候,是否需要传递参数,要看函数是否有形参。那么在函数执行的时候传递的参数,叫做实际参数,简称实参。

注: 就像洗碗机一样,我们有了洗碗机(函数), 还需要把“碗”放进去,还需要把“洗洁精”放进去,这样,按下开关(调用函数)时,才可以最终得到一个干净的碗。那么这里的“碗”和“洗洁精”等内容,就是“实际参数”。而洗碗机放碗的位置,和放洗洁精的位置,就是“形式参数”。

函数的参数关系

当函数定义时,可以定义形参,当函数执行时,可以传递实参。
如果函数在执行时,传递的参数与形参不一致,分类如下

当形参比实参多: 
    多余的形参的值为undefined
function sum(a, b) {
    console.log(a);
    console.log(b); 
}
sum(10); // a是10 b是undefined
当形参比实参少:
    没有形参接收多余的实参
function sum(a, b) {
    console.log(a);
    console.log(b);
}
sum(10, 11, 12); // a是10 b是11 12没有形参来接收

arguments

arguments是函数内部的一个成员,只有在函数执行的时候才会存在。可以使用它来获取本次函数在执行时,所有传递的实参。
arguments.length可以获取实参的个数。
function sum() {
    console.log(arguments);
    console.log(arguments.length);
}
sum(1); // => [1]  arguments.length => 1
sum(2); // => [2]  arguments.length => 1
sum(1, 2, 3, 4, 5); // => [1, 2, 3, 4, 5]  arguments.length => 5

arguments是一个类数组对象,也叫做伪数组对象。可以使用 arguments[数字] 来获取对应的值。 数字是 从0开始 的。 这个数字,也可以叫做 下标 或者 索引

function sum() {
    console.log(arguments[2]);
}
sum(1, 2, 3, 4); // => 3
sum(1, 2); // => undefined

return关键字

作用:该关键字是用于在 函数内部 返回内容中止函数执行 的。

// 中止函数执行
function demo() {
    console.log(1);
    console.log(2);
    console.log(3);
    return;
    console.log(4);
    console.log(5);
}
demo(); // 只会输出1 2 3 而不会输出4 5 因为遇见了return
// 返回内容
var a = 10;
var b = 11;
function sum(num1, num2) {
    return num1 + num2;
}
// 进行计算
var result = sum(a, b);
// 使用结果
console.log(result); // 21

注:return关键字只能够在函数内部出现。

函数的定义过程

1 在内存中开辟一个空间
2 把代码放进去
3 把空间的地址交给函数名

函数的调用过程

1 根据函数名称找到内存空间
2 将实参的值传递给形参
3 开始解析内存空间中的代码
4 执行代码

作用域

作用域: 指的是变量起作用的范围 
作用域的划分规则: 只有全局作用域和函数的私有作用域
作用域是根据书写的单词和语法来确定的,所以又叫做词法作用域.
所以,通常我们把代码写完,就可以确定每一个作用域的范围.
注: script标签之间是全局作用域 多个script标签共享同一个作用域 但是每一个script标签中的变量 函数,它们的提升,只能够在本script标签的范围之内.
注: 浏览器在加载script标签的代码的时候,是一个执行完,再去加载执行后面的一个.
    <script>
        var a = 10;
    </script>
    <script>
        console.log(a); // 输出10
    </script>


    <script>
        console.log(a); // ReferenceError: a is not defined
    </script>
    <script>
        var a = 10;
    </script>

函数的属性

函数的属性之一: name  它是函数的名称 函数的名称不论是表达式还是声明 都是变量的名字
函数的属性之二: length  它是函数的形参的个数 
    function demo(a, b, c) {

    }
    console.log(demo.name); // "demo"
    console.log(demo.length); // 3


    var fun = function() {

    }
    console.log(fun.name); // "fun"
    console.log(fun.length); // 0

递归函数

递归函数指的是函数自己再函数体内部调用自己.

注: 无停止条件的递归 就是死循环 写递归函数,先写停止条件

    // a变量一定要定义在函数外部 
    var a = 0;
    function demo() {
        a++;
        if (a >= 10) {
            return;
        }
        demo();
    }
    demo(); // 循环让a自加10次 之后就停止

复习

自增自减运算符
    自增: i++  
    该运算符可以出现在变量的前面或后面
    等价于: i = i + 1
    如果++出现在变量的前面,先自增,再运算 如果++出现在变量的后面,先运算,再自增
    自减: i--
    该运算符可以出现在变量的前面或后面
    等价于: i = i - 1
    如果--出现在变量的前面,先自减,再运算 如果--出现在变量的后面,先运算,再自减
分支结构
    if语句
        语法:
            if (expression1) {

            } else if (expression2) {

            } else {

            }
        执行机制:
            先对expression1做判定,如果为真,执行对应的代码块中的代码执行完毕,分支结束
            如果expression1为假,再根据这种机制往下对其它的表达式做判定,如果遇见了真的,就执行对应的代码块,如果都没有,执行else里的代码
        注: if代码块是一定要有的 else if可以出现多个可以出现一个可以不出现 else 可以出现 可以不出出现 如果出现 只能够出现一次
        注: 如果 if语句的代码块中,只有一条代码,可以省略{}
    switch语句
        语法:
            switch(expression) {
                case value:
                    code...
                break;
                case ……
                break;
                default: 
                break;
            }
            它是对expression做判定,最终得到一个结果 然后使用该结果依次与每一个case的value进行比较(比较方式是全等),如果匹配到了,执行对应的代码。如果匹配不到,继续往下,直到匹配到了,或者到了最后还没有匹配到,则会执行default的代码。
        注: 如果break没写,会出现一种“落空”现象。也就是说:执行完当前case的代码之后,会继续执行下一个case的代码。
    三元运算符:
        是针对if else分支结构的一种简化
        语法: expression ? result1 : result2
        规则: 对expression做判定, 如果为真,则使用result1. 如果为假,则使用result2
循环结构:
    while循环:
        语法:
            while (expression) {
                code...
            }
        执行规则:
            先对expression做判定,如果为真,进入循环执行code,再判定……
            如果为假,就不会进入。
        注: 如果expression第一次判定为假,则不会进入循环
        注: 一定要在code部分修改expression中的内容,以期有朝一日表达式为假。否则就是死循环。
    do while循环:
        语法:
            do {
                code...
            } while (expression);
        执行规则:
            先执行一次code,再做判定。也就是无论如何会执行到一次code部分。
        注意事项,与while循环相同,一定要在code部分修改expression中的内容,以期有朝一日表达式为假。否则就是死循环。
    for 循环:
        语法:
            for (初始化值; 判定条件; 修改初始化值) {
                code...
            }
        执行顺序:
            第一次执行:
                初始化值 开始判定 执行循环体中的代码 修改初始化值
            第二次执行:
                开始判定 执行循环体中的代码 修改初始化值
    break: 跳出循环 默认跳出当前循环

    continue: 跳过当前循环 跳过一次  
函数:是用来装载代码的容器 具备某一种功能的函数 我们可以叫它工具 
函数的定义:
    语法1: 函数声明
        function 函数名() {

        }
    语法2: 函数表达式
        var 变量 = function() {

        }
    区别:
        函数声明,可以在同级作用域的任何位置调用。 
        函数表达式,可以在同级作用域中,赋值代码之后的位置调用。
函数的调用:
    语法: 函数()
函数的优点:
    1 复用 一次书写,多次使用
    2 封装 使代码变得简洁
    3 执行时机 函数定义在哪里无所谓 关键看在哪里调用 想什么时候调用就什么时候调用
函数在定义的时候:
    1 开辟一个内存空间
    2 把函数代码放进去
    3 把内存空间的地址交给变量 
函数在调用的时候:
    1 根据变量找到对应的内存空间
    2 传递参数
    3 预解析
    4 执行
函数的组成部分: 关键字 函数名 形参列表 函数体
    关键字:function
    函数名:函数的名称 起名时的规则 依照变量的命名规范 尽可能的有语义
    形参列表:函数的形参定义位置    =>  ()
    函数体: 函数存放将来要执行的代码的位置    => {}
函数的参数:
    形参:
        等于定义在函数内部的变量 它们只可以在函数内部使用
        名字也要符合JS的变量命名规范
    实参:
        函数定义的时候,决定有多少形参。函数调用的时候,决定传递多少实参。
    传递规则:
        函数在调用的时候,第二步是传递参数,参数在调用时,是一一对应的传递方式。一个形参对应一个实参,按照顺序,一一对应。
        如果形参比实参多,多余的形参的值为undefined
        如果形参比实参少,多余的实参没有意义。
arguments:它是一个函数内部的伪数组/类数组对象,可以根据它获取到所有函数在本次调用时传递的参数。它的生存周期,就是函数执行的过程中。
    arguments是所有实参的集合
    我们可以通过[数字]获取里面的内容 数字从0开始 表示“下标” “索引”
    arguments.length 可以获取实参的个数
return关键字:
    作用1: 中止函数的执行
    作用2: 将return后面的内容,返回到函数的调用处。只可以返回一个值。
递归:是一种函数的使用方式。 函数自己调用自己。
    注:递归可以认为是一种特殊的循环。
    注: 递归一定要有停止条件,否则就是死循环。
作用域: 指的是代码对不同的“范围”的划分。 
    划分规则: 
        1 全局是一个作用域 这个作用域叫做全局作用域
        2 只有函数,可以划分这么一个“范围”(作用域) 这样划分出来的作用域叫做私有作用域。
    划分规则的应用对象: 变量
    所以我们可以理解为: 作用域 划分了一个所有变量各自起作用的区域。
    作用域的查找机制:
        一个代码中使用到了某一个变量
            首先,在这条代码当前所在的作用域中查找,如果找到了就使用 如果没有找到
            向上级作用域查找,如果找到了就使用 如果没有找到
            向上级作用域查找,如果找到了就使用 如果没有找到
            ……
            重复这个过程,直到找到了,或者到了全局作用域还没有找到。此时会报一个错误 xxx is not defined
预解析:
    指的是浏览器JS引擎在执行代码的过程之前,会先进行“通读”代码,在这个过程中,会将所有遇见的var定义的变量和函数声明的函数提升。
        提升的位置: 
            如果是script标签,提升到当前script标签的最开头
            如果是函数,提升到函数的函数体的最开头

作用域的特点

作用域的机制

作用域是针对变量的起作用的范围。
而变量又分为“使用变量”和“赋值变量”

使用变量

又叫做访问变量 出现在表达式中,赋值语句右侧。 

访问变量规则: 当访问变量的时候,会先查看当前作用域中是否存在该变量,如果有,就使用。如果没有,就将会向上一层级作用域中寻找。依次向上,直到找到,或者到了全局作用域中还没有找到,就会报错。

赋值变量

也叫做修改变量 只出现在赋值语句左侧

赋值变量规则: 当对一个变量进行赋值的时候,会先查看当前作用域中是否存在该变量,如果有,就赋值。如果没有,就向上一层级查找。依次向上,直到找到,或者到了全局作用域中还没有找到,就会在全局作用域中悄悄的声明这个变量并赋值。

千万不要使用这个特点 切记,切忌。

// 当前是全局作用域
var num = 100; // 在全局作用域中定义的变量

// 定义一个函数
function demo() {
    var num = 101; // 这是在函数作用域中定义的变量
    console.log(num);
}
// 执行函数
demo(); // 101 

解释: 当在函数内部访问变量num的时候,先看当前作用域中是否有num 找到了! 于是就用101 输出101

var num = 100; // 在全局作用域中定义的变量
// 定义一个函数
function demo() {
    // var num;  // 因为声明提升的原因 代码其实是这样子的
    console.log(num); 
    var num = 101; // 这是在函数作用域中定义的变量 虽然定义是在这里 但是提升了
}
// 执行函数
demo(); // undefined

解释:依旧是作用域的问题,但是因为输出代码在前面,所以有些同学可能会误以为会输出100 但是不要忘记 预解析!!!

var num = 100; // 在全局作用域中定义的变量
// 定义一个函数
function demo() {
    var num = 101; 
}
// 执行函数
demo();
// num是多少
console.log(num); // 100

解释:作用域的问题,因为输出的代码是在全局作用域中的,所以会直接访问全局中的变量 而与函数内部的变量无关

var num = 100; // 在全局作用域中定义的变量
// 定义一个函数
function demo() {
    num = 101; 
}
console.log(num); // 100
// 执行函数
demo();
// num是多少
console.log(num); // 101   

读代码:

1 提升
2 给全局中的num赋值为100 
3 执行函数
    将num赋值为101  问题的关键在于:修改的这个num到底是不是全局中的? 
        答案就是: 依旧是就近原则, 如果当前作用域中有声明的num变量 
        就修改它 如果没有向上寻找 如果找到了就修改它 如果没有找到再向上寻找 
        重复这个过程 直到找到或者到了全局作用域中还没有找到,就会在全局中声明这个变量并赋值
// 如果一个变量没有通过var声明 就直接赋值  
num = 101; // 这种不经过声明就直接赋值而且还不会报错的特点属于JS的糟粕之一。一定不要使用。
console.log(num); // 101
console.log(num);
num = 101;

这种情况下会报错 因为num没有经过定义就被使用

疑问:
console.log(num)在使用num
难道 num = 101 不是在使用num吗?

为什么第一条console代码就会报错 而num = 101就不会报错?

因为第一个是在“访问”变量 而第二个是在“赋值”

function demo() {
    num = 11;
}
demo();
console.log(num);

解读: 当demo执行的时候, num = 11 被执行 先查找num是否在当前作用域中存在,结果发现没有

没有就向上寻找,到达了全局作用域,也没有,于是就在全局作用域中,声明了该变量 所以当输出num时候,已经声明并赋值完毕
所以可以输出

当demo不执行的时候,就不会执行到这条代码 于是整个过程不会发生, num就没有被声明在全局 此时输出num时,是在访问num变量
会报错

数组

装载一组数据的容器

数组的定义

方式1  字面量
语法:
    var arr = [];
方式2  构造函数
语法:
    var arr = new Array();
传参规则:
    当没有参数时, 定义的是一个空数组
    当参数只有一个并且是数字时,该数字表示数组的长度
    当参数有多个时,参数就是每一个成员
方式3 构造函数
语法:
    var arr = Array();
传参规则: 同上

数组的使用

存储数据
    数据是以一定的顺序存储在内部 每一个数据都有一个"序号" 这个序号叫做下标 或者 索引
    语法: 
        数组[下标] = xxx
访问数据
    语法:
        数组[下标] 
    当该代码单独出现,就表示要使用数据。就会去读取对应的数据。如果数据存在,就得到,如果不存在就读取不到,返回undefined。

数组的length属性

数组是一组数据,length属性表示这个数组中的内容的个数。简称数组的长度。
该长度是可读可写的属性。
当设置属性的时候,表示要修改该数组的长度。数组的长度会发生变化。
当读取时,会实时返回数组的当时的长度。
    var arr = [1, 2, 3, 4];
    console.log(arr.length); // 4
    arr.length = 1; // 修改数组的长度
    console.log(arr); // 输出 [1]
    console.log(arr.length); // 1

对象的使用

对象: 是一组k:v对的集合。
每一组k:v对,叫做对象的属性。 k表示对象的属性名,v表示对象的属性值。
每一组k:v对,使用逗号隔开,推荐一行一个k:v对
k最好符合变量的命名规范。 v是具体的数据。可以是任何数据。

定义对象:

方式一: 字面量 (推荐方式)

    var obj = {}; // 字面量定义对象

    // 定义对象并设置属性
    var obj1 = {
        name: "张三"
    };

方式二: 构造函数

    var obj = new Object();
    var obj = Object();

对象的属性操作:

读取属性:
方式1 点语法

    var obj = {
        name: "张三"
    }
    console.log(obj.name); // 张三

方式2 方括号语法

    var obj = {
        name: "张三"
    }
    console.log(obj["name"]); // 张三

设置属性:
方式1 点语法

    var obj = {
        name: "张三"
    }
    obj.age = 12;
    console.log(obj); // {name: "张三", age: 12}

方式二 方括号语法

    var obj = {
        name: "张三"
    }
    obj["age"] = 13;
    console.log(obj); // {name: "张三", age: 13}

删除属性

delete关键字 该关键字只能用来删除对象的属性 而不可以用来删除变量

    var obj = {
        name: "张三"
    }
    delete obj["name"];
    console.log(obj); // {} 

对象的循环遍历

语法: for (var i in obj) {}

    var obj = {
        name: "小明",
        age: 13,
        sex: "男",
        married: false
    }
    // 使用for in 循环遍历对象
    for (var i in obj) {
        // i 是对象的属性名 
        // obj[i] 是对象的属性值
    }

注:obj.i 这种方式,真的是在读取 obj的 i 属性 而不是读取i变量所保存的值属性

方括号语法与点语法的区别

方括号语法:
    [] 之间是一个JS的执行环境,可以使用变量,表达式
    [] 最终需要的是一个字符串,如果不是字符串,会转为字符串(调用toString方法)
    [] 只要内容是字符串,不论是否符合变量命名规范,都可以成功
点语法:
    点语法,点什么,就是什么 
    点语法,必须符合变量的命名规范
        var a = "name";
        var obj = {
            name: "张三",
            a: 123
        }
    点语法:
        console.log(obj.name); // "张三"
        console.log(obj.a); // 123
    方括号语法:
        console.log(obj[a]); // "张三"
        console.log(obj["a"]); // 123

复习

作用域的特点

作用域的机制

作用域是针对变量的起作用的范围。
而变量又分为“使用变量”和“赋值变量”

使用变量

又叫做访问变量 出现在表达式中,赋值语句右侧。 

访问变量规则: 当访问变量的时候,会先查看当前作用域中是否存在该变量,如果有,就使用。如果没有,就将会向上一层级作用域中寻找。依次向上,直到找到,或者到了全局作用域中还没有找到,就会报错。

赋值变量

也叫做修改变量 只出现在赋值语句左侧

赋值变量规则: 当对一个变量进行赋值的时候,会先查看当前作用域中是否存在该变量,如果有,就赋值。如果没有,就向上一层级查找。依次向上,直到找到,或者到了全局作用域中还没有找到,就会在全局作用域中悄悄的声明这个变量并赋值。
千万不要使用这个特点 切记,切忌。

数组

装载一组数据的容器

数组的定义

方式1  字面量
语法:
    var arr = [];
方式2  构造函数
语法:
    var arr = new Array();
传参规则:
    当没有参数时, 定义的是一个空数组
    当参数只有一个并且是数字时,该数字表示数组的长度
    当参数有多个时,参数就是每一个成员
方式3 构造函数
语法:
    var arr = Array();
传参规则: 同上

数组的使用

存储数据
    数据是以一定的顺序存储在内部 每一个数据都有一个"序号" 这个序号叫做下标 或者 索引
    语法: 
        数组[下标] = xxx
访问数据
    语法:
        数组[下标] 
    当该代码单独出现,就表示要使用数据。就会去读取对应的数据。如果数据存在,就得到,如果不存在就读取不到,返回undefined。

数组的length属性

数组是一组数据,length属性表示这个数组中的内容的个数。简称数组的长度。
该长度是可读可写的属性。
当设置属性的时候,表示要修改该数组的长度。数组的长度会发生变化。
当读取时,会实时返回数组的当时的长度。

对象的使用

对象: 是一组k:v对的集合。
每一组k:v对,叫做对象的属性。 k表示对象的属性名,v表示对象的属性值。
每一组k:v对,使用逗号隔开,推荐一行一个k:v对
k最好符合变量的命名规范。 v是具体的数据。可以是任何数据。

定义对象:
方式一: 字面量 (推荐方式) ;
var obj = {};
方式二: 构造函数
var obj = new Object();
var obj = Object();

对象的属性操作:

读取属性:
方式1 点语法 obj.name
方式2 方括号语法 obj[“name”]
设置属性:
方式1 点语法 obj.xxx = xxx;
方式2 方括号语法 obj[“xxx”] = xxx;
删除属性

delete关键字 该关键字只能用来删除对象的属性 而不可以用来删除变量

对象的循环遍历

语法: for (var i in obj) {

}

注:obj.i 这种方式,真的是在读取 obj的 i 属性 而不是读取i变量所保存的值属性

方括号语法与点语法的区别

方括号语法:
    [] 之间是一个JS的执行环境,可以使用变量,表达式
    [] 最终需要的是一个字符串,如果不是字符串,会转为字符串(调用toString方法)
    [] 只要内容是字符串,不论是否符合变量命名规范,都可以成功
点语法:
    点语法,点什么,就是什么 
    点语法,必须符合变量的命名规范

其它知识点

Math.pow(x, y); 该方法用于计算x的y次方
Math.max();  该方法用于计算传递给max的所有参数中,最大的那个
Math.min();  该方法用于计算传递给min的所有参数中,最小的那个

小提示: 数组的循环与arguments的循环方式一致

数组的方法

push

作用: 向数组的末尾增加一个成员
返回值: 数组的长度
注:会改变原数组
// 定义数组
var arr = ["张三", "李四", "王五", "尼古拉斯赵四", "尼斯湖水怪"];
// 使用数组的方法 
var result = arr.push("西双版纳");
console.log(result); // 6
console.log(arr); // ["张三", "李四", "王五", "尼古拉斯赵四", "尼斯湖水怪", "西双版纳"]

pop

作用: 从数组的末尾移除一个成员 
返回值: 被移除的成员
注:会改变原数组
// 定义数组
var arr = ["张三", "李四", "王五", "尼古拉斯赵四", "尼斯湖水怪"];
// 使用数组的方法 
var result = arr.pop();
console.log(result); // 尼斯湖水怪
console.log(arr); // ["张三", "李四", "王五", "尼古拉斯赵四"]

unshift

作用:从数组的头部添加一个成员
返回值: 数组的长度
注:会改变原数组
// 定义数组
var arr = ["张三", "李四", "王五", "尼古拉斯赵四", "尼斯湖水怪"];
var result = arr.unshift("王二");  // 它的作用是给数组的头部增加一个新成员 并返回数组的长度
console.log(arr); // 王二  出现在数组的头部  
console.log(result);  // 改变之后 数组的新长度  6

shift

作用: 从数组的头部移除一个成员
返回值: 被移除的成员
注:会改变原数组
// 定义数组
var arr = ["张三", "李四", "王五", "尼古拉斯赵四", "尼斯湖水怪"];
var result = arr.shift(); // 它的作用是将数组的头部第一项移除 并返回
console.log(arr);  // 张三已经从数组中消失
console.log(result); // 被移除的成员 张三

concat

作用: 将两个数组拼接
返回值:新的拼合后的数组 
注:不会改变原数组
var arr = [1, 2, 3, 4];
var arr1 = arr.concat([5, 6, 7, 8]);
console.log(arr); // [1, 2, 3, 4]
console.log(arr1); // [1, 2, 3, 4, 5, 6, 7, 8]

sort

作用:将数组重新排序 
参数:函数
    接受一个函数作为参数 该函数有两个形参 分别代表数组内的两个数字 如果该函数的返回值为a - b  则数组从小到大排序
    如果该函数返回的是b - a 则数组从大到小排序 
返回值: 原数组
注:会改变原数组
var arr = [1, 9, 45, 55, 3, 67, 8, 101];
var arr1 = arr.sort(function(a, b) {
    return a - b;
});
console.log(arr);  // [1, 3, 8, 9, 45, 55, 67, 101]
console.log(arr1); // [1, 3, 8, 9, 45, 55, 67, 101]

slice

splice

join

indexOf

其它知识点

Math.random() 该方法返回一个随机数 [0 - 1)

# JS中的常用事件

什么叫做事件

所谓的事件,是浏览器监听用户行为的一种机制。
比如,当用户使用鼠标 “点击” 一个按钮,会触发该按钮的“点击”事件 如果此时我们想要执行代码 就可以通过JS脚本设置“点击”事件
同样的,如果用户鼠标双击一个按钮,会触发该按钮的双击事件 
类似的事件还有很多

事件的分类

鼠标事件
    click 点击事件
    dblclick 双击事件
    mousedown 鼠标按下事件
    mouseup 鼠标抬起事件(一次click包含一次mousedown和一次mouseup)
    mouseover 鼠标进入事件
    mouseenter 鼠标进入事件
    mouseout 鼠标离开事件
    mouseleave 鼠标离开事件
    mousemove 鼠标移动事件
键盘事件
    keydown 键盘键被按下
    keyup   键盘键被松开
    keypress 输入
浏览器的事件
    load 页面中所有资源都被加载完毕的时候
    scroll 页面的卷动
焦点事件
    focus 当一个元素获取到焦点时
    blur 当一个元素失去焦点时
移动端事件
    touchstart  触摸开始事件 会在手指按下的时候触发
    touchmove   触摸并移动  会在手指按下并移动的时候触发
    touchend    触摸结束事件  会在手指离开的时候触发
其它事件
    animationstart  动画开始时触发 
    animationend    动画结束时触发
    transitionend   过渡结束时触发

绑定事件

绑定事件的第一步 获取元素
    // HTML代码
    <button id="btn">点我试试看</button>
    // JS代码
    function click() {
        console.log("你好");
    }
    btn.onclick = click;

函数中的this

this是函数中的一个对象 只能够通过点语法和方括号语法修改或者访问 不能够通过 = 修改 因为它直接指向内存
特点:
    在函数定义的时候,无法确定指向
    只有在函数调用的时候,才可以确定指向
指向规则:
    谁调用 this就指向谁
    当没有明确的调用者时,指向window

```JavaScript
    var fun = function() {
        console.log(this);
    }
    var obj = {};
    obj.demo = fun;
    
    // 设置为元素的事件
    btn.onclick = fun;


    fun(); // 指向window 因为没有明确的调用者
    obj.demo(); // 指向obj 因为是obj在调用
    // 当点击btn时 this指向 btn 因为是触发了 btn的该事件
```

字符串

存储: 计算机只能够存储二进制 所以存储字符串时 也需要转为二进制 所以就需要有一个对照表 方便将字符和二进制进行转换 这样的内容叫做编码方式 常见的有 ascii unicode 等

定义字符串的新的方式

    var str = new String("a");
    console.log(typeof str); // object
    // 转换为字符串的方式就是str.toString();
包装类型:在面向对象的思想中,一切都得是对象。而JS中有一些基本类型,此时就需要“包装”一下,将这些基本类型包装成对象类型。

字符串的length属性

字符串也有length属性

    var a = "abcdefg";
    console.log(a[2]); // c

字符串也可以通过下标获取对应的字符

常见的方法

charAt 参数是数字 返回值是该数字所指向的下标字符
    var str = "abcdefg";
    // 获取指定位置的字符
    var code = str.charAt(5);
    console.log(code); // f
charCodeAt 参数是数字 返回值是该数字所指向的下标字符的编码
    var str = "abcdefg";
    var code = str.charCodeAt(5); 
    console.log(code); // 102 
split 参数是分隔符 返回值是以该参数作为切割之后的数组
    var str = "a1b1c1d1e1f"; // 想要以1作为分隔符 将字符串切割成数组 => ["a", "b", "c", "d", "e", "f"];
    var arr = str.split("1");
    console.log(arr); // ["a", "b", "c", "d", "e", "f"];

    // 数组转为字符串
    // ["a", "b", "c", "d", "e", "f"].join("1"); => a1b1c1d1e1f
substring 该方法用于截取字符串中的一段
    var str = "abcdefg";
    var str1 = str.substring(1, 2);
    var str2 = str.substring(1);
    var str3 = str.substring();
    var str4 = str.substring(-5, -2);
    var str5 = str.substring(5, 1);
    console.log(str1); // b
    console.log(str2); // bcdefg
    console.log(str3); // abcdefg
    console.log(str4); // 空字符串 截取不到
    console.log(str5); // bcde
    // 特点:两个参数时,总是从小的截取到大的
    // 特点:当数值为负数时 不会从后往前数

substr 该方法也用于截取字符串中的一段 第一个参数依旧表示截取的开始位置 第二个参数表示要截取的字符串的长度

    var str = "abcdefghijkl";
    var str1 = str.substr(3, 5);
    console.log(str1);

slice 该方法用于截取字符串的一段 第一个参数表示截取的开始位置(包含) 第二个参数表示截取的结束位置(不包含)

    var str = "abcdefghijkl";
    var str1 = str.slice(1, 5);
    var str2 = str.slice(5, 1);
    var str3 = str.slice(-5);
    console.log(str1); // bcde
    console.log(str2); // 空字符串 因为截取不到
    console.log(str3); // hijkl 从后往前截取

indexOf 该方法用于获取数组中第一个从某个位置开始出现的字符串的第一个字符的下标 如果找不到 就返回-1 第一个参数是被查询的字符串 第二个参数是查询的开始位置

    var str = "abcdefgdfdfdf";
    var index = str.indexOf("df");
    console.log(index); // 

toLowerCase 该方法用于将所有的字符串中的英文小写

    var str = "ABCDEFG,你好,abcde";
    var str1 = str.toLowerCase();
    console.log(str1); // abcdefg,你好,abcde

字符串的比较 一位一位的比较 比较对应位数的字符的ascii码 如果相同 比较下一位 如果不同 出结果

    var str = "aA"; // ascii A 65
    var str1 = "aa"; // ascii a 97 
    console.log(str > str1); // false

toUpperCase 该方法用于将所有的字符串中的英文大写

    var str = "abc";
    var str1 = str.toUpperCase();
    console.log(str1); // ABC
    // replace 该方法用于将字符串中的指定字符(串)替换位指定字符(串)
    // var str = "今天天气不错,没下雨";
    // var str1 = str.replace("没", "");
    // console.log(str1);

郑重声明: 所有的字符串方法都不会改变原字符串

为什么字符串居然能够调用方法,它不是基本数据类型吗?

值类型就是值类型 不应该拥有任何方法的

其实…

var a = "str";
var b = a.replace("s", "a");

字符串这个数据类型,在JS中运行时
JS引擎中解析的时候会先把 a 这个"str"值替换为 var s = new String(“str”);
当a.replace方法调用的时候 等价于

var s = new String("str");
var b = s.repalce("s", "a");
s = null;

因为真正操作的时候是新生成的对象内部在操作 a所保存的"str"只是作为参数传递了进去 在里面复制了一份 操作的是这个"副本" 最终会销毁这个生成的对象

函数的传参规则

JS中的函数可以执行时传递参数。那么如果在函数内部修改传递进去的参数,会不会影响到函数外部的值呢?
函数在传递参数时,到底是如何传参的呢?

JS中的数据类型分两种: 基本数据类型,引用数据类型

基本数据类型的数据在传递时,复制传递 也就是复制了一份并传递进去 所以在函数内部,如何操作都只是在操作副本。与外部的数据无关。
引用数据类型的数据在传递时,传递引用 也就是把地址复制了一份并传递进去 所以函数内部是可以得到函数外部的数据保存的地址的,如果在函数内部打点或者方括号修改地址内容,则会影响到函数外部,如果在函数内部使用=修改变量保存的内容,则不会影响函数外部。
    // 在函数内部修改值类型参数
    var a = 123;
    function demo(b) {
        b = 12;
    }
    demo(a);
    console.log(a); // 123
    // 在函数内部使用等号修改引用类型参数
    var obj = {};
    function demo(b) {
        b = 123;
    }
    demo(obj);
    console.log(obj); // {}
    // 在函数内部使用方括号或者点语法修改引用类型参数
    var obj = {};
    function demo(b) {
        b.a = 10;
        b["b"] = 11;
    }
    demo(obj);
    console.log(obj); // {a: 10, b: 11}
    // 在函数内部先使用方括号或者点语法修改 再使用等号
    var obj = {};
    function demo(b) {
        b.a = 10;
        b["b"] = 11;
        b = {};
        b.c = 12;
    }
    demo(obj);
    console.log(obj); // {a: 10, b: 11} 

严格模式

因为JS是一门很随心 很随意的语言 而且因为设计之初遗留了很多不好的地方 这就给开发人员制造了很多困扰 而且也有开发人员给开发人员制造困扰
为了解决这些问题 ES5 中 增加了一个 "严格模式" 严格要求开发人员的代码书写

开启严格模式

在当前作用域的第一行 使用字符串 "use strict";

1 声明变量必须使用var

num = 10;
console.log(num);
// 开启严格模式之后 报错: num is not defined

2 函数的形参不可以重名

function demo(a, a, b, c, d) {
    console.log(a, b, c, d);
}
demo(1, 2, 3, 4, 5);
// 开启严格模式之后 报错:Uncaught SyntaxError: Duplicate parameter name not allowed in this context

3 不可以使用八进制

var num = 044;
console.log(num); // 36
// 开启严格模式之后 报错:Uncaught SyntaxError: Octal literals are not allowed in strict mode.

4 不可以使用保留字作为变量名

var implements = 123;
console.log(implements);
// 开启严格模式之后 Uncaught SyntaxError: Unexpected strict mode reserved word

5 eval

eval("var a = 10;");
console.log(a);
// 开启严格模式之后 eval执行的代码 不会影响到当前的作用域了 会独立给eval强制开辟一个作用域
// Uncaught ReferenceError: a is not defined 

复习

字符串:
    初始化方式 
        字面量  构造函数 
    存储方式
        ascii  
        unicode 
        utf-8就是八位的unicode编码
    属性
        length属性 表示字符串的长度
        length属性只读
        可以通过下标的方式获取对应位置的字符
    循环 
        可以使用for循环 
        也可以使用for in 循环
    方法
        charAt 用来获取对应位置的字符
        charCodeAt 用来获取对应位置的字符的ascii码
        subString  用来截取一部分字符串 数字比较小的参数表示开始截取的下标位置(包含) 数字比较大的参数表示截取结束的下标位置(不包含)  如果只有一个参数 表示从该位置截取到最后 如果没有参数 就是复制原字符串
        subStr  用来截取一部分字符串 第一个参数表示开始位置 第二个参数表示要截取的字符串的长度
        slice 用来截取一部分字符串 第一个参数表示开始截取的下标位置(包含) 第二个参数表示截取的结束位置(不包含) 如果值为负数 从后往前数 从-1开始  如果只有一个参数 表示从该位置截取到最后 如果没有参数 就是复制原字符串
        split 用来切割字符串成为数组 参数是分隔符
        indexOf 用于查询指定字符串在源字符串中的下标位置 第一个参数是被查询的字符串 第二个参数表示查询的起始位置 如果找得到,就返回第一个字符下标位置 如果找不到返回-1 
        toLowerCase 将字符串转为小写
        toUpperCase 将字符串转为大写
        replace 用于将字符串中的指定内容替换为指定内容  第一个参数表示被替换下的内容 第二个参数表示被替换上的内容 两个参数都是字符串
    字符串调用方法
        字符串是可以调用方法的 因为它有包装类型
        var a = "";
        var b = a.slice();

        var a = "";
        var s = new String(a);
        var b = s.slice();
        s = null;
    字符串的所有方法都不会改变原字符串
事件
    想要与网页进行交互 离不开事件
函数中的this
    函数中有三个内容 
        arguments 表示实参的集合 
        return    表示返回内容 || 终止函数的执行
        this      this是一个对象 指向谁只有在函数被执行的时候才能确定 谁调用 指向谁
函数传参
    如果传递的是值类型数据 会复制一份传递给函数内部
        所以,无论在函数内部怎么修改 都不会影响到函数外的值
    如果传递的是引用类型数据 会把地址复制一份 传递给函数内部
        如果函数内部通过点语法或者方括号语法进行修改 赋值等操作 都会影响到函数外部的值
        如果函数内部通过等号将地址丢弃 不会影响到函数外部

Math对象

JS中有许多的内置对象。其中,Math对象封装了许多常用的数学函数。

  • Math.random

    该方法用于生成一个随机数0~1 包含0 不包含1

        // 获取一个从0到9的随机整数数字
        var r = Math.random();
        var num = parseInt(Math.random() * 10);
        console.log(num);
    
  • Math.abs

    该方法用于获取一个数的绝对值

        // 定义一个负数
        var num = -10;
        // 获取它的绝对值
        var abs = Math.abs(num);
        // 输出
        console.log(abs); // 10
    
  • Math.ceil

    向上取整

        var num = 1.1;
        var result = Math.ceil(num);
        console.log(result); // 2
    
  • Math.floor

    向下取整

        var num = 1.1; 
        var result = Math.floor(num);
        console.log(result); // 1
    
  • Math.round

    四舍五入

        var num = 1.4;
        var num1 = 1.5;
        console.log(Math.round(num)); // 1
        console.log(Math.round(num1)); // 2
    
  • Math.pow

    用于求一个数的几次方 第一个参数是底数 第二个参数是指数

        var num = Math.pow(2, 8);
        console.log(num); // 256
    
  • Math.max

    求所有参数中的最大值

        var max = Math.max(1, 2, 56, 78, 99, 0, 46, 23);
        console.log(max); // 99
    
  • Math.min

    求min参数中的最小值

        var min = Math.min(1, 2, 56, 78, 99, 0, 46, 23);
        console.log(min); // 1
    

额外说明: …语法是ES6中的语法 可以将数组的每一个成员拆解成参数传递给函数

额外说明: apply方法是所有函数都有的方法 作用是改变函数中的this指向并以数组的形式传递参数

Date对象

JS中有许多的内置对象。 还有一个对象 Date 它负责日期方面的内容。(其实是构造函数)

注意:以后 只要出现new关键字 它就是引用类型

初始化日期

  • 不传递参数

    var date = new Date(); // 当直接通过new调用Date时 并且不传递参数时 得到的时当前的系统时间
    console.log(date); // 当前时间 Tue Aug 27 2019 16:43:49 GMT+0800 (中国标准时间)
    
  • 传递一个参数

    Date可以接受一个字符串作为参数 要求是符合系统时间的字符串

        var date = new Date("2019-10-10 19:00:00")
    
  • 传递两个参数

    Date可以接受参数 接受两个参数 第一个表示年份 第二个表示月份(0表示1月) 0 ~ 11

        var date = new Date(2019, 2);
    
  • 传递三个参数

    前两个同上 第三个表示天数 这个不是从0开始 写几就是几号 1 ~ 31

        var date = new Date(2019, 1, 20);
    
  • 传递四个参数

    前三个同上 第四个表示小时 值0 ~ 23

        var date = new Date(2019, 1, 20, 1); 
    
  • 传递五个参数

    前四个同上 第五个表示分钟 0 ~ 59

        var date = new Date(2019, 1, 20, 1, 5);
    
  • 传递六个参数

    前五个同上 第六个表示秒 0 ~ 59

        var date = new Date(2019, 1, 20, 1, 5, 45);
    

获取日期部分内容

  • 获取年 getFullYear()

  • 获取月 getMonth()

  • 获取天数 getDate()

  • 获取小时 getHours()

  • 获取分钟 getMinutes()

  • 获取秒数 getSeconds()

  • 获取毫秒值 getMillionseconds()

  • 获取星期几 getDay()

    注: 0 是星期天 周一到周六 1 ~ 6

  • 获取从1970年1月1日0点0分0秒至日期的毫秒值 getMillions()

设置日期

  • 设置年 setFullYear()
  • 设置月 setMonth()
  • 设置天 setDate()
  • 设置小时 setHours()
  • 设置分钟 setMinutes()
  • 设置秒数 setSeconds()

复习

函数中的this
是函数中的对象,它直接指向内存地址,必定是一个引用类型
特点:在函数执行的时候,确定this的指向。
规则:谁在调用这个函数,this指向谁。如果没有明确的调用者,this将会指向window

Math对象 就是一些常用的数学函数的封装对象
该对象不需要通过new来调用,就可以直接使用

绝对值 Math.abs() 参数是数字 返回值是绝对值
随机数 Math.random() 返回值 0 ~ 1 的一个随机数 可能为0 不可能为1 
向上取整 Math.ceil() 参数是数字 返回值是该数字的整数部分+1(如果有小数位)
向下取整 Math.floor() 参数是数字 返回值是该数字的整数部分(舍弃小数位)
四舍五入 Math.round() 参数是数字 返回值是四舍五入之后的值
获取最大值 Math.max() 参数是不定数量的数字 返回值是这些数字中的最大值
获取最小值 Math.min() 参数是不定数量的数字 返回值是这些数字中的最小值
Math.PI => 3.141592.....

Date构造函数 用于处理日期方面的相关
初始化
    new Date() 
        传递两个参数 分别是 年 月
        传递三个参数 分别是 年 月 日
        传递四个参数 分别是 年 月 日 时 
        传递五个参数 分别是 年 月 日 时 分
        传递六个参数 分别是 年 月 日 时 分 秒
        传递一个参数 是一个符合日期格式的字符串 可以是 yyyy.MM.dd hh:mm:ss 可以是yyyy-MM-dd hh:mm:ss
方法
    getFullYear() 获取一个日期的年份数字
    getMonth() 获取日期的月份 0表示1月 1表示2月
    getDay() 获取星期几 0 表示周日 1 ~ 6 表示周一~周六
    getDate() 获取该日期是当月的几号 1 ~ 31
    getHours() 获取小时数
    getMinutes() 获取分钟数
    getSeconds() 获取秒数
    getMillionseconds() 获取毫秒值
    getTime() 获取从1970年1月1日0时0分0秒至该日期的毫秒值

    setFullYear() 设置一个日期的年份
    setMonth() 设置一个日期的月份
    setDate() 设置一个日期的几号
    setHours() 设置小时数
    setMinutes() 设置分钟数
    setSeconds() 设置秒数
    setMillionseconds() 设置毫秒数

补充: 数组也有一个reverse方法 作用: 将原数组的成员顺序反转 会改变原数组 返回值也是原数组
补充: 任何字符串的方法都不会改变原字符串

BOM(Browser Object Model浏览器对象模型)

BOM是JS中的一个组成部分,用于操作浏览器

BOM 可以做的事情有很多很多
获取浏览器的视口尺寸
修改浏览器的地址栏
通过BOM可以操作历史记录
可以关闭页面
可以设置定时器 延时器
可以获取浏览器的信息
……

获取浏览器的尺寸

    console.log(window.innerWidth); // 输出浏览器视口宽度
    console.log(window.innerHeight); // 输出浏览器视口高度

window对象

该对象是BOM的具体对象。所有的BOM内容都可以通过它来获取

特点:所有的window上的属性,在访问时,可以省略"window. "

window.location

是浏览器中负责浏览器的地址栏的相关对象

  • href属性 用于设置和读取当前浏览器窗口的地址栏内容
    // 将当前页面的地址栏修改为百度 也就是跳转到百度
    location.href = "https://www.baidu.com";
  • reload方法 用于刷新当前页面
    location.reload(); // 刷新页面

window.history

是浏览器中负责历史记录的相关对象

  • forward方法 让历史记录前进一次
    history.forward(); // 前进一次
  • back方法 让历史记录后退一次
    history.back(); // 后退一次
  • go方法 接受一个数字作为参数
    如果为0 表示刷新当前页面
    如果为正数 表示前进几次
    如果为负数 表示后退几次
    history.go(0); // 刷新页面
    history.go(1); // 前进一步 等价于history.forward();
    history.go(2); // 前进两步 
    history.go(-1); // 后退一步 等价于history.back();
    history.go(-2); // 后退两步 

打开关闭页面

    // 打开页面
    window.open(打开的页面的网址);

    // 关闭页面
    window.close();

事件

  • load事件 在资源都加载完毕之后触发
    window.onload = function() {
        // code... 这里的代码会在所有资源加载完毕之后执行
    }
  • scroll事件 当页面有卷动值(页面比视口高)时,页面卷动值发生了改变时会触发
    window.onscroll = function() {
        // code... 这里的代码会在页面卷动值发生改变时触发
    }

浏览器信息

window.navigator 获取浏览器对象

  • navigator.userAgent 获取浏览器代理信息字符串
  • navigator.platform 获取平台信息

setInterval(重点)

  • 第一个参数是函数
    • 表示要执行的代码
  • 第二个参数是数字
    • 表示执行的时间间隔 单位是毫秒
  • 返回值是数字 这个数字是一个编号 代表这是第几个定时器
    // 每一秒都会执行一次输出
    setInterval(function() {
        console.log(1);
    }, 1000);

今天只需要知道这是一个可以让代码按照时间循环执行的函数即可。

setTimeout(重点)

  • 第一个参数是函数
    • 表示要执行的代码
  • 第二个参数是数字
    • 表示延迟的时间 单位是毫秒
  • 返回值是数字 这个数字是一个编号 代表这是第几个定时器
    // 1秒后输出一次 不再输出
    setTimeout(function() {
        console.log(1);
    }, 1000)

clearInterval(重点)

  • 接受一个参数 就是要清除的定时器或者延时器的编号

clearTimeout(重点)

  • 接受一个参数 就是要清除的定时器或者延时器的编号

注:以上两个方法可以混合使用,但不推荐。

DOM(document object model文档对象模型)

document, 该对象是window的属性。但是因为太重要,所以单独成立一个概念。
它包含着所有操作文档的方法。

获取元素

在JS中操作元素,必须要先获取到元素
  • 根据ID获取元素

    • document.getElementById(id)
      该方法用于根据ID获取元素 ID是HTML标签的属性 应当具备唯一性
    • 返回值:如果有这个元素 就可以得到该元素对象。如果没有,就是null。
  • 根据标签名获取元素

    • document.getElementsByTagName(tagName)
    • 返回值: 集合对象(类数组对象)
  • 根据name属性获取元素

    • document.getElementsByName(name)
    • 返回值: 集合对象(类数组对象)
  • 根据选择器获取元素

    • document.querySelector(selector)
    • 返回值: 元素对象
  • 根据选择器获取多个元素

    • document.querySelectorAll(selector);
    • 返回值: 集合对象(类数组对象)

额外知识点

  • 获取页面卷动值
    • document.documentElement.scrollTop
    • document.body.scrollTop

统一写法: var scrollTop = document.documentElement.scrollTop || document.body.scrollTop

  • 获取页面高度

    • document.body.clientHeight
  • 操作元素的行内样式

    // 设置行内样式
    dom.style.xxx = yyy;
    // xxx 表示对应的css样式属性名 如果用点语法,就需要使用驼峰 如果用方括号语法 则可以不用驼峰 但是一定要加双引号 
    // yyy 表示对应的属性值

    // 驼峰写法
    box.style.backgroundColor = "black";
    // 方括号写法
    box.style["background-color"] = "black";

BOM

Browser Object Model (浏览器对象模型)
体现在代码中,就是window对象。每一个页面都有一个window对象。
它可以得到浏览器的相关信息。
它可以操作浏览器的地址栏
它可以操作浏览器的历史记录

window.innerWidth 视口的宽度
window.innerHeight 视口的高度

window.location.href 该属性是浏览器的地址栏字符串 可以读取 可以设置(跳转页面)
window.location.reload() 该方法用于刷新当前页面
window.history.go() 跳转历史记录 如果值为0 等价于 location.reload(); 该值如果为大于0的数字,表示前进按钮点击的次数 如果值为小于0的数字 表示后退按钮点击的次数
window.history.forward(); 前进一次
window.history.back(); 后退一次
window.navigator.userAgent 浏览器的用户代理字符串 说明这个浏览器的厂商版本等
window.navigator.platform 用户的操作平台
window.open() 该方法用于打开一个新页面
window.close() 该方法用于关闭页面

事件: load scroll resize
load 表示当所有的资源加载完毕之后 会触发的事件
scroll 当浏览器具备滚动条 并且页面的卷动值发生变化的时候会触发 
    document.documentElement.scrollTop 
    document.body.scrollTop
    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
setInterval 该方法用于打开一个定时器 按照时间循环执行代码 
    第一个参数: 函数
    第二个参数: 数字 毫秒值为单位的时间
setTimeout 该方法用于打开一个延时器 让代码推迟一定的时间执行
    第一个参数: 函数
    第二个参数: 数字 推迟的时间毫秒值
这两个的返回值都是数字,专业名称(句柄)。我们刚接触,就暂且理解为编号。
我们可以根据这个编号去停止它们。
停止方式: clearTimeout、clearInterval 分别 清除setTimeout和setInterval的设置的内容

DOM

Document Object Model(文档对象模型)
每一个页面都有一个document对象,它是通过文档对象模型具体化的一个对象。
它可以操作页面中的所有内容。
修改元素样式: 元素.style.backgroundColor = "yellow";
获取元素: 
    document.getElementById() 根据ID获取元素 得到的是对应的ID元素 
    document.getElementsByTagName() 根据标签名获取元素 得到的是对应的标签元素组成的集合
    document.getElementsByName() 根据name属性获取元素 得到的是集合
    document.querySelector() 根据选择器获取元素 得到的是第一个符合该选择器描述的元素
    document.querySelectorAll() 根据选择器获取元素 得到的是所有符合该选择器描述的元素集合

同步、异步

HTML属性

可以分为标准属性与非标准属性(自定义属性)

  • 标准属性 指的是由W3C制定的属性
    • 通用属性 所有标签都有的属性 比如 id class style title等
    • 特有属性 只有一个或者几个标签有的属性 比如 name type checked 等
  • 非标准属性 指的是由程序员自己定义的属性

元素的基本操作

标准属性可以直接通过元素打点获取 打点修改 (或者使用方括号语法也可以) 注意避讳关键字

    // 避讳JS中的class关键字
    元素.className = "abc";
    // 读取name属性值
    var str = 表单元素.name;

非标准属性要通过

  • setAttribute(propName, propValue); 设置、修改属性值
    • propName 表示属性名
    • propValue 表示属性值
  • getAttribute(propName); 获取属性值
    • propName 表示属性名
  • removeAttribute(propName); 移除属性(从HTML标签身上移除)
    • propName 表示属性名

节点

整个页面是由节点组成的。每一个节点有不同的性质,DOM将它们根据性质分类。

节点的属性

  • nodeType 节点类型 属性值为数字
    • 1 表示元素节点
    • 2 表示属性节点
    • 3 表示文本节点
    • 8 表示注释节点
    • 9 表示文档节点(就一个 document)

获取属性节点 要通过 元素.attributes 来获取到集合 再通过下标获取想要的属性节点

  • nodeName 节点名称 属性值为字符串
    • 元素节点的名称为大写的标签名
    • 属性节点的名称为属性名
    • 文本节点的名称为 #text
    • 注释节点的名称为 #comment
    • 文档节点的名称为 #document
  • nodeValue 节点值
    • 元素节点没有节点值 null
    • 属性节点的节点值就是属性值
    • 文本节点的节点值是文本内容
    • 注释节点的节点值是注释内容
    • 文档节点没有节点值 null

节点的关系

节点关系就两种:父子关系 兄弟关系
  • 父子关系
    • 父找子
      • childNodes 所有的节点
      • children 所有的元素节点
      • firstChild 第一个节点
      • firstElementChild 第一个元素节点
      • lastChild 最后一个节点
      • lastElementChild 最后一个元素节点
    • 子找父
      • parentNode 父节点
  • 兄弟关系
    • nextSibling 下一个兄弟
    • nextElementSibling 下一个元素兄弟
    • previousSibling 前一个兄弟
    • previousElementSibling 前一个元素兄弟

节点的操作(重要)

  • 创建节点

    • document.createElement(标签名字符串)
    • document.createTextNode(文本内容)
        // 创建一个div元素节点
        var div = document.createElement("div");
        // 创建文本节点
        var textNode = document.createTextNode("我是一个通过JS脚本创建出来的文本节点");
        // 这样的节点只在JS环境中存在,还没有到DOM树上去.所以叫做"孤儿节点"
    
  • 追加节点

    • 父元素.appendChild(子元素)
      • 子元素会被追加到父元素的最后,作为lastChild节点
        // 创建一个节点
        var div = document.createElement("div");
        // 向父元素中追加一个节点
        var dom = document.getElementById("#box");
        dom.appendChild(div);
    
  • 插入节点

    • 父元素.insertBefore(newChild, oldChild)
      • newChild是新元素
      • oldChild是父元素的已有元素
      • newChild会插入到oldChild的前一个位置
        // 创建一个节点
        var div = document.createElement("div");
        // 获取父元素
        var box1 = document.getElementById("box1");
        // 插入到box1之前
        document.body.insertBefore(div, box1);
    
  • 替换节点

    • 父元素.replaceChild(newChild, oldChild)
      • newChild是替换上的元素
      • oldChild是被替换的元素
        // 创建一个节点
        var div = document.createElement("div");
        // 获取树上的元素
        var box1 = document.getElementById("box1");
        // 替换box1
        document.body.replaceChild(div, box1);  
    
  • 克隆节点

    • 元素.cloneNode(boolean);

      • boolean是一个布尔值 决定是否克隆子元素 如果为真则克隆子元素 否则不克隆 默认是false
        // 选中一个节点
        var node = document.querySelector(".one");
        // 复制该节点得到新节点
        var cloneNode = node.cloneNode(true);
    
  • 删除节点

    • 元素.remove() 让调用remove方法的元素 下树
    • 父元素.removeChild(子元素) 让父元素中的子元素下树
        // 获取元素
        var box2 = document.getElementById("box2");
        // 元素自己下树
        box2.remove();
    
        // 获取元素
        var box2 = document.getElementById("box2");
        // 让body把box2删掉
        document.body.removeChild(box2);
    

复习

补充内容

window.onresize事件  它会在浏览器的窗口尺寸被改变时触发 它属于高频率事件
window 对象 是BOM对象本体 
location/history/navigator/document 这几个都是window对象的属性 都属于BOM的属性 
其中 document是对文档的具体对象。单独叫做DOM对象。
setInterval/setTimeout 定时器/延时器 它们可以让代码异步执行 
document.body => body元素
document.documentElement => html元素
document.head => head元素
document.title => 当前页面的标题文本

节点

节点分类 一共12种节点,我们需要记忆的就是1 2 3 8 9 
1 元素节点
2 属性
3 文本
8 注释
9 文档
节点属性
    nodeType 节点类型对应的数字
    nodeName 节点名称
        元素 => 标签名大写字符串
        属性 => 属性名
        文本 => #text
        注释 => #comment
        文档 => #document
    nodeValue 节点值
        元素没有节点值  null
        属性的节点值就是属性值
        文本的节点值就是 文本内容字符串
        注释的节点值就是 注释内容字符串
        文档的节点值就是 null
节点的关系
    父子关系
        父找子
            childNodes 所有节点的集合 注意,空白折叠现象压缩出来的空白符在有些浏览器中会被当做文本节点来处理
            children 所有元素节点的集合
            firstChild 第一个子节点
            firstElementChild 第一个子元素
            lastChild 最后一个子节点
            lastElementChild 最后一个子元素
        子找父
            parentNode
    兄弟关系
        nextSibling 下一个节点兄弟
        nextElementSibling 下一个元素兄弟
        previousSibling 上一个节点兄弟
        previousElementSibling 上一个元素兄弟
节点的操作
    document.createElement(标签名称字符串) 创建元素
    document.createTextNode(文本内容) 创建文本
    父元素.appendChild(子元素) 将子元素追加到父元素中  作为lastChild
    父元素.insertBefore(新子元素, 旧子元素) 将新子元素插入到父元素的旧子元素之前
    父元素.replaceChild(新子元素, 旧子元素) 新子元素会代替旧子元素 旧子元素会下树
    父元素.removeChild(子元素) 将子元素从父元素的子节点列表中移除
    元素.remove() 将元素移除
    元素.cloneNode(布尔) 元素被克隆一份 返回克隆体 如果布尔为真 则会克隆子元素 布尔为假 则不克隆子元素 只克隆元素本身

document.getElementById() => 返回值是元素对象
document.getElementsByTagName() => 返回值是集合(类数组对象)
document.getElementsByName() =>  返回值是集合(类数组对象)
document.getElementsByClassName() => 返回值是集合(类数组对象)
document.querySelector() => 返回的是元素
document.querySelectorAll() => 返回值是集合(类数组对象)

元素的基本操作:
打点或者使用方括号进行属性值的设置 修改 读取
规则:
只要这个元素拥有该HTML标准属性 就可以直接通过点语法或者方括号语法进行操作(注意避讳关键字)
如果这个属性是程序员自己定义的属性
setAttribute(propName, propValue);
getAttribute(propName);
removeAttribute(propName);

复习

快捷属性

因为在JS中,我们要操作DOM结构,需要得到CSS的样式,所以,一些常用的样式值,就被定义成快捷获取方式
  • clientWidth 内容宽 + 左右padding
  • clientHeight 内容高 + 上下padding
  • offsetWidth 内容宽 + 左右padding + 左右border
  • offsetHeight 内容高 + 上下padding + 上下border
  • clientLeft 左边框宽度
  • clientTop 上边边框宽度

快捷位置关系

  • offsetParent 获取元素的祖先元素中第一个具备定位属性的元素 如果一个元素没有定位父元素 offsetParent就是body
  • offsetLeft 获取元素左边框外到定位父元素的左边框内(IE8 中 到定位父元素的边框外)
  • offsetTop 获取元素上边框外到定位父元素的边框内(IE8中到定位父元素的边框外)

ES5的数组方法

  • forEach 迭代器方法 其实就是循环

    • 参数是函数 函数会执行多次 要看数组的长度 这个函数有三个参数
      • 数组的成员
      • 数组的下标
      • 数组本身
      • this指向window
  • map 迭代器方法 根据参数的返回 生成一个对应的数组

    • 参数是函数 函数会执行多次 要看数组的长度 这个函数有三个参数
      • 数组的成员
      • 数组的下标
      • 数组本身
      • this指向window
    • 返回值 根据函数的返回值 生成的新数组
  • filter 过滤方法 接受一个函数作为参数 函数的返回值如果为真 则过滤该成员 否则不过滤

    • 参数是函数 函数会多次执行 要看数组的长度 这个函数有三个参数
      • 数组的成员
      • 数组的下标
      • 数组本身
      • this指向window
      • 返回值 是布尔值 如果该值为真 则当前成员会被过滤到新数组中
    • 返回值 新数组
  • some 判定方法 接受一个函数作为参数 函数会多次执行 依次对每一个数组成员进行执行

    • 参数是函数
      • 数组的成员
      • 数组的下标
      • 数组本身
      • this指向window
      • 返回值 是布尔值 如果该值为真 则停止循环
    • 返回值 是布尔值 如果为真 则表示数组中是具备参数函数描述的成员的 如果为假 说明没有任何成员符合描述
  • every 判定方法 接受一个函数作为参数 函数会多次执行 依次对每一个数组成员进行执行

    • 参数是函数
      • 数组的成员
      • 数组的下标
      • 数组本身
      • this指向window
      • 返回值 是布尔值 如果该值为真 则停止循环
    • 返回值 是布尔值 如果为真 则表示数组中所有成员都符合参数函数描述 如果为假 说明有成员不符合描述

事件对象

函数可以定义,可以调用。
定义的时候可以定义参数 叫形参 调用的时候可以传递参数 传递的参数叫实参
事件函数是我们定义的,所以形参可以随便写 名字随便起 调用是触发事件的时候 由这个元素自身去调用 事件触发时也会产生很多的信息,这些信息由浏览器收集并封装成一个对象 这个对象被传递到咱们定义的事件函数中 我们就可以在这个对象身上获取到产生的那些信息
  • 通用
    • altKey 是否按下了alt键
    • ctrlKey 是否按下了ctrl键
    • shiftKey 是否按下了shift键
  • 鼠标事件
    • offsetX 表示鼠标在元素内部到元素左边的位置(边框内)
    • offsetY 表示鼠标在元素内部到元素顶部的距离(边框内)
    • clientX 表示鼠标在视口内的到视口左边的位置
    • clientY 表示鼠标在视口内的到视口上边的位置
    • pageX 表示鼠标在页面内的到页面左边的位置
    • pageY 表示鼠标在页面内的到页面上边的位置
  • 键盘事件
    • key 表示对应的按下的字符
    • keyCode 表示按下的键的字符对应的ASCII码

获取非行内样式

- 在高级浏览器中 getComputedStyle 
    - 该方法是window的属性  接受一个元素作为参数
        - 参数是元素
        - 返回值是该元素的样式对象 我们可以通过点语法或者方括号语法进行属性的读取 如果是点语法 要注意驼峰写法 如果是方括号 注意加双引号或者单引号
- 在IE7 8中 元素.currentStyle
    - 这是一个元素的属性 返回的也是CSS样式对象

事件绑定方式

  • DOM0级
    • 绑定

      • 元素.on事件类型 = 事件函数
      • 只能够绑定一个事件 因为它是对属性进行赋值
    • 移除

      • 元素.on事件类型 = null

我们都知道,一个对象的属性只能够保存一个值。 如果对一个对象属性进行多次赋值,后面赋值的属性会替换掉前面的属性

  • DOM2级

    • 绑定

      • dom.addEventListener(type, handler, boolean)
        • type: 事件类型字符串 不带on
        • handler: 事件处理函数
        • boolean: 布尔值 决定绑定到捕获阶段还是冒泡阶段 默认是false false表示冒泡
    • 结论: 可以通过addEventListener方法进行多个事件函数的绑定 执行时是按照代码的书写顺序执行 因为代码的书写顺序决定了绑定顺序

    • 移除

      • document.removeEventListener(type, handler, boolean);
        • type: 事件类型字符串 不带on
        • handler: 事件处理函数 一定要保证函数地址是绑定的那个
        • boolean: 布尔值 决定移除的是捕获阶段还是冒泡阶段 默认是false false表示冒泡
    • 结论: 第二个参数是要移除的函数 函数是引用类型 引用类型的比较的是地址 所以一定要保证 移除的函数是当初绑定的那个函数本身

  • IE中的高级绑定方式(非DOM2级)

IE中没有实现DOM2级

  • 绑定方式:
    • dom.attachEvent(type, handler);
      • type: 事件类型字符串 带on
      • handler: 事件处理函数
      • 没有第三个参数 意味着不能够绑定到捕获阶段
        特点: 可以对同一个元素绑定多个同类型事件的处理函数 执行起来是倒着执行 先绑定的后执行 后绑定的先执行
  • 移除方式:
    • dom.detachEvent(type, handler);
      • type: 事件类型字符串 带on
      • handler: 事件处理函数 要注意函数的地址问题

事件流程

  • 事件冒泡:当点击时 事件从最精确的元素 一层一层往上触发 直到最顶层元素 这个过程叫做事件冒泡
  • 事件捕获:当点击时 事件从最顶层元素 一层一层的往下触发 直到最精确元素 这个过程叫做事件捕获
    • 最精确元素: 鼠标点到谁 谁就是最精确元素
    • 最顶层元素:
      • 高级浏览器 最顶层元素是window
      • IE中 最顶层元素是 document

阻止冒泡

  • 高级浏览器中 可以通过e.stopPropagation() 进行阻止事件的冒泡

        // 高级浏览器中
        // box1是box2的父元素
        var box1 = document.querySelector(".box1");
        var box2 = document.querySelector(".box2");
    
        box1.onclick = function() {
            console.log("这是BOX1");
        }
        box2.onclick = function(e) {
            e.stopPropagation();
            console.log("这是BOX2");
        }
    
  • IE浏览器中 可以通过e.cancelBubble = true 进行阻止事件的冒泡

       // IE浏览器中
       // box1是box2的父元素
       var box1 = document.querySelector(".box1");
       var box2 = document.querySelector(".box2");
    
       box1.onclick = function() {
           console.log("这是BOX1");
       }
       box2.onclick = function(e) {
           var e = e || window.event;
           e.cancelBubble = true;
           console.log("这是BOX2");
       }
    

停止默认行为

浏览器的一些事件中,带有一些默认行为 比如a标签的点击事件中 会带有跳转页面的行为 表单的点击事件中 带有提交的默认行为 滚轮事件中 带有改变页面卷动值的默认行为

  • 高级浏览器中 可以通过 e.preventDefault() 阻止默认行为

        // 获取元素
        var a = document.getElementsByTagName("a")[0];
        // 设置点击事件
        a.addEventListener("click", function(e) {
            console.log("点击了a标签1111");
            e.preventDefault();
        }, false);
    
  • IE浏览器中 可以通过 e.returnValue = true; 阻止默认行为

        // 获取元素
        var a = document.getElementsByTagName("a")[0];
        // 设置点击事件
        a.attachEvent("onclick", function(e) {
            console.log("点击了a标签1111");
            e.returnValue = true;
        });
    
  • DOM0级事件绑定方式中,可以通过return false进行阻止默认行为

       // 获取元素
       var a = document.getElementsByTagName("a")[0];
       // 设置点击事件
       a.onclick = function() {
           return false;
       }
    

复习

事件绑定

  • IE
    • DOM0级 元素.on事件类型 = 事件处理函数
    • 高级绑定方式 元素.attachEven(“on事件类型”, 事件处理函数)
  • 高级浏览器
    • DOM0级 元素.on事件类型 = 事件处理函数
    • DOM2级 元素.addEventListener(事件类型, 事件处理函数, 布尔值)

事件绑定的区别

  • IEDOM0级
    • 只能够绑定一个函数
    • 事件对象不会传递到事件函数中
    • 要通过window.event来获取
    • this指向这个元素
  • IE高级绑定方式
    • 可以绑定多个事件函数
    • 执行的时候是反着执行 先绑定的后执行 后绑定的先执行
    • 无法绑定到捕获阶
    • 会把事件对象传递到事件处理函数中 this指向window
  • 高级浏览器DOM0级
    • 只能够绑定一个函数
    • 事件对象不会传递到事件函数中
    • 浏览器会把事件对象传递到函数中
    • this指向这个元素
  • 高级浏览器DOM2级
    • 可以绑定多个事件函数
    • 绑定顺序决定执行顺序
    • 浏览器会把事件对象传递到函数中
    • this指向绑定事件的元素

事件流程

事件捕获: 事件从最顶层元素开始触发,一层层向下,直到最精确元素
事件冒泡: 事件从最精确元素开始触发,一层层向上,直到最顶层元素
处于目标: 在它身上的事件是不区分捕获和冒泡的

阻止冒泡

  • IE浏览器
    e.cancelBubble = true
  • 高级浏览器
    e.stopPropagation()

阻止默认行为

  • IE浏览器
    e.returnValue = false
  • 高级浏览器
    e.preventDefault()

注: 如果是DOM0级绑定方式 则可以使用 return false进行默认行为的阻止
默认行为: a标签的点击时跳转 鼠标滚轮滚动时的造成页面下滑

事件委托(事件代理)

思想: 将原本子元素做的事情,委托给父元素去做。将事件绑定给父元素,父元素事件触发时,通过e.target判定触发事件的元素。决定执行对应代码。
    // 1 获取元素 获取不可能被移除的父元素
    var tbody = document.querySelector("tbody");
    // 2 给tbody绑定事件
    tbody.onclick = function(e) {
        // e.target 这个属性指向触发事件的元素
        console.log(e.target)
        // 判定 点击到的是什么  
        if (e.target.className === "del") {
            // 点击到的是移除按钮 
            e.target.parentNode.remove();
        }
    }

正则表达式

正则表达式是专门针对字符串而定义出来。
它是一组规则 通过特定的字符来表示不同的字符串类型

正则表达式的定义

  • 字面量定义 /正则表达式/修饰符

    • /\d+/g
  • 构造函数定义 RegExp(正则表达式, 修饰符);

    • new RegExp(“abc”, g)
      • 第一个参数是正则表达式的表达体
      • 第二个参数是正则表达式的修饰符
  • 转义字符

    • \d 所有的数字
    • \D 所有的非数字
    • \w 所有的数字字母下划线
    • \W 所有的非数字字母下划线
    • \s 所有的空白符
    • \S 所有的非空白符
  • 特殊字符(元字符)

    • . 除了回车和换行之外的其它所有内容
    • () 分组 分组内是一个整体
    • [] 范围
      • [a-z]
      • [A-Z]
      • [0-9]
      • [0-9A-Za-z]
    • {} 数量
      • {10} 限定十个 不能多也不能少
      • {3,5} 最少三个 最多五个
      • {1,} 最少一个 最多无穷个
    • ? 零个或一个
      • 一个或任意个
      • 零个或任意个
    • | 或者

字符串方法replace

  • replace(drop, add);
    • drop 被替换下的内容
      • 可以是字符串
      • 可以是正则表达式
    • add 被替换上的内容
      • 可以是字符串
      • 可以是函数
        • 函数的返回值是被替换上的内容
        • 函数的参数
          • 第一个表示匹配到的内容
          • 第二个表示匹配到的内容的索引
          • 第三个表示原字符串
          • 如果正则表达式中有圆括号,则圆括号的内容会一一对应放在第二个参数位置及后面位置 原来的第二个参数和第三个参数会向后推移

复习

正则表达式

正则表达式的初始化方式
字面量 => /正则表达式/修饰符
构造函数 => new RegExp(正则表达式, 修饰符); 注:字符串也有转义字符 正则表达式也有转义字符

- \d 所有的数字
- \D 所有的非数字
- \s 所有的空白符
- \S 所有的非空白符
- \w 所有的数字、字母、下划线
- \W 所有的非数字、字母、下划线

特殊字符

- () 分组
- [] 范围区间  [a-z0-9A-Z]
- {} 数量
- * 任意个
- + 至少一个
- ? 0个或1个
- . 除了回车和换行之外的任意字符
- | 或者
- ^ 如果出现在[]中 则表示方括号里的内容都不能出现 如果出现在[]之外 必须要出现在正则表达式的第一位 表示开头必须是指定的内容
- $ 表示结尾

修饰符
g  全局匹配
i  忽略大小写
m  允许多行匹配

方法
test 用于测试字符串是否符合正则表达式的描述
exec 用于对字符串执行,会返回一个数组 数组的成员是这一次匹配到的内容 index属性表示匹配到的内容第一个字符的下标 input表示原字符串 如果没有匹配到则会返回null 如果正则表达式有全局修饰符 则每一次调用都会查询下一个位置
字符串方法
replace(arg1, arg2);
    arg1: 被替换下的内容
        可以是字符串
        可以是正则表达式
    arg2: 被替换上的内容
        可以是字符串 
        可以是函数
            函数的返回值会被作为替换上的内容
            函数的参数
                如果正则表达式中没有() 则一共三个参数 
                    匹配到的内容
                    匹配到的内容的第一个字符的下标位置
                    原字符串
                如果正则表达式中有() 则参数个数要参照()的数量
                    匹配到的内容
                    第一个()匹配到的内容
                    第二个()匹配到的内容
                    ……
                    匹配到的内容的第一个字符的下标位置
                    原字符串

ES6

块级作用域

  • ES6中的块级作用域 指的是 {} 之间可以生成作用域

let关键字

通过let定义的变量 遵循ES6的块级作用域规范

  • 块级作用域
    if (true) {
        var a = 10;
        let b = 11;
        console.log(a); // 10
        console.log(b); // 11
    }
    console.log(a); // 10
    console.log(b); // 报错
  • 没有变量声明的提升
    console.log(a);  // undefined 因为声明提升
    var a = 10;
    console.log(b); // 报错
    let b = 11; 
    console.log(b);
  • 不可以重复定义同名变量
    var a = 10;
    var a = 11;
    console.log(a); // 可以输出11

    let a = 10;
    let a = 11; // 报错 Uncaught SyntaxError: Identifier 'a' has already been declared
  • let定义的变量不会自动注册到window身上
    var a = 10; // var出来的全局变量会被自动注册成window的属性
    console.log(window.a); // 10

    let a = 10; 
    console.log(a); // 10
    console.log(window.a); // undefined

    console.log(a); // 在不声明a时 会报错
    console.log(window.a); // 有就用 没有就undefined 
  • for循环的不同
    var arr = new Array(5).fill(0);
    for (let i = 0; i < arr.length; i++) {
        arr[i] = function() {
            console.log(i);
        }
    }
    // 如果上面定义循环变量i时使用的是var 则下面代码执行时都输出5 如果用let定义变量 则如下执行
    arr[0](); // 0
    arr[1](); // 1
    arr[2](); // 2
    arr[3](); // 3
    arr[4](); // 4

const关键字

用于定义常量
命名规范: 推荐全部大写 如果出现了单词需要使用_进行分割
ex: const HELLO_WORLD = 10;

  • 值一旦被赋值 不能使用等号改
    const A = 10;
    A = 11; // 报错: Uncaught TypeError: Assignment to constant variable.
    /* 如果常量保存的是引用类型 可以使用方括号语法和点语法进行属性的修改 */
    const OBJ = {};
    OBJ = 123; // 会报错
    OBJ["hello"] = 123;

注:const定义出来的常量也遵守块级作用域 也没有声明提升 也不会注册到window身上 千万不要使用const来定义循环变量

对象的定义简化

对象的定义 可以用字面量 可以用构造函数 ES6中 针对对象的定义 进行了简化

  • 如果对象的属性名和属性值一致 则可以只使用一个
    /* 以前的定义变量 */
    var color = "red"; 
    var obj = {
        color: color
    }

    // 简化后
    var obj = {
        color
    }
    console.log(obj);
  • 现在可以在对象属性定义时通过方括号进行开辟JS执行环境
    var he = "he";
    var llo = "world";
    var obj = {
        hello: "",
        [he + llo]: ""
    }
  • 定义方法时 可以省略 : function
     var obj = {
        a: 1,
        hello: function() {
            console.log("hello");
        },
        world() {
            console.log("world");
        }
    }
    console.log(obj.a);
    obj.hello(); // hello
    obj.world(); // world

解构语法

提到解构,就不得不提封装

  • 封装 封装指的是将内容包装在一起

    • 代码封装 使用函数
    • 数据封装 使用数据结构 目前为止我们学习的数据结构一共有两种 分别是数组和对象
  • 解构 指的是解除构造\解除结构(换句话说就是,你封装的,我给你拆了)

解构数组

  • 人工解构
    // 定义数组
    var arr = [1, 2, 3, 4, 5];
    // 人工解除结构
    var a = arr[0];
    var b = arr[1];
    var c = arr[2];
    var d = arr[3];
    var e = arr[4];
  • ES6语法解构
    // 定义数组
    var arr = [1, 2, 3, 4, 5];
    // 解构语法
    var [a, b, c, d, e] = arr;

解构对象

  • ES6语法解构
    // 解构对象
    var obj = {
        username: "zhangsan",
        password: "123321",
        dog: {
            name: "xiaobai"
        }
    }
    var {password, username, dog} = obj;
    console.log(username, password, dog);

注: 数组解构,是用下标一一对应,所以要注意顺序。 对象解构,是使用属性名对应,所以不用注意顺序,但是要注意属性名是否对应。

多行字符串

在ES6之前 所有的字符串只能是单行字符串 单引号与双引号定义的都是单行

  • 定义语法
    • ES6定义多行字符串方式 ``
    • 按键位置: 横向数字键1左侧 tab键上侧 esc键下方
  • 插值语法
    • ${}
      注: ${}内是一个JS执行环境,可以放变量,可以放表达式,可以调用方法
    var str = `
        <div>
            <div class="box1">${username}
            </div>
            <div class="box1">${password}
            </div>
            <div class="box1">${email}
            </div>
        </div>
    `;

函数中的this

function定义的函数中的this,是可以变化的,遵循的规则是: 谁调用就指向谁, 如果没有明确的调用者,则指向window

  • 会变化的this
    
    function demo() {
        console.log(this);
    }

    // 自己执行 
    demo(); // window

    document.onclick = demo; // document

    var obj = {
        demo
    }

    obj.demo(); // obj

    setInterval(demo, 1000); // window
    setTimeout(demo, 1000); // window

改变函数中this指向的方法

这三个都是函数的方法

  • call
    call可以调用函数 它的作用是执行函数并改变函数中的this指向 如果原函数需要参数 需要往call的参数列表中传递 第一个参数是this 往后的每一个参数是原函数所需参数
    function sum(a, b) {
        console.log(this);
        console.log(a, b);
    }

    sum.call(); // 不传递参数时 this指向window a和b 都是undefined
    sum.call(document);//  this指向了document a 和 b都是undefined
    sum.call(document.body, 1);// this指向body a时1 b是undefined
    sum.call(document.body, 1, 3);// this指向body a时1 b是3
  • apply
    apply可以调用函数 它的作用是执行函数并改变函数中的this指向 如果原函数需要参数 需要往apply的参数列表中传递 第一个参数是this 第二个参数是数组 数组中的每一个成员是原函数所需的参数 按照数组顺序一一对应
    function sum(a, b) {
        console.log(this);
        console.log(a, b);
    }
    sum.apply(); // 不传递参数时 this指向window a和b 都是undefined
    sum.apply(document); // this指向了document a 和 b都是undefined
    sum.apply(document, [1]); // this指向了document a 是 1 b 是undefined
    sum.apply(document, [1, 3]); // this指向了document a 是 1 b 是 3
  • bind
    bind 是ES5中新增的方法 作用是在定义的时候改变this指向(其实是返回了一个新的函数)
    function sum(a, b) {
        console.log(this);
        console.log(arguments);
    }
    // 调用bind方法
    var fun = sum.bind(document, 1, 2, 0.4, 0.5, 0.6);
    // fun是一个函数 
    fun(3, 4, 5, 6, 7);
    console.log(sum === fun); // false

箭头函数

ES6中新增的一种函数定义方式
箭头函数 var name = () => {}

  • demo
    var fun = () => {
        console.log("hello 我是一个箭头函数");
    }
    fun(); // hello 我是一个箭头函数
    console.log(typeof fun); // function
  • 箭头函数中的this
    箭头函数中的this 只有在定义箭头函数时能够确定 而且一旦确定再也不会更改
    let fun = () => {
        console.log(this);
    }
    fun(); // window
    document.onclick = fun; // 依然是window
    let obj = {
        fun
    }
    obj.fun(); // window
    fun.call(document.body); // window
    fun.apply(document.documentElement); // window
    var fun1 = fun.bind(document);
    fun1(); // window

总结:经过各种测试 我们发现无论如何 箭头函数中的this是不会发生变化的

  • 函数的参数默认值
    function fun(a = [], b = {}) {
        console.log(a, b);
    }
    fun(); // 不传递参数 但是因为在定义形参时 通过赋值语法进行了默认值的赋值 所以依然可
    fun(0); // 一旦传递了参数 不论传递的是什么 传递了值的参数 将不会再使用默认值
    fun("a0", "b1");
    箭头函数中依旧如上写法
  • 函数中没有arguments
    let fun = () => {
        console.log(arguments); 
    }
    fun(); // 报错 
  • 箭头函数的简写形式
    • 如果参数只有一个 那么可以省略圆括号
    • 如果函数体中只有一条代码并且还是返回值 则可以省略大括号 和return
    var fun = x => x * x * x * x;
    var result = fun(5);
    console.log(result); // 625

拓展语法(…)

  • 作用1 作为函数的参数收集器
    // ...语法作用之一: 获取参数为数组
    let fun = (...a) => {
        console.log(a);
    }
    fun(); 
    fun(1); 
    fun(1, 2); 
    fun(1, 2, 3); 
  • 作用2 解构时使用
    var arr = "abcdefg".split("");
    console.log(arr); // ["a","b","c","d","e","f","g"]
    var [a,b,c, ...d] = arr;
    console.log(a, b, c); // a b c
    console.log(d); // ["d","e","f","g"]
  • 作用3 传递参数时使用
    var arr = "abcdefg".split("");
    var [a,b,c, ...d] = arr;
    console.log(arr);
    console.log(d);
    // 将arr数组中最后一项 “g”去掉 并将d数组中 ["d", "e", "f", 
    arr.splice(arr.length - 1, 1, ...d);
    console.log(arr); // ["a","b","c","d","e","f","d","e","f","g"]

额外补充

  • 能力检测
    // getComputedStyle  能力检测 利用的就是从对象身上读取属性 无论如何都不会报错的特点
    if (window.getComputedStyle) {

    } else {

    }
  • bind方法的实现
    // 定义一个函数 
    function sum(a, b) {
        console.log(this);
        console.log(arguments);
    }
    // 模拟bind方法
    function bind(sum, target) {
        var arr = [].slice.call(arguments, 2);
        return function() {
            var arr1 = [].slice.call(arguments);
            sum.apply(target, arr.concat(arr1));
        }
    }
    var fun = bind(sum, document.body, 1, 26, 7, 8, 9);
    fun(10, 11, 12, 13);  // this指向document.body 参数为 [1, 26, 7, 8, 9, 10, 11, 12, 13]

ion sum(a, b) {
console.log(this);
console.log(arguments);
}
// 调用bind方法
var fun = sum.bind(document, 1, 2, 0.4, 0.5, 0.6);
// fun是一个函数
fun(3, 4, 5, 6, 7);
console.log(sum === fun); // false

# 箭头函数
ES6中新增的一种函数定义方式
箭头函数 **var name = () => {}**

- demo
```JavaScript
    var fun = () => {
        console.log("hello 我是一个箭头函数");
    }
    fun(); // hello 我是一个箭头函数
    console.log(typeof fun); // function
  • 箭头函数中的this
    箭头函数中的this 只有在定义箭头函数时能够确定 而且一旦确定再也不会更改
    let fun = () => {
        console.log(this);
    }
    fun(); // window
    document.onclick = fun; // 依然是window
    let obj = {
        fun
    }
    obj.fun(); // window
    fun.call(document.body); // window
    fun.apply(document.documentElement); // window
    var fun1 = fun.bind(document);
    fun1(); // window

总结:经过各种测试 我们发现无论如何 箭头函数中的this是不会发生变化的

  • 函数的参数默认值
    function fun(a = [], b = {}) {
        console.log(a, b);
    }
    fun(); // 不传递参数 但是因为在定义形参时 通过赋值语法进行了默认值的赋值 所以依然可
    fun(0); // 一旦传递了参数 不论传递的是什么 传递了值的参数 将不会再使用默认值
    fun("a0", "b1");
    箭头函数中依旧如上写法
  • 函数中没有arguments
    let fun = () => {
        console.log(arguments); 
    }
    fun(); // 报错 
  • 箭头函数的简写形式
    • 如果参数只有一个 那么可以省略圆括号
    • 如果函数体中只有一条代码并且还是返回值 则可以省略大括号 和return
    var fun = x => x * x * x * x;
    var result = fun(5);
    console.log(result); // 625

拓展语法(…)

  • 作用1 作为函数的参数收集器
    // ...语法作用之一: 获取参数为数组
    let fun = (...a) => {
        console.log(a);
    }
    fun(); 
    fun(1); 
    fun(1, 2); 
    fun(1, 2, 3); 
  • 作用2 解构时使用
    var arr = "abcdefg".split("");
    console.log(arr); // ["a","b","c","d","e","f","g"]
    var [a,b,c, ...d] = arr;
    console.log(a, b, c); // a b c
    console.log(d); // ["d","e","f","g"]
  • 作用3 传递参数时使用
    var arr = "abcdefg".split("");
    var [a,b,c, ...d] = arr;
    console.log(arr);
    console.log(d);
    // 将arr数组中最后一项 “g”去掉 并将d数组中 ["d", "e", "f", 
    arr.splice(arr.length - 1, 1, ...d);
    console.log(arr); // ["a","b","c","d","e","f","d","e","f","g"]

额外补充

  • 能力检测
    // getComputedStyle  能力检测 利用的就是从对象身上读取属性 无论如何都不会报错的特点
    if (window.getComputedStyle) {

    } else {

    }
  • bind方法的实现
    // 定义一个函数 
    function sum(a, b) {
        console.log(this);
        console.log(arguments);
    }
    // 模拟bind方法
    function bind(sum, target) {
        var arr = [].slice.call(arguments, 2);
        return function() {
            var arr1 = [].slice.call(arguments);
            sum.apply(target, arr.concat(arr1));
        }
    }
    var fun = bind(sum, document.body, 1, 26, 7, 8, 9);
    fun(10, 11, 12, 13);  // this指向document.body 参数为 [1, 26, 7, 8, 9, 10, 11, 12, 13]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值