JavaScript视频 --李立超

JavaScript简介

起源
95年,主要用于处理网页中的前端验证 – 检查用于输入的内容是否符合一定的规则
比如:

  • 用户名长度
  • 密码的长度
  • 邮箱的格式等
    现在常常用作页面的一些动态效果的展示:
    JavaScript视频 --李立超_第1张图片
  • 甚至是一款 小游戏都可以使用JavaScript来完成
    JavaScript视频 --李立超_第2张图片
  • Node.js用在服务器上面
  • JS的标准命名ECMAScript,是网景公司把JavaScript捐出来了以后规定命名
  • ECMAScript是一个标准,这个标准需要由各个浏览器厂商来实现。
  • 不同的浏览器使用的引擎是不一样的,
    JavaScript视频 --李立超_第3张图片
  • JavaScript实现应该由以下三个部分组成:① ECMAScript ② DOM ③ BOM
  • DOM 操作网页
  • BOM 操作浏览器

JS特点

  • 解释型语言 – 不用编译, 写完直接运行
  • 类似于C和Java的语法结构
  • 动态语言 – 变量随便什么类型
  • 基于原型的面向对象

JS基础

JS的HelloWorld

  • JS代码的执行是从上往下一行一行执行的
  • JS代码需要编写到script标签中
  • 控制浏览器弹出一个警告框 – alert(" ")
  • 让计算机在页面中输入一个内容 – document.write(" ")
  • 向控制台输出一个内容 – console.log(" ")
<!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">
    <title>Document</title>
    <!-- JS代码需要编写到script标签中 -->
    <script>
        /*
            控制浏览器弹出一个警告框
            alert("这是我的第一行JS代码");
        */
        
        /*
            让计算机在页面中输入一个内容
            document.write() 可以向我们的body中输出一个内容
            document.write("看我出不出来~~~")
        */ 

        /*
            向控制台输出一个内容
            console.log("")
            console.log("你猜我在哪里出来呢?")
        */
        // console.log("你猜我在哪里出来呢?")
    </script>
</head>
<body>
    
</body>
</html>

JS编写位置

  • 可以编写到标签的内部,比如 button的onclick,a标签的href 等,其他的类似。
    不推荐,结构与行为耦合,不方便维护!
<body>
    <!-- 可以将js代码编写到标签的onclick属性中 
         当我们点击按钮的时候,js代码才会执行
         虽然可以写在标签的属性中,但是他们属于结构与行为耦合,不方便维护,不推荐使用
    -->
    <button onclick="alert('讨厌,你点我干吗~~')">点我一下</button>
</body>
<body>
    <!-- 
        可以将js代码写到超链接的href属性中,这样当点击超链接时,会执行js代码
     -->
     <a href="javaScript:alert('让你点你就点')">让你点你就点</a>
     <!-- 希望超链接点完以后没有任何反应 -->
     <a href="JavaScript:;">你也点我一下</a>
</body>
  • 写在script标签当中
    <!--  
        可以将js代码编写到script标签
    <script>
        alert("我是script标签中的代码!!!")
    </script>
    -->
  • 最佳方式,写在外部文件中,.js文件, 通过script标签中src引入
    <script src="script.js">
    </script>

注意点:

  • script标签一旦用于引入外部文件了,就不能在编写代码了,即使编写了,浏览器也会忽略。如果需要则可以在创建一个新的script标签用于编写内部代码。
  • 记住JS代码是从上往下执行的,所以,运行哪一个JS文件,观察从上到下的位置

总代码实现:

<!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">
    <title>JS的编写位置</title>
    <!-- 可以将js代码编写到外部js文件中,然后通过script标签引入 
         写到外部文件中可以在不同的页面中同时引用,也可以利用到浏览器的缓存机制当中
         推荐使用的方式!
    -->
    <!-- script标签一旦用于引入外部文件了,就不能在编写代码了,即使编写了浏览器也会忽略
         如果需要则可以在创建一个新的script标签用于编写内部代码
    -->
    <script src="script.js">
        // alert("我是内部的js标签");
    </script>
    <script>
        alert("我是内部的JS代码")
    </script>
    <!--  
        可以将js代码编写到script标签
    <script>
        alert("我是script标签中的代码!!!")
    </script>
    -->
</head>
<body>
    <!-- 可以将js代码编写到标签的onclick属性中 
         当我们点击按钮的时候,js代码才会执行
         虽然可以写在标签的属性中,但是他们属于结构与行为耦合,不方便维护,不推荐使用
    -->
    <button onclick="alert('讨厌,你点我干吗~~')">点我一下</button>
    <!-- 
        可以将js代码写到超链接的href属性中,这样当点击超链接时,会执行js代码
     -->
     <a href="javaScript:alert('让你点你就点')">让你点你就点</a>
     <!-- 希望超链接点完以后没有任何反应 -->
     <a href="JavaScript:;">你也点我一下</a>
</body>
</html>

基本语法

重点:

  • 注释: ① 多行注释 /**/ ② 单行注释 // 注释中的内容不会被执行,但是可以在源代码中查看, 要养成写注释的习惯
  • JS中严格区分大小写,Html中是不区分大小写
  • JS中每一条语句以分号(;)结尾
    - 如果不写分号,浏览器会自动添加,但是会消耗一些系统资源,
    - 而且有些时候,浏览器会加错分号,所以在开发中分号必须写
  • JS中会忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化
    - 可以写的会比较的随意一些

代码测试

 <script>
        /*
            多行注释
            JS注释 -- 简单明了
            多行注释:注释中的内容不会被执行,但是可以在源代码中查看
                要养成良好的编写注释的习惯,也可以通过注释来对代码进行一些简单的调试
        */
       // 单行注释:想观察具体的hello是由于哪一个输出的
       alert("hello");
       document.write("hello");
       console.log("hello"); // 该语句用来在控制台输出一个日志

       /*
        1、JS中严格区分大小写,Html中是不区分大小写
        2、JS中每一条语句以分号(;)结尾
                - 如果不写分号,浏览器会自动添加,但是会消耗一些系统资源,
                - 而且有些时候,浏览器会加错分号,所以在开发中分号必须写
        3、JS中会忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化
                - 可以写的会比较的随意一些,
       
       */
       // Alert("Hello"); // 要观察是否报错,可以F12在控制台中进行查看
    </script>

字面量和变量

  • 字面量:都是一些不可改变的值
    - 比如: 1 2 3 4 5
    - 字面量都是可以直接使用,但是我们一般都不会直接使用字面量
  • 变量:可以用来保存自变量,而且变量的值是可以任意改变的
    - 变量可以方便我们使用,现在在开发中都是通过变量来保存一个字面量
    - 而很少使用字面量
    - 可以通过变量对字面量进行描述

代码测试

    <script>
        /*
            字面量:都是一些不可改变的值
                比如: 1 2 3 4 5
                字面量都是可以直接使用,但是我们一般都不会直接使用字面量
            变量:可以用来保存自变量,而且变量的值是可以任意改变的
                  变量可以方便我们使用,现在在开发中都是通过变量来保存一个字面量
                  而很少使用字面量
                  可以通过变量对字面量进行描述

        */
        // alert(1234556);
        // 声明变量:在JS中使用var关键字来声明一个变量
        var a;
        // 为变量赋值
        a = 123;

        // 声明和赋值同时进行
        var b = 789;
        console.log(a);
        console.log(b);
    </script>

标识符

  • 在JS中所有的可以由我们自主命名的都可以称为标识符
  • 例如:变量名、函数名、属性名都属于标识符
  • 命名一个标识符的时需要遵守以下规则:
    1、标识符中可以包含:字母、数字、 _ 、$
    2、标识符不能以数开头,其他都行
    3、标识符不能是ES中的关键字或保留字
    - var var = 123; 报错 不用特意记,
    4、标识符一般采用驼峰命名方法:-- 规范
    - 首字母小写,每个单词的开头字母大写,其余字母小写
    helloWorld xxxYyyZzz
  • JS底层保存标识符时实际上是采用Unicode编码
    所以理论上讲,所有的utf-8中含有的内容都可以作为标识符
    var 锄禾日当午 = 789; 能用千万别用

字符串

  • 数据类型指的是字面量的类型
  • 在JS当中一种由六种数据类型:① String 字符串 ② Number 数值 ③ Boolean 布尔值 ④ Null 空值 ⑤ Undefined 未定义 ⑥ Object 对象
  • 其中String Number Boolean Null Undefined 属于基本数据类型
    而 Object 属于引用数据类型

String字符串

  • 在JS中字符串需要使用一个引号引起来
  • 使用双引号或单引号都可以 “hello” ‘hello’ - 不要混着用
  • 引号不能嵌套 双引号里面不能放双引号,单引号里面不能放单引号
    - 但是单引号里面可以嵌套双引号 : str = ‘我说:“今天天气真不错!”’

转义字符的使用

  • 在字符串中我们可以使用\作为转义字符
    当表示一些特殊符号时可以使用\ 来转义
    \" 表示 "
    \’ 表示 ’
    \n 表示换行
    \t 制表符 相当于tab键
    \\ 表示 \

代码展示

    <script>
        /*
            数据类型指的是字面量的类型
            在JS当中一种由六种数据类型
                - String 字符串
                - Number 数值
                - Boolean 布尔值
                - Null 空值
                - Undefined 未定义
                - Object 对象
            
            其中String Number Boolean Null Undefined 属于基本数据类型
            而 Object 属于引用数据类型
        */
       /*
            String字符串
            - 在JS中字符串需要使用一个引号引起来
            - 使用双引号或单引号都可以 "hello" 'hello' - 不要混着用
            - 引号不能嵌套 双引号里面不能放双引号,单引号里面不能放单引号
                - 但是单引号里面可以嵌套双引号 : str = '我说:"今天天气真不错!"'
       */
      var str = "hello";
      /*
            在字符串中我们可以使用\作为转义字符
                当表示一些特殊符号时可以使用\ 来转义
                \" 表示 "
                \' 表示 '
                \n 表示换行
                \t 制表符 相当于tab键
                \\ 表示 \

      */
    //   str = '我说:"今天天气真不错!"'
    //   str = "我说:\"今天天气真不错!\"";
      str = '\\\\'
      console.log(str);
      // 输出字面量 字符串 str 
      alert("str");
      // 输出变量str 
      alert(str);
    </script>

Number

  • 在JS中所有的数值都是Number类型:包括整数和浮点数(小数)
  • JS中可以表示数字的最大值和最小值(表示大于0的最小值)
    Number.MAX_VALUE - 1.7976931348623157e+308
    Number.MIN_VALUE - 5e-324 表示大于0的最小值
 console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
  • 如果使用Number 表示的数字超过了最大值,则会返回一个
    Infinity 表示正无穷
    -Infinity 表示负无穷
    使用typeof检查Infinity也会返回Number
 c = Number.MAX_VALUE * Number.MAX_VALUE;
 console.log(c); // Infinity
  • NaN 是一个特殊的数字,Not a Number
    使用一个typeof检查一个NaN也会返回number
e = NaN;
console.log(typeof e); // number
  • 可以使用一个运算符typeof, 来检查一个变量的类型
    语法:typeof 变量
    检查字符串时,会返回String
    检查数值时,会返回number
 // 数字123
 var a = 123;
 // 字符串123
 var b = "123";
 console.log(a); // 123
 console.log(typeof a); // number
 console.log(b); // 123
 console.log(typeof b); // string
  • 使用JS进行浮点元素的运算,可以得到一个不精确的结果
    所以千万不要使用JS进行对精确度要求比较高的运算(钱)
var c = 123 + 456;
console.log(c); // 579 
var d = 0.1 + 0.2;
console.log(d); // 0.30000000000000004

布尔值

  • 布尔值只有两个,主要用来做逻辑判断
    true
    - 表示真
    false
    - 表示假
    使用typeof 检查一个布尔值时,会返回boolean
var bool = true;
console.log(bool);
console.log(typeof bool); // boolean

Null 和 Undefined

  • Null类型的值只有一个,就是null
    null这个值专门用来表示为空的对象
    使用typeof 检查一个null值的时候,会返回object
var a = null;
console.log(typeof a); // object
  • Undefined类型也只有一个,就是undefined
    当声明一个变量,但是并不给变量赋值的时候,它的值就是undefined,
    使用typeof 检查一个undefined时也会返回undefined
    注意:添加了引号就是String类型
var b;
console.log(b); // undefined 
console.log(typeof b); // undefined 

强制类型转换 (String)

  • 指将一个数据类型强制转换为其他的数据类型

  • 类型转换主要指 将其他的数据类型转换为 - String Number Boolean(null 和 undefined 一般不)

  • 将其他的数据转换为String
    -方式一 (有局限)
    - 调用被转换数据类型的toString() 方法
    - 该方法不会影响到原变量,会将转换的结果返回
    - 方式二
    - 调用String函数 String(),并将被转换的数据作为参数传递给函数
    - 使用String() 函数做强制类型转换时
    对于Number和Boolean实际上就是调用的toString()方法
    但是对于null和undefined就不会调用toString() 方法
    他会将null直接转换为"null"
    他会将undefined直接转换为"undefined"

  • 方式一测试

var a = 123;

// 调用a的toString() 方法
// 调用 xxx的yyy方法,就是xxx.yyy() 
var b = a.toString();
console.log(typeof a); 
console.log(typeof b);
// 要想对原来的元素进行处理的话,可以用a元素接受即可
a = a.toString();
  • 但是注意:null和undefined这两个值没有toString() 方法, 如果调用它们的方法,会报错
a = null;
a = a.toString();
console.log(typeof a); // caught TypeError: Cannot read properties of null (reading 'toString')
  • 方式二测试
var a = 123;
// 方式二:调用 String() 函数来将a转换为字符串,a作为参数
// a = String(a);
// a = null;
a = undefined;
a = String(a);
console.log(typeof a);  // string
console.log(a); // "undefinded"

强制类型转换 (number)

  • 将其他的数据类型转换为Number
    转换方式一:使用Number() 函数,和转换成String用法是一样的
  • 字符串 --> 数字
    1、如果是纯数字的字符串,则直接将其转换成数字
    2、如果字符串中有非数字的内容,则转换为NaN
    3、如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
    上面有一个很大的缺陷就是如果里面的参数是“abc”这一类,则没有办法进行转换
  • 布尔 --> 数字 :true 转成1 false 转成0
  • null --> 数字 0
  • undefined --> 数字NaN
// var a = "123";
// var a = "abc";
// var a = "";
// a = true;
// a = false;
a = null;
// 调用Number() 函数来将a 转换为Number类型
a = Number(a);
// 其实每次写代码都是可以接着写的,因为每次执行都是从上到下进行执行操作

a = undefined;
a = Number(a);

**转换方式二:**使用函数进行 - 这种方式是专门用来对付字符串的
① parseInt() 将一个字符串转换为一个整数
② parseFloat() 把一个字符串转换为一个浮点数

// 方式二: 可能获取的东西不一样
// 因为使用Number() 稍微有一点非法的内容就没有办法进行转换
// a = "123px";
// a = Number(a);
a = "123px";
// 调用parseInt()函数将a转换为Number
/*
    parseInt() 可以将一个字符串中的·有效的整数内容去出来
    只会取整数
    然后转换为Number
    如果第一位就是非法的,直接返回的就是NaN

    parseFloat() 函数就是后面的小数部分也可以取值

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

*/
a = "123.456px";
a = "123.456.789px"; // 后面的789是没有的,这一点还是很关键的
a = parseFloat(a);
/*
    如果对非String 使用parseInt()或parseFloat()
    他会先将其转换为String,然后再操作
*/
a = true;
a = parseInt(a); // NaN

a = 198.23;
a = parseInt(a); // 一个简单的取整操作

console.log(typeof a); // number
console.log(a);

其他进制的数字

  • 如果需要表示16进制的数字,则需要ox开头
// 十六进制数字
a = 0x10;
a = 0xff;
  • 如果需要表示8进制的数字,则需要以0开头
// 八进制数字
a = 070;
  • 如果需要表示2进制的数字,则需要以0b开头(但不是所有浏览器都支持,- 内置浏览器就不支持)
// 二进制数字
a = 0b10; 
  • 需要注意的一点就是:像"070"这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析
  • 需要进行统一, a = parseInt(a, 10); 指定哪一种进制,就需要用到第二个参数指明
a = "070";
// 转换成number类型
// 可以在parseInt()中传递一个第二个参数,来指定数字的进制
a = parseInt(a, 10);
console.log(typeof a); // number
console.log(a); // 70

转换为boolean类型

将其他数据类型转换为Boolean类型

  • 使用Boolean() 函数即可(记住)
    ① 数字 --> 布尔 :除了0和NaN其余的都是true
    ② 字符串 --> 布尔:除了空串,其余的都是true
  • null和undefined都会转换为false
  • 对象也会转换为true
var a = 123; // true
a = -123; // true
a = 0; // false
a = Infinity; // true
a = NaN; // false
// 调用一个Boolean()函数将a转换为布尔值
//    a = Boolean(a);

// 字符串测试
a = " ";
a = null; // false
a = undefined; // false
a = Object; // true
a = Boolean(a);
console.log(typeof a);
console.log(a);

运算符

  • 运算符也叫操作符
  • 通过运算符可以对一个或多个值进行运算,并获取运算结果( + - * /)
    ( 比如 typeof就是运算符,可以用来获取一个值的类型
    它会将该值的类型以字符串的形式返回)
    number string boolean undefined object
  • 算数运算符 + - * / %
  • 当对非Number类型的值进行运算时,会将这些值转换为Number然后再进行运算
  • 任何值和NaN做运算都得NaN

加法 (+)

  • 可以对两个值进行加法运算,并将结果返回
  • 如果对两个字符串进行加法运算,则会进行拼串操作
  • 双引号必须在同一行,可以使用加号来进行拼串操作
  • 任何的值和字符串做加法运算,都会先转换为字符串,然后拼串
var a = 123;
var result = typeof a;
console.log(result); // number 
console.log(typeof result); // string

// 运算符测试
result1 = a + 1;
console.log(result1);

result2= true + 1;
console.log(result2);

result3 = true + false;
console.log(result3);

result4 = 2 + null;
result5 = 2 + NaN;
console.log(result4); // 2
console.log(result5); // NaN 
  • 任何值和字符串相加都会转换为字符串,并做拼串操作
  • 我们可以利用这一特点,来将一个任意的数据类型转换为String类型
  • 我们只需要为任意的数据类型 + 一个 “”, 这是一种隐式的类型转换,由浏览器自动完成,实际上也是调用了String()
var c = 123; 
//    c = String(c); // 方式一
//    c = c + ""; // 方式二
//    console.log(typeof c);
// 更清楚的表示
console.log("c = " + c);
console.log(result);
result = 1 + 2 + "3"; // "33"
result = "1" + 2 + 3; // "123"

减法(-)

  • 可以对两个值进行减法操作
  • 其和字符串进行相减,字符串会转换为number类型
// 减法
result = 100 - 5;
result = 100 - true;
result = 100 - "1";
console.log(result);

乘法(*)

  • 可以对两个值进行乘法运算
  • undefined 对应的数字就是非数字NaN
// 减法
result = 2 * 2;
result = 2 * "8"; // 16
result = 2 * undefined; //NaN 任何值和NaN运算还是NaN
result = 2 * null; // 0

除法(/)

result = 4 / 2;
result = 3 / 2; // 1.5

注意点

  • 任何值做 - * / 运算时都会自动转换为Number
  • 我们可以利用这一特点做隐式的类型转换: 可以通过为一个值 -0 *1 /1 来将其转换为Number, 原理和Number() 函数一样,使用起来更简单
var d = "123";
d = d - 0;
console.log(typeof d);
console.log(d);

取模(%)
即取余数

result = 9 % 3; // 0
result = 9 % 4; // 1
result = 9 % 5;
console.log("result = " + result);

一元运算符

  • 一元运算符,只需要一个操作数
  • ① 正号 (+):不会对数字产生任何影响
  • ② 负号(-): 可以对数字进行负号的取反
  • 对于非Number类型的值,它会先转换为Number,然后在运算
var a = 123;
a = +a;
a = -a;
a = true;
a = -a;
a = "18";
a = +a;
console.log("a = " + a);
console.log(typeof a);

var result = 1 + "2" + 3; //123
var result = 1 + +"2" + 3; //6
console.log("result = " + result);

自增自减

自增(a++)

  • 通过自增可以使变量在自身的基础上加1
  • 对一个变量自增以后,原变量的值会立即自增1
  • 自增分成两种,后++(a++) 前++(++a)
  • 无论是a++ 还是++a 都会立即使原变量的值自增1
  • 不同的是a++和++a的值不同
  • a++的值等于原变量的值(自增前的值)
  • ++a 的值等于原变量的新值
var a = 1;
//    a = a + 1;
// 使a自增1
//    a++;
//    ++a;
// console.log(a++); // 表达式 1
console.log(++a); // 2
console.log(a);

var c = 10;

//使c自增1
// 第一次c++是在10的基础上自增
c++;
// 第二次c++是在11的基础上自增,考虑自增的时候一定要考虑是在谁的基础上自增的

console.log(c++); // 11
// 前自增
var d = 20;
console.log(++d); // 21 ++d 是新值
console.log(++d); // 22 ++d 得到的是原变量的新值

var d = 20;

// 简单测试,d++ 是原值,但是d的值就会发生相应的变化
// 从左到右进行执行操作即可

// var result = d++ + ++d + d; // 64
d = d++; // d = d++;
console.log(d); // 20 
console.log("result = " + result);

自减(a–)

  • 通过自减可以使变量在自身的基础上减1
  • 自减分成两种,后–(a–) 和 前-- (–a)
  • 无论是a-- 还是 --a 都会立即使原变量的值自减1
  • 不同的是a-- 和 --a的值不同
  • a-- 是变量的原值, --a 是变量的新值(自减以后的值)
// 自减
var num = 10;
//    num--;
//    --num;
console.log(num);

自增练习

var n1 = 10;
var n2 = 20;
var n = n1++; // n1 = 11, n1++ = 10
console.log("n = " + n); // 10
console.log("n1 = "+ n1); // 11

n = ++n1; // n1 = 12, ++n1 = 12
console.log("n = "+ n); // 12
console.log("n1 = "+ n1); // 12

n = n2--; // n2 = 19, n2-- = 20
console.log("n = "+ n); // 20
console.log("n2 = "+ n2); // 19

n = --n2; // 19的基础上,n2 = 18, --n2 = 18
console.log("n = "+ n); // 18
console.log("n2 = "+ n2); // 18

逻辑运算符

JS中为我们提供了三种逻辑运算符
① ! 非

  • !可以用来对一个值进行非运算
  • 所谓非运算就是值对一个布尔值进行取反操作
  • true 变false false 变true
  • 如果对一个值进行两次取反,它不会变化
  • 如果对非布尔值进行取反,则会将其转换为布尔值,然后在取反
  • 所以我们可以利用该特点,来将一个其他的数据类型转换为布尔值:可以为一个任意数据类型取两次反,来将其转换为布尔值,原理和Boolean() 函数一样

② && 与

  • && 可以对符号两侧的值进行与运算并返回结果
  • 运算规则:两个值中只要有一个为false就返回false, 只有两个值都为true时,才会返回false, JS中的与属于短路与,如果第一个值为false则不会看第二个

③ 或 (||)

  • || 可以对符号两侧的值进行或运算,并返回结果
  • 如果两个值都为false,才返回false,理解为亲情
  • JS中的或属于短路或,如果第一个值为true则不会检查第二个
var a = true;
// 对a进行非运算
a = !a;
console.log(a);

var b = 10;
b = !!b;
console.log(b); // false

var c = "hello";
c = !!c;
console.log(c); // true

// 如果两个值都是true则返回true
// 只要有一个false就返回false
var result = true && true; // true
result = true && false; // false

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

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

// 或运算:只要有一个true就返回true
result = false || false;
result = false || true;
console.log("result = " + result);

// 第一个值为false,则会检查第二个
//    false || alert("12334");
true || alert("kangkang");

非布尔值的与或运算

  • 对于非布尔值进行与或运算时,会先其转换为布尔值,然后在运算,并且返回原值
  • 与运算: ① 如果第一个值为true,则必然返回第二个值 ② 如果第一值为false,则直接返回第一个值
  • 或运算:① 如果第一个值为true则直接返回第一个值 ② 如果第一个值为false,则直接返回第二个值
    记住上面的运算规则即可!
// true && true
// 与运算:如果两个值都为true,则返回后边的
// 如果两个值中有false,则返回靠前的false
var result = 1 && 2;

// false && true
result = 0 && 2;
// 如果有false 则返回false
result = 2 && 0;
// false && false
result = NaN && 0; // NaN
result = 0 && NaN; // 0
console.log("result = " + result); //

// 或运算测试
// true || true
// 如果第一个值为true,则直接返回第一个值

result = 1 || 2; // 1
result = 2 || NaN;

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

result = NaN || 1;
result = NaN || 0;

console.log("true = " + result);

result = "" || "hello"; // "hello"
result = -1 || "你好";
console.log("result = " + result);

赋值运算符

  • = 可以将符号右侧的值赋值给符号左侧的变量
  • += : a += 5; 等价于 a = a + 5;
  • -= : a -= 5; 等价于 a = a - 5;
  • *= : a *= 5; 等价于 a = a * 5;
  • /= : a /= 5; 等价于 a = a / 5;
  • %= : a %= 5; 等价于 a = a % 5;
var a = 10;
//    a = a + 5;
//    a += 5;
//    a -= 5;
//    a *= 5;
//    a /= 5;
a %= 5;            
console.log("a = " + a);

关系运算符

通过关系运算符可以比较两个值之间的大小关系 - 如果关系成立会返回true,关系不成立会返回false
① > 大于号

  • 判断符号左侧的值是否大于右侧的
  • 如果关系成立,则返回true,如果关系不成立则返回false

② >= 大于等于

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

③ < 小于
④ <= 小于等于

非数值的情况

  • 对于非数值进行比较时,会将其转换为数字然后进行比较
  • 任何值和NaN做任何比较都是false
  • 如果符号两侧的值都是字符串,不会将其转换为数字进行比较
  • 而会分别比较字符串中字符的Unicode编码

还有几点需要特别注意的 - 见下面代码

var result = 5 > 10; // false;
result = 5 >= 5;
result = 5 < 4; // false
result = 4 <= 4;
console.log("result = "+ result);

// 非数值
console.log(1 > true); // false
console.log(1 > "0"); // true
// 任何值和NaN做任何比较都是false
console.log(10 < "hello"); // false
console.log("1" < "5"); // true
// 如果比较的两个字符串型的数字,可能会得到不可预期的结果
// 注意:在比较两个字符串型的数字时,一定一定要转型, + 
console.log("11" < +"5"); // false
console.log("11" < "5"); // true 先比较第一位 
console.log("a" < "b"); // true
// 比较字符编码时是一位一位进行比较
console.log("abc" < "b"); // true
// 如果两位一样,则比较下一位,所以借用它来对英文进行排序
console.log("abc" < "bcd"); // true

Unicode编码

  • hex表示十六进制,十六进制一般用四位表示

Script中用Unicode来表示字符

<script>
    // hex表示的是十六进制,四位表示
    /*
        在字符串中使用转义字符输入Unicode编码
        \u四位编码 十六进制
    */
   console.log("\u2620");
</script>

网页中用Unicode来表示字符

<body>
    <!-- 
        在网页中使用Unicode编码
        &#编码;这里的编码需要的是10进制
     -->
     <h1>&#9760</h1>
     <h2>&#9856</h2>
</body>

相等运算符

  • 相等运算符用来比较两个值是否相等
  • 如果相等返回true,否则返回false
  • 使用 == 来做相等运算(会自动类型转换):当使用 == 来比较两个值时,如果值的类型不同
    则会自动进行类型转换,将其转换为相同的类型
    然后在比较
  • 不相等 != : ① 不相等用来判断两个值是否不相等,如果不相等则返回true,否则返回false ② 不相等也会对变量进行自动类型转换,如果转换后相等它也会返回false
  • 全等(===) : ① 用来判断两个值是否全等,它和相等类似,不同的是它不会进行类型转换 ② 如果两个值的类型不同,直接返回false
  • 不全等(!==): ① 用来判断两个值是否不全等,和不等类似,不同的是不会做自动类型转换 ② 如果两个值的类型不同,直接返回true
console.log(1 == 1); // true
var a = 10;
console.log(a == 4); // false

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

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

/*
undefined 衍生自 null
所以这两个值做相等判断时,会返回true

*/
console.log(undefined == null); // true

/*
NaN不和任何值相等,包括它本身
*/
console.log(NaN == NaN); // false

var b = NaN;

// 判断b的值是否是NaN
console.log(b == NaN);
/*
可以通过isNaN() 函数来判断一个值是否是NaN
如果该值是NaN则返回true,否则返回false

*/
console.log(isNaN(b)); // true

// 不相等
console.log(10 != 5); // true

console.log("abcd" != "abcd");
console.log("1" != 1); // false

// 全等
console.log("123" === 123); // false
console.log(null == undefined); // true
console.log(null === undefined); // false

// 不全等
console.log(1 !== "1"); // true

条件运算符

  • 条件运算符也叫三元运算符
  • 语法: 条件表达式?语句1:语句2
  • 执行的流程: ① 条件运算符在执行时,首先对条件表达式进行求值 ② 如果该值为true,则执行语句1,并返回执行结果 ③ 如果该值为false,则执行语句2,并返回执行结果
  • 如果条件表达式是非布尔值,会转换成布尔值,进行运算
//    true?alert("语句1"):alert("语句2");
var a = 10;
var b = 20;
var c = 50;
a > b ? alert("a大"):alert("b大");

// 获取a和b中的最大值
//    var max = a > b ? a : b;
// 获取a b c中的最大值,一步一步来
//    max = max > c ? max : c;
// 下面这种写法不推荐,不方便阅读,要写,括号加上
var max = a > b ? (a > c ? a : c) : (b > c ? b : c);
console.log("max = " + max);

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

运算符的优先级

  • , 运算符 - 使用 , 可以分隔多个语句,一般可以声明多个变量时使用
// 使用, 运算符同时声明多个变量
var a, b, c;
// 可以同时声明多个变量并赋值
var a = 1, b = 2, c = 3;
alert(b);
  • 运算符的优先级 - 和数学中一样,在JS中运算符也有优先级 比如:先乘除后加减
  • 在JS中有一个运算符优先级的表,在表中越靠上优先级越高,优先级越高越优先计算
  • 如果优先级一样,则从左往右计算, 但是这个表并不需要记忆,不确定优先级使用括号进行计算即可
/*
如果||的优先级高,或者两个一样高,则应该返回3
如果与的优先级高,则应该返回1
*/
var result = 1 || 2 && 3; // 1
console.log("result = " + result);

代码块

  • 我们的程序是由一条一条语句构成的,语句是按照自上而下的顺序一条一条执行的
  • 在JS中可以使用{}来为语句进行分组,同一个{} 中的语句我们称为是一组语句,它们要么都执行,要么都不执行
  • 一个{} 中的语句我们也称为叫一个代码块, 在代码块的后边就不用在编写; 了
  • 在JS中代码块,只具有分组的作用,没有其他用途
// 在代码块中声明的a变量,在代码块外面也可以使用,{} 只有分组作用
{
var a = 10; 
alert("hello");
console.log("你好");
document.write("语句");
}
console.log("a = " + a);

if语句1

  • 流程控制语句:
  • JS中的程序是从上到下一行一行执行的
  • 通过流程控制语句可以控制程序执行流程 - 使程序可以根据一定的条件来选择执行
  • 语句的分类: ① 条件判断语句 ② 条件分支语句 ③ 循环语句
  • 条件判断语句: 使用条件判断语句可以在执行某个语句之前进行判断, 如果条件成立才会执行语句,条件不成立则语句不执行
  • if语句:语法一 : if(条件表达式) 语句
  • if语句在执行时会先对条件表达式进行求值判断:① 如果条件表达式为true,则执行if后的语句 ② 如果条件表达式为false,则不会执行if后的语句 ③ if语句只能控制紧随其后的那个语句 ④ 如果希望if语句可以控制多条语句,可以将这些语句统一放到代码块中 ⑤ if语句后的代码块不是必须的,但是开发中建议写上,即使后面只有一条语句
var a = 11;
if (a > 10){
alert("请叫我Kangkang");
alert("a比10大...");
}
// 要判断if语句中两个条件的话可以使用 && 连接左右两个条件即可

if语句2

  • 对于if语句还有两种更全面的用法 - 语法2 和 语法3
 <script>
     /*
         if语句
         语法二:
             if(条件表达式){
                 语句1....
             }else{
                 语句2...
             }
         if...else...语句
             当该语句执行时,会先对if后的条件表达式进行求值判断
                 如果该值为true,则执行if后的语句
                 如果该值为false,则执行else后的语句
         语法三:
             if(条件表达式){
                 语句1....
             }else if(条件表达式){
                 语句2...
             }else{
                 语句3...
             }
         if...else if... else
             当该语句执行时,会从上到下依次对条件表达式进行求值判断
             如果该值为true,则执行当前语句,如果值为false则继续向下判断,依次类推
             该语句中只会有一个代码块执行,一旦满足后面就不会执行

     */
    var age = 60;
    /*if(age > 60){
        alert("你已经退休了!");
    }else{
        alert("你还没有退休!");
    }*/
    if (age > 100){
        alert("或者没有什么意思");
    }else if (age > 80){
        alert("你也老大不小了!");
    }else{
        alert("你还只是一个小孩子!");
    }
 </script>

if练习

  • prompt() 可以弹出一个提示框,该提示框会带有一个文本框
  • 用户可以在文本框中输入一段内容,该函数需要一个字符串作为参数
  • 该字符串将会作为提示框的提示文字,用户输入的内容将会作为函数的返回值返回,可以定义一个变量来接收该内容
var score = prompt("请输入小明的期末成绩:");
alert(score); 
// 后面利用题目意思对score进行相应的判断即可

JavaScript视频 --李立超_第4张图片
JavaScript视频 --李立超_第5张图片

if练习一

        从键盘输入小明的期末成绩:
        当成绩为19时,奖一辆BMw
        当成绩[80-99]时,奖一台 iphone15s
        当成绩[60-80]时,奖励一本考书”
        其他时,什么奖励也没有

代码实现

 // score就是小明的期末成绩,友好提示
 var score = prompt("请输入小明的期末成绩(0 - 100):");
 // 判断值是否合法    
 if (score > 100 || score < 0 || isNaN(score)) {
     alert("拉出去毙了");
 } else {
     // 根据score的值来决定给小明什么奖励
     if (score == 100) {
         // 奖励一台宝马
         alert("宝马拿去");
     } else if (score >= 80) {
         alert("手机拿去");
     } else if (score >= 60) {
         alert("参考书拿去看");
     } else {
         alert("棍子一根!");
     }
 }

if练习二

        大家都知道,男大当婚,女大当嫁。那么女方家长要嫁女儿,当然要提出一定的条件
        高:180cm以上;富:1000万以上;帅:500上
        如果这三个条件同时满足,则:'我一定要嫁给他
        如果三个条件有为真的情况,则:嫁吧,比上不足,比下有余。
        如果三个条件都不满足,则:不嫁!

代码实现

 var height = prompt("请输入你的身高(CM):");
 var money = prompt("请输入你的财富(万):");
 var face = prompt("请输入你的颜值(PX):");

 // 输出三个变量
 //    alert(height + "," + money + "," + face);
 //    如果这三个条件同时满足,则:'我一定要嫁给他
 if (height > 180 && money > 1000 && face > 500) {
     alert("我一定要嫁给他");
 } else if (height > 180 || money > 1000 || face > 500) {
     alert("嫁吧!比上不足,比下有余");
 } else {
     alert("不嫁了");
 }
         编写程序,由键盘输入三个整数分别存入变量num1、num2、num3,
         对他们进行排序,并且从小到大输出           

代码实现

var num1 = +prompt("请输入第一个数:");
var num2 = +prompt("请输入第二个数:");
var num3 = +prompt("请输入第三个数:");
// 把几种情况都理清楚即可
// alert(typeof num1);
// 找到三个数中最小的数
if (num1 < num2 && num1 < num3) {
    // num1最小,比较num2 和 num3
    if (num2 < num3) {
        // num1 num2 num3 
        alert(num1 + "," + num2 + "," + num3);
    } else {
        alert(num1 + "," + num3 + "," + num2);
    }
} else if (num2 < num1 && num2 < num3) {
    // num2最小,比较num1 和 num3
    if (num1 < num3) {
        alert(num2 + "," + num1 + "," + num3);
    } else {
        alert(num2 + "," + num3 + "," + num1);
    }
} else {
    // num3最小,比较num1 和 num2
    if (num1 < num2) {
        alert(num3 + "," + num1 + "," + num2);
    } else {
        alert(num3 + "," + num2 + "," + num1);
    }
}

var num = 20;
// 也是会弹出来,下方就是作为很简单的赋值运算,里面始终为true
if (num = 10) {
    alert("哈哈哈");
}

条件分支语句

  • 条件分支语句也叫说switch语句
  • 语法:
switch(条件表达式){
              case 表达式:
                  语句....
                  break;
              case 表达式:
                  语句...
                  break;
              default:
                  语句....
                  break;
          }

执行流程:

  • switch…case… 语句:
  • 在执行时会依次将case后的表达式的值和switch后的条件表达式的值进行全等比较
  • 如果比较结果为true,则从当前case处开始执行代码
  • 当前case后的所有代码都会执行,我们可以在case后边跟着break,以此来结束
  • 这样可以确保只会执行当前case后的语句,而不会执行后边的语句
  • 如果比较结果为false,则接着向下面比较
  • switch语句和if语句的功能实际上是有重复的,使用switch可以实现if的功能, 同样使用if也可以实现switch的功能,所以我们在使用时,可以根据自己习惯选择
// 根据num的值输出相应的中文
var num = "abc";
switch (num) {
    case 1:
        console.log("kang");
        // 使用break可以退出switch语句
        break;
    case 2:
        console.log("贰");
        break;
    default:
        console.log("非法数字!");
}

switch练习

 对于成绩大于60分的,输出"合格" 低于60分的,输出“不合格"
        6x / 10 = 6
        7x / 10 = 7
        8x / 10 = 8
        9x / 10 = 9
        100 / 10 = 10
// 方式一 
/*
   var score = 99;
   switch(parseInt(score / 10)){
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
            console.log("合格!");
            break;
        default:
            console.log("不合格!");
            break;
   }
*/
// 方式二:类似于if语句
switch(true){
    case score >= 60:
        console.log("合格");
        break;
    default:
        console.log("不合格");
        break;
}

while循环

while循环

  • 向页面中写数字,这种重复操作往往要用到循环
  • 因为document.write写东西是向网页里面写东西的,所以换行用到的是 < br/ >
document.write(1 + "
"
); document.write(2 + "
"
);
  • 循环语句 - 通过循环语句可以反复的执行一段代码多次
  • while循环,语法
 - 语法
 while(条件表达式){
     语句... 
 }
  • 执行流程:① while语句在执行时,先对条件表达式进行求值判断 ② 如果值为true,则执行循环体 ③ 循环体执行完毕以后,继续对表达式进行判断 -> 如果为true,则继续执行循环体,以此类推, 如果值为false,则终止循环
var n = 1;
// 像这种将条件表达式写死为true的循环,叫做死循环
// 该循环不会停止,除非浏览器关闭,死循环在开发中慎用
// 可以使用break; 退出循环
while (true) {
    alert(n++);
    // 判断n是否是10
    if (n == 10) {
        // 退出循环
        break;
    }
}

do…while 循环

  • 语法
     do{
          语句... 
       }while(条件表达式)
  • 解释:① do…while 语句在执行时,会先执行循环体 ② 循环体执行完毕后,在对while后的条件表达式进行判断 ③ 如果结果为true,则继续执行循环体,执行完毕继续判断,以此类推 ④ 如果结果为false,则终止循环
  • 实际上这两个语句功能类似,不同的是while先判断后执行;而do…while 会先执行后判断
  • do…while… 可以保证循环体至少执行一次; 而while不能保证 – 尽量不要写死循环操作即可

创建一个while循环的三个步骤

// 创建一个循环,往往需要三个步骤
// 1创初始化的一个变量
var i = 0;
// 2在循环中设置一个条件表达式
while (i < 10) {
    // alert(i);
    document.write(i + "
"
); // 往页面中进行写入即可 // 3、定义一个更新表达式,每次更新初始化变量 i++; }

while的练习

练习一:

        假如投资的年利率为5%,试求1000块增长到5000块,需要花费多少年
        1000 1000 * 1.05
        1050 1050 * 1.05

代码实现

// 定义一个变量,表示当前的钱数
var money = 1000;
// 定义一个计数器
var count = 0;
// 定义一个while循环来计算每年的钱数
while(money < 5000){
    money *= 1.05;
    // 使count自增
    count++;
}
console.log("一共需要" + count + "年");

练习二:

        从键盘输入小明的期末成绩:
        当成绩为19时,奖一辆BMw
        当成绩[80-99]时,奖一台 iphone15s
        当成绩[60-80]时,奖励一本考书”
        其他时,什么奖励也没有                  
  • 之前的练习希望每次输错以后能够重新进行输入,这就需要使用到循环操作才行
while(true){
     // score就是小明的期末成绩,友好提示
     var score = prompt("请输入小明的期末成绩(0 - 100):");
     // 判断用户输入的值是否合法
     if(score >= 0 && score <= 100){
         // 满足该条件则证明用户的输入合法,退出循环
         break;
     }
     alert("请输入有效的分数:");
}  

// score就是小明的期末成绩,友好提示
//    var score = prompt("请输入小明的期末成绩(0 - 100):");
// 判断值是否合法    
if (score > 100 || score < 0 || isNaN(score)){
    alert("拉出去毙了");
}else{
     // 根据score的值来决定给小明什么奖励
     if(score == 100){
         // 奖励一台宝马
         alert("宝马拿去");
     }else if (score >= 80){
         alert("手机拿去");
     }else if (score >= 60){
         alert("参考书拿去看");
     }else{
         alert("棍子一根!");
     }
}

for循环

  • for语句,也是一个循环语句,也称为for循环
  • 在for循环中为我们提供了专门的位置用来放三个表达式:
    1、初始化表达式 2、条件表达式 3、更新表达式
  • for循环的语法
for(①初始化表达式;②条件表达式;更新表达式){
     ③语句....
 } 
  • 执行流程: ① 执行初始化表达式,初始化变量(初始化表达式只会执行一次)② 执行条件表达式,判断是否执行循环: 如果为true 则执行循环③, 如果为false 终止循环 ④ 执行更新表达式,更新表达式执行完毕继续重复②
  • 创建一个执行10次的while循环
var i = 0;
// 创建一个循环,定义条件表达式
while(i < 10){
    // 设置更新表达式
    alert(i++);
}
  • 使用for循环来表示
for (var i = 0; i < 10; i++) {
     alert(i);
}
  • for循环中的三个部分都可以省略,也可以写在外部
    如果在for循环中不写任何表达式,只写两个 ; ;
    此时循环是一个死循环会一直执行下去,慎用;
    初始化 - 习惯是从0开始
var i = 0;
for (; i < 10;) {
    alert(i++);
}

for循环练习

练习一:
打印1-100之间的所有奇数之和

代码实现:

// 打印1 - 100 之间的数
// 创建一个变量来保存奇数之和
var sum = 0;
for (var i = 1; i <= 100; i++) {
    // 判断i是否是奇数-不能被2整除
    if (i % 2 != 0) {
        // 如果i除以2有余数则证明i是奇数
        //    console.log(i);
        sum = sum + i;
    }
}
console.log("奇数之和:" + sum);

练习二:
打印1-100之间所有7的倍数的个数及总和
代码实现:

// 定义一个变量来保存总和
var sum = 0;
// 定义一个计数器,来记录数量
var count = 0;
// 打印1-100之间所有的数
for (var i = 1; i <= 100; i++) {
    // 判断i是否是7的倍数
    if (i % 7 == 0) {
        //    console.log(i);
        sum += i;
        // 使得计数器自增1
        count++;
    }
}
// 输出总和
console.log("总和为:" + sum);
// 输出总数
console.log("总数为:" + count);

练习三:
水仙花数是指一个3位数,它的每个位上的数字的3次幂之和等于它本身:例如 1^3 + 5^3 + 3^3 = 153),打印所有的水仙花数

代码实现:

// 打印所有的三位数
for (var i = 100; i < 1000; i++) {
    // 获取i的百位,十位,个位的数字
    // 获取百位上的数字
    var bai = parseInt(i / 100);
    // 获取十位的数字
    var shi = parseInt((i - bai * 100) / 10);
    // 获取个位数字
    var ge = i % 10;

    // 判断i是否是水仙花数
    if (bai * bai * bai + shi * shi * shi + ge * ge * ge == i) {
        console.log(i);
    }
}

质数的练习

        在页面中接收一个用户输入的数字,并判断该数是否是质数
        质数:只能被1和它自身整除的数,
        1不是质数也不是合数,质数必须是大于1的自然数。

代码实现:

var num = prompt("请输入一个大于1的整数:");

// 判断这个值是否合法
if(num <= 1){
    alert("该值不合法!");
}else{
    // 创建一个变量来保存当前的数的状态
    // 默认当前的num是质数,使用一个旗帜
    var flag = true;
    // 判断num 是否是质数
    // 获取1-num之间的数
    for(var i = 2; i < num; i++){
     //    console.log(i);
         // 判断num能否被i整除
         if(num % i == 0){
             // 如果num能被i整除,则说明num一定不是质数
             // alert(num + "不是质数");
             flag = false;
         }
    }
    // 如果num是质数则输出
    if(flag){
        alert(num + "是质数!!!");
    }else{
        alert("这个不是质数");
    }
}
  • 用到了标志flag来保存当前某个状态

补充质数的练习

  • 主要是对上述的质数的判断使用了flag进行标志说明

嵌套的for循环

需求: 通过程序在页面中输出
*****
*****
*****
*****
*****

 document.write("*****
"
); document.write("*****
"
); ...
  • 上面这种效率太过于低下

使用for循环进行 - 通过一个for循环来输出图形

// 通过一个for循环来输出图形
// 这个for循环执行几次,图形的高度就是多少
// 它可以用来控制图形的高度
// 内层循环可以决定图形的宽度,执行几次图形的宽度就是多少
for (var i = 0; i < 5; i++) {
    //    document.write("*****
");
// 在循环的内部再创建一个循环,用来控制图形的宽度 for (var j = 0; j < i+1; j++) { // 在页面中输出要用到html标签表示空格或者换行 document.write("*  "); } document.write("
"
); }

嵌套for循环的练习

1、打印倒过来的三角形
*****
****
***
**
*

  • 观察题目之间的规律
for(var i = 0; i < 5; i++){
    for(var j = 0; j < 5-i; j++){
        document.write("*");
    }
    document.write("
"
); }

2、打印99乘发表

1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
....
.....................9*9=81

// 创建外层循环,用来控制乘法表的高度
for (var i = 1; i < 10; i++) {
    //    console.log(i);
    // 创建一个内层循环来控制图形的宽度
    for (var j = 1; j <= i; j++) {
        // 在添加换行或者空格的时候,一定要用"" 包起来才行
        document.write("" + j + "*" + i + "=" + i*j + "");
    }
    // 输出一个换行
    document.write("
"
) } // 设置使用了span标签括起来,则可以使用相应的css来设置样式 <style> body{ /* 给body足够的宽度,可以容纳下元素即可 */ width:2000px; } span{ display: inline-block; width:80px; } </style>

3、打印1-100之间所有的质数

// 打印2-100之间所有的数
for(var i = 2; i <= 100; i++){
    // 创建一个布尔值,用来保存结果,默认i是质数
    var flag = true;
    // 判断i是否是质数
    // 获取到2-i之间所有的数
    for(var j = 2; j < i; j++){
        // console.log("----->" + j);
        // 判断i是否能被j整除
        if(i % j == 0){
            // 如果进入判断则证明i不是质数
            flag = false;
        }
    }
    // 如果是质数,则打印i的值
    if(flag){
        console.log(i);
    }
}

break和continue

break

  • break关键字可以用来退出switch或循环语句
  • 不能在if语句中使用break和continue
  • break关键字会立即终止距它最近的循环语句
for(var i = 0; i < 5; i++){
            console.log(i);
            if(i == 2){
                // 在for循环中,对当前for循环起作用
                break;
            }
        }
  • 可以为循环语句创建一个label来标识当前循环
  • label:循环语句
  • 使用break语句时,可以在break后跟着一个label
  • 这样break将会结束指定的循环,而不是最近的
 outer:
 for (var i = 0; i < 5; i++) {
     console.log("@外层循环" + i);
     for (var j = 0; j < 5; j++) {
         break outer;  // @外层循环0
         console.log("内层循环:" + j);
     }
 }

continue

  • continue关键字可以用来跳过当次循环
  • 同样和continue也是默认只会对离他最近的循环起作用
for(var i = 0; i < 5; i++){
            if(i == 2){
                continue;
            }
            console.log(i);
        }
  • 也可以设置一个标签label
outer:
for (var i = 0; i < 5; i++) {
    for (var j = 0; j < 5; j++) {
        if (j == 1) {
            // continue outer;
            continue;
        }
        console.log("--->" + j);
    }
    console.log("@---->" + i);
}
  • 质数练习的补充(性能的提升)
// 打印2-100之间所有的数
for (var i = 2; i <= 10000; i++) {
    // 创建一个布尔值,用来保存结果,默认i是质数
    var flag = true;
    // 判断i是否是质数
    // 获取到2-i之间所有的数
    for (var j = 2; j < i; j++) {
        // console.log("----->" + j);
        // 判断i是否能被j整除
        if (i % j == 0) {
            // 如果进入判断则证明i不是质数
            flag = false;
            // 一旦进入的判断,则证明i不可能是质数了,此时循环再执行已经没有任何意义
            // 使用break来结束循环
            // break;
            // 不加break 259.27ms
            // 加上break 58.64ms
        }
    }
    // 如果是质数,则打印i的值
    if (flag) {
        // console.log(i);
    }
}
// 终止计时器
// console.timeEnd()用来停止一个计时器,需要一个计时器的名字作为参数
console.timeEnd("test");

质数练习的大改进

// 可以通过Math.sqrt();对一个数进行开方
//    var result = Math.sqrt(4);
//    console.log("result = "+ result);
  • 而求取质数的时候,在内层循环中根本不需要求余这么多次
// 2、打印1-100之间所有的质数
// 打印2-100之间所有的数
for (var i = 2; i <= 10000; i++) {
    // 创建一个布尔值,用来保存结果,默认i是质数
    var flag = true;
    // 判断i是否是质数
    // 获取到2-i之间所有的数
    for (var j = 2; j <= Math.sqrt(i); j++) {
        // console.log("----->" + j);
        // 判断i是否能被j整除
        if (i % j == 0) {
            // 如果进入判断则证明i不是质数
            flag = false;
            // 一旦进入的判断,则证明i不可能是质数了,此时循环再执行已经没有任何意义
            // 使用break来结束循环
            // break;
            // 不加break 259.27ms
            // 加上break 58.64ms
            // 修改j<= 以后 11.07ms
        }
    }
    // 如果是质数,则打印i的值
    if (flag) {
        // console.log(i);
    }
}
// 终止计时器
// console.timeEnd()用来停止一个计时器,需要一个计时器的名字作为参数
console.timeEnd("test");

对象的简介

  • JS中的数据类型:① String 字符串 ② Number 数值 ③ Boolean 布尔值 ④ Null 空值 ⑤ Undefined 未定义的
  • 以上这五种类型属于基本数据类型,以后我们看到的值
    只要不是上边5种,全都是对象
  • Object 对象
  • 基本数据类型都是单一的值,“hello”,“123”,true; 值和值之间没有任何的联系
  • 在JS中来表示一个人的信息(name, gender, age)
var name = "孙悟空";
var gender = "男";
var age = 18;
  • 如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体
  • 对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性
  • 对象的一个分类
    1、内建对象:- 由ES标准中定义的对象,在任何ES的实现中都可以使用 - 比如:Math String Number Boolean Function…
    2、宿主对象:- 由JS的运行环境提供的对象,目前来讲,主要指由浏览器提供的对象 - 比如BOM DOM console.log()中的console 和document.write()中的document
    3、自定义对象:- 由开发人员自己创建的

对象的基本操作

  • 创建一个对象
  • 使用new关键字调用的函数,是构造函数constructor
  • 构造函数是专门用来创建对象的函数
  • 使用typeof检查一个对象时,会返回object
var obj = new Object();
// console.log(typeof obj); // object
  • 对象中添加属性
/*
    在对象中保存的称为属性
    向对象添加属性
        语法:对象.属性名 = 属性值;
*/
// 向obj中添加一个name属性
obj.name = "孙悟空";
// 向obj中添加一个gender属性
obj.gender = "男";
// 向obj中添加一个age属性
obj.age = 18;
console.log(obj); // 外部浏览器会将属性放入Object对象中
  • 读取对象中的属性
/*
    读取对象中的属性
    语法: 对象.属性名

    如果读取对象中没有属性,不会报错而是会返回undefined
*/
console.log(obj.name); // 孙悟空
console.log(obj.hello); // undefinded
  • 修改对象的属性值
/*
    修改对象的属性值
    语法:对象.属性名 = 新值;
*/
obj.name = "kangkang";
console.log(obj.name); // kangkang
  • 删除对象的属性
/*
     删除对象的属性
         语法:delete 对象.属性名

*/
delete obj.name;
console.log(obj.name); // 删除以后在进行查找就变成undefined

属性名和属性值

属性名

  • 对象中的属性名不强制要求遵守标识符的规范
  • 什么乱七八糟的名字都可以使用
  • 但是我们使用时还是尽量按照标识符的规范去做

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

  • 需要使用另一种方式:
  • 语法: 对象[“属性名”] = 属性值;
  • 读取时也要采用这种方式
  • 使用[] 这种形式去操作属性,更加的灵活
  • 在[] 中可以直接传递一个变量,这样变量是多少就会读取那个属性
// obj.123 = 789; 会报错
obj["123"] = 789;
obj["nihao"] = "你好";
obj.name = "孙悟空";
var n = "nihao";
console.log(obj["123"]); // 789
console.log(obj[n]); // 你好

属性值

  • JS对象的属性值,可以是任意的数据类型,甚至可以是一个对象
obj.test = true;
obj.test = null;

// 创建一个对象
var obj2 = new Object();
obj2.name = "猪八戒";

// 将obj2设置为obj的属性
obj.test = obj2;
console.log(obj.test.name); // 猪八戒

in运算符

  • 通过该运算符可以检查一个对象中是否含有指定的属性
  • 如果有则返回true,没有则返回false
  • 语法: “属性名” in 对象
console.log(obj.test2); // undefined
// 检查obj中是否含有test2属性
console.log("test2" in obj); // false

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

  • 基本数据类型:String Number Boolean Null Undefined
  • 引用数据类型: Object

基本数据类型变量

  • JS中的变量都是保存到栈内存中的
  • 基本数据类型的值直接在栈内存中存储
  • 值与值之间是独立存在的,修改一个变量不会影响其他的变量
    JavaScript视频 --李立超_第6张图片

引用数据类型

  • 对象是保存在堆内存当中 出现了new意味着在堆内存中开辟了一个空间, 变量中保存的是内存的地址
  • 每创建一个新的对象,就会在堆内存中开辟一个新的空间
  • 而变量中保存的是对象的内存地址(对象的引用)
  • 如果两个变量保存的是同一个对象的引用, 当一个变量通过一个变量修改属性的时候,另一个也会受到影响
var a = 123;
var b = a;
a++;
console.log("a = " + a);
console.log("b  = " + b);

var obj = new Object();
obj.name = "孙悟空";
var obj2 = obj;

// 修改obj中的name属性
obj.name = "猪八戒";
//    obj2 = null;

console.log(obj.name); // 猪八戒 obj2设置为null 不会影响到obj
console.log(obj2.name); // 猪八戒 
  • 当比较两个基本数据类型的时候,就是比较值
  • 而比较两个引用数据类型时,它是比较对象的内存地址
  • 如果两个对象是一模一样的,内存地址不同,也会返回
var c = 10;
var d = 10;
console.log(c == d); // true

var obj3 = new Object();
var obj4 = new Object();
obj3.name = "沙和尚";
obj4.name = "沙和尚";
// console.log(obj3);
// console.log(obj4);
/*
    当比较两个基本数据类型的时候,就是比较值
    而比较两个引用数据类型时,它是比较对象的内存地址
        如果两个对象是一模一样的,内存地址不同,也会返回false

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

JavaScript视频 --李立超_第7张图片

对象字面量

  • 创建一个对象 var obj = new Object();
  • 使用对象字面量来创建一个对象
var obj = {};
console.log(typeof obj); // object
obj.name = "孙悟空";

console.log(obj.name); // 孙悟空

使用对象字面量创建对象

  • 使用对象字面量,可以在创建对象的时候,直接指定对象中的属性
  • 语法:{属性名:属性值, 属性名:属性值…};
  • 对象字面量的属性名,可以加引号也可以不加,建议不加;
    如: “name”:“猪八戒”; name: “猪八戒”,一样的效果
  • 如果要使用一些特殊的名字,则必须加引号
  • 属性名和属性值是一组一组的名值对结构
  • 名和值之间用:连接,多个名值对之间用逗号隔开
  • 如果一个属性之后没有其他的属性了,就不要写逗号
var obj2 = {
    name: "猪八戒",
    age: 28,
    gender: "男",
    test:{name:"沙和尚"}
};
console.log(obj2);
console.log(obj2.test);

函数的简介

函数

  • 函数也是一个对象
  • 除了基本数据类型,一切都是对象,document
  • 函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)
  • 函数中可以保存一些代码在需要的时候调用
  • 使用typeof 检查一个函数对象时,会返回function

放在一个代码块中的形式

{
    console.log("我是第一行");
    console.log("我是第二行");
}
  • 我们在实际开发中很少使用构造函数来创建一个函数对象
  • 可以将要封装的代码以字符串的形式传递给构造函数: 如:函数里面可以传入你想要说的话
  • 创建一个函数对象
var fun = new Function("console.log('hello 这是我第一个函数');");
console.log(typeof fun); // function
  • 封装到函数中的代码不会执行,函数中的代码会在函数调用的时候执行
  • 调用函数语法,函数对象()
  • 当调用函数时,函数中封装的代码会按照顺序执行
fun();

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

/*
    使用函数声明来创建一个函数
    语法 套上中括号表示写不写都行
        function 函数名([形参1,形参2...]){
            语句...
        }
*/
function fun2(params) {
    console.log("这是我的第二个函数!");
    alert("哈哈");
    document.write("kangkang");
}
// 调用函数
fun2();

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

/*
    使用函数表达式来创建一个函数
    var 函数名 = function([形参1,形参2...]){
        语句... 
    }
*/
var fun3 = function(){
   console.log("我是匿名函数中封装的代码");
}; // 整个是一个赋值语句,最好加上分号
fun3();

函数的参数

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

/*
    定义一个用来求两个数和的函数
        可以在函数的() 中指定一个或多个形参(形式参数)
        多个形参之间使用,隔开,声明形参就相当于在函数内部声明了对应的变量
        但是并不赋值
*/
function sum(a, b) {
    console.log(a + b);
}
  • 调用函数时也可以指定相应的形参
sum(1, 2);
sum(123, 456);
  • 调用函数时,解析器不会检查实参的类型
  • 所以要注意:是否有可能会接收到非法的参数
  • 如果有可能需要对参数做检查: 函数的实参可以是任意的数据类型
sum(123, "hello"); // 123hello
sum(true, false); // 1
/*
    调用函数时,解析器也不会检查实参的数量
    多余实参不会被赋值
    如果实参的数量少于形参的数量,则没有对应的实参的形参将是undefined
*/
sum(123, 456, "hello", true); // 579 

函数的返回值

  • 创建一个函数,用来计算三个数的和

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

  • 语法:
             return 值
    
  • return 后的值将会作为函数的执行结果返回
    可以定义一个变量来接收该结果

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

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

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

  • return后可以跟着任意类型的值

function sum(a, b, c) {
    // alert(a + b + c);
    var d = a + b + c;
    // return -- undefined
    return d;
    // alert是没有返回值的
    alert("hello"); // 不执行
}
// 调用函数
// sum(1, 2, 3);
// 变量result的值就是函数的执行结果,
// 函数返回什么result的值就是什么
var result = sum(4, 7, 8);
// alert是没有返回值的
var result = alert("hello"); // 网页会弹出
console.log("result = " + result); //  undefined 

实参可以是任何值

例子一

/*
    定义一个函数,判断一个数字是否是偶数
    如果是则返回true,否则返回false
*/
function isOu(num) {
    /*
    if(num % 2 == 0){
        return true;
    }else{
        return false;
    }
    */
    return num % 2 == 0;
 }
var result = isOu(15);
console.log("result = " + result);

例子二

/*
     定义一个函数,可以根据半径计算一个圆的面积,并返回计算结果
     3.14 * r * r
*/
function mianji(r) {
    return 3.14 * r * r;
}
result = mianji(5);
console.log("result = " + result);

例子三

/*
    创建一个函数,可以在控制台中输出一个人的信息
    可以输出人的name age gender address

    实参可以是任意的数据类型,也可以是一个对象
        当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递

*/
function sayHello(name, age, gender, address) {
    console.log("我是" + name + ",今年我" + age + "岁了," + "我是一个" + gender + "人" + ",我住在" + address);
}
  • 上面这种情况对于参数不好进行很好的把握,包括顺序对应位置等,这一点很是关键
  • 改进
function sayHello(o) {
    // 这样就不用担心参数的顺序问题,这一点还是很关键
    console.log("我是" + o.name + ",今年我" + o.age + "岁了," + "我是一个" + o.gender + "人" + ",我住在" + o.address);
}
// 测试
sayHello("孙悟空",18,"男","花果山");
  • 创建一个对象 + 测试
// 创建一个对象,
var obj = {
    name: "孙悟空",
    age: 18,
    gender: "男",
    address: "花果山"
};
// sayHello(obj);
  • 实参可以是一个对象,也可以是一个函数
function fun(a) {
    console.log("a = " + a); // a = function sayHello(o) 
    a(obj); // 也可以打印出来,这里的a就相当于是sayHello
}
//    fun(sayHello);
// fun(function(){alert("hello")});

/*
    mianji()
        - 调用函数
        - 相当于使用的函数的返回值
        - 冰淇淋机做出来的冰淇淋拿出来了
    mianji
        - 函数对象
        - 相当于直接使用函数对象

*/
fun(mianji); // a就是上述的整个面积函数
fun(mianji(10)); // 函数的返回值作为参数

返回值的类型

  • 先看一个关于return的例子,return可以结束整个函数
function fun(){
    alert("函数要执行了");
    for(var i = 0; i < 5; i++){
        console.log(i);
        if(i == 2){
            // 使用break可以退出当前的循环
            break;
            // continue 用于跳过当次循环
            continue;
            // 使用return可以结束整个函数
            return;
        }
    }
    alert("函数执行完了");
}
fun();
  • 返回值可以是任意的数据类型,
  • 也可以是一个对象,也可以是一个函数(可以是一个对象也可以是一个函数)
function fun2(){
 //    return 10;
     var obj = {name:"沙和尚"};
     return obj;
}
var a = fun2();
console.log("a = " + a);

function fun3(){
    // 在函数里面再声明一个函数
    function fun4(){
        alert("我是fun4");
    }
    // 将fun4 函数对象作为返回值返回
    return fun4;
 //    fun4();
}
//    fun3();
a = fun3();
console.log(a); // 就是返回我们的fun4即可
// a(); // 相当于我们的fun4() 
fun3()(); // 和a() 是一样的

立即执行函数

  • 函数定义完,立即被调用,这种函数叫做立即执行函数
  • 立即执行函数往往只会执行一次
  • 通常有两种常见的形式
(function(){
    alert("我是一个匿名函数");
})();
// 不仅可以直接调用,还可以传递参数
(function(a, b){
    console.log("a = " + a);
    console.log("b = " + b);
})(123, 456);

方法

/*
    创建一个对象
*/
var obj = new Object();
// 向对象中添加属性
obj.name = "孙悟空";
obj.age = 18;
// 对象的属性值可以是任何的数据类型,也可以是一个函数
obj.sayName = function () {
    console.log(obj.name);
};
// console.log(obj.sayName);
// 调方法
obj.sayName(); // 孙悟空
/*
    函数也可以称为对象的属性
    如果一个函数作为一个对象的属性保存
    那么我们称这个函数是这个对象的方法
    调用这个函数就说调用对象的方法(method)
        - 上面的sayName() 就是函数的方法

    但是它只是名称上的区别,
    console.log() 调用console对象的log()方法
*/
var obj2 = {
    name: "猪八戒",
    age: 18,
    sayName: function () {
        console.log(obj2.name);
    }
};
obj2.sayName(); // 猪八戒

枚举对象中的属性

var obj = {
    name:"孙悟空",
    age:18,
    gender:"男",
    address:"花果山"
};
// 枚举对象中的属性
// 使用for...in 语句
/*
     语法:
     for (var 变量 in 对象){

     }
     for...in语句,对象中有几个属性,循环体就会执行几次
     每次执行时,会将对象中的一个属性的名字赋值给变量

*/
for(var i in obj){
 //   console.log(i); // name age ...属性名
   console.log("属性值" +  obj[i]);
}

全局作用域

作用域

  • 作用域指一个变量的作用的范围
  • 在JS中作用域一共有两种作用域
1、全局作用域
    - 直接编写在script标签中的JS代码,都在全局作用域中
    - 全局作用域在我们页面打开时创建,页面关闭时销毁
    - 在全局作用域中有一个全局对象window,我们可以直接使用
        它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
    - 在全局作用域当中,
        - 创建的变量都会作为window对象的属性保存
        - 创建的函数会作为window对象的方法保存
2、函数作用域
function fun(){
               var a = 123;
           }
fun();
console.log(a); // 报错,里面定义的外面不能使用

console.log(window); // 并不是undefined,所以真实存在该对象
var a = 10;
console.log(window.a); // 10
console.log(window.c); // undefined 不会发生报错现象
function fun(){
    console.log("我是function函数");

}
window.fun(); // 和fun() 效果都是一样的
window.alert("你好,我觉得这是可以的,还行")

变量和函数的声明提前

/*
    变量的声明提前
    - 使用var 关键字声明的变量会在所有的代码执行之前被声明(但是不会被赋值)
        - 但是如果声明变量不使用var 关键字,则变量不会被声明提前
    - 函数的声明提前
        - 使用函数声明形式创建的函数function 函数名(){}
            它会在所有代码执行之前就被创建,所以我们可以函数声明之前来调用调用函数
    使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
    - 全局作用域中变量都是全局变量
        在页面中的任意部分都可以访问的到

*/
console.log("b = " + b); // undefined
var b = 123;

/*
    使用函数声明形式创建的函数function 函数名(){}
        -  它会在所有代码执行之前就被创建,所以我们可以函数声明之前来调用调用函数
*/

// fun();
console.log(fun2); // undefined
fun2();
// 函数声明,会被提前创建
function fun() {
    console.log("我是一个fun函数");
}
// 函数表达式不会被提前创建
var fun2 = function () {
    console.log("我是一个fun2函数");
};

函数的作用域

  • 函数作用域 - 整体里面的局部
  • 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
  • 每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的
  • 在函数作用域中可以访问到全局作用域的变量;但是在全局作用域中无法访问到函数作用域的变量
  • 当在函数作用域中操作一个变量的时候:① 它会先在自身作用域中查找,如果有就直接使用;② 如果没有则向上一级作用域中查找, 直到找到全局作用域;③ 如果全局作用域中依然没有找到,则会报错ReferenceError
// 创建一个变量
var a = 10;
function fun() {
    var a = "我是函数中的变量a";
    var b = 20;
    console.log("a = " + a);
    function fun2(){
        // console.log("a = " + a);
        console.log("a = " + window.a); // 就近原则,但是如果想用全局中的a可以用window对象调用
    }
    fun2();
}
fun();
//    fun(); // 互相独立的
// console.log("b = " + b); // 报错
console.log("a = " + a);

/*
    在函数作用域中也有声明提前的特性
    使用var关键字声明的变量,会在函数中所有的代码执行之前被声明

    函数声明也会在函数中的所有代码执行之前执行
*/
function fun3(){
   console.log(a);
   var a = 35;
   fun4();
   function fun4(){
       alert("我是fun4");
   }
}
fun3(); // undefined

// \
/*
    在函数中,不使用var声明的变量都会成为全局变量
*/
var c = 33;
function fun5(){
   console.log("c = " + c);
   c = 10; // 不使用var关键字相当于window.c
}
fun5(); // 33
// 在全局中输出c
console.log("c = " + c); // c = 10
/*
   定义形参就相当于在函数作用域中声明了变量
*/
var e = 23;
function fun6(e){
   // 相当于 var e;
   alert(e); // undefined
}
fun6();

debug

  • 按照图进行相应操作即可
    JavaScript视频 --李立超_第8张图片

this

  • 解析器在调用函数时每次都会向函数内部传递一个隐含的参数
  • 这个隐含的参数就是this,this指向的是一个对象
  • 这个对象我们称为函数执行的上下文对象
  • 根据函数调用的方式不同,this会指向不同的对象:① 以函数的形式调用时,this永远都是window ② 以方法的形式调用时,this就是调用方法的那个对象
function fun(a, b){
    console.log("a = " + a + ", b = " + b);
    console.log(this.name);
}
fun(123, 456);

//创建一个对象
var obj = {
    name:"孙悟空",
    sayName:fun
};
// 继续创建一个新的对象
var obj2 = {
    name:"猪八戒",
    sayName:fun
};
// console.log(obj.sayName == fun); // true

var name = "全局的name属性";
// obj.sayName();
// 以函数形式调用,this是window
// fun(); // 全局的name属性

// 以方法的形式调用,this是调用方法的对象
obj.sayName(); // 孙悟空
obj2.sayName(); // 猪八戒

this的补充(往往是在程序中的应用)

// 创建一个name变量
var name = "全局";

// 创建一个sayName() 函数
function fun(){
    // console.log(name); 写死了,只会找obj.name 
    // console.log(obj.name); // 孙悟空 往往也出现固定值
    // 以方法的形式调用时,this就是调用方法的那个对象
    console.log(this.name); // 
}
// 创建两个对象
var obj = {
    name:"孙悟空",
    sayName:fun
};
var obj2 = {
    name:"猪八戒",
    sayName:fun
};
fun(); // 全局
// 我们希望调用obj.sayName()时可以输出obj的名字
obj.sayName();  // 孙悟空
obj2.sayName(); // 猪八戒

使用工厂方法创建对象

  • 使用工厂方法创建对象,通过该方法可以大批量生产对象
  • 创建一个对象
var obj = {
    name: "孙悟空",
    age: 18,
    gender: "男",
    sayName: function () {
        alert("this.name");    }
};
// 测试
obj.sayName(); // 孙悟空
  • 创建了一个新的对象,工厂方法写死了
function createPerson(){
    // 创建一个新的对象
    var obj = new Object();
    // 向对象中添加属性
    obj.name = "孙悟空";
    obj.age = 18;
    obj.gender = "男";
    obj.sayName = function(){
        alert(this.name);
    };
    // 将一个新的对象返回
    return obj;
}
  • 上面创建的方法写死了,我们可以在方法里面传入相应的参数,这样就不会写死了
function createPerson(name, age, gender) {
    // 创建一个新的对象
    var obj = new Object();
    // 向对象中添加属性
    obj.name = name;
    obj.age = age;
    obj.gender = gender;
    obj.sayName = function () {
        alert(this.name);
    };
    // 将一个新的对象返回
    return obj;
}
//    var obj2 = createPerson();
//    var obj3 = createPerson();
var obj4 = createPerson("kangkang", 23, "男");
//    console.log(obj2); // Object 空的
console.log(obj4);
obj4.sayName(); // 弹出kangkang

构造函数

  • 用来创建一个基本的对象 - 使用的不多
function createDog(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.sayHello = function () {
        alert("汪汪");
    };
    // 没有写的话默认返回undefined
    return obj; // JS中每一个函数都是需要有返回值
}
  • 使用工厂方法创建的对象,有一个很大的弊端就是:使用的构造函数都是Object类型,所以创建的对象都是Object类型,导致无法区分出多种不同类型的对象。
// 创建狗的对象
var dog = createDog("旺财", 3);
dog.sayHello();
console.log("dog = " + dog); // Object 类型
//    console.log(obj4) // 前一个代码中的人对象的变量
  • 上面创建函数在返回的时候都是Object类型, 没有本质区别
  • 使用构造函数的形式来构造函数,专门用来创建Person对象的
  • 构造函数就是一个普通的函数,创建方式和普通函数没有区别; 不同的是构造函数习惯上首字母大写 !!!
  • 构造函数和普通函数的区别在于调用方式的不同
  • 普通函数是直接调用,而构造函数需要new关键字来调用
  • 构造函数的执行流程:1、立刻创建一个新的对象 2、将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象 3、逐行执行函数中的代码 – 只有第三个是我们干的,这一点还是很关键的 4、将新建的对象作为返回值返回
  • 使用同一个构造函数创建的对象,我们称为一类函数,也将一个构造函数称为一类,我们将通过一个构造函数创建的对象,称为该类的实例:如:per是Person类的实例

this的情况

  • 当以函数的形式调用时,this就是window
  • 当以方法的形式调用时,谁调用方法this就是谁
  • 当以构造函数的形式调用时,this就是新创建的那个对象

没有参数,写死的情况,方式一

function Person() {
    // alert("hello");
    // alert(this); // this就是新创建的对象
    // this就是新建的对象,其实就是per
    this.name = "孙悟空";
    this.age = 18;
    this.gender = "男";
    this.sayName = function(){
        alert(this.name);
    };
}

有参数,没有写死,比较灵活的情况,进行相应的改造

function Person(name, age, gender) {
    // alert("hello");
    // alert(this); // this就是新创建的对象
    // this就是新建的对象,其实就是per
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.sayName = function () {
        alert(this.name);
    };
}
  • 对上面两种方式分别进行构造
// 方式一构造
// var per = new Person();
// 方式二构造
var per = new Person("孙悟空", 18, "男");
  • 作为普通函数进行调用的情况
// console.log(per); // Object 只是一个简单的对象而已
console.log(per.name);
console.log(per);
  • 再创建一个狗的构造函数
// 在搞一个狗的
function Dog() {

}
var dog = new Dog();
console.log(dog);
// 构造函数就是一个类
/*
    使用instanceof可以检查一个对象是否是一个类的实例
    语法 
        对象 instanceof 构造函数
*/
console.log(per instanceof Person); // true
console.log(dog instanceof Person); // false
  • 所有的对象都是Object的后代
  • 所以任何对象和Object做instanceof检查时都会返回true
console.log(per instanceof Object); // true

构造函数的修改

  • 实际例子:创建一个Person构造函数
  • 在Person构造函数中,为每一个对象都添加了一个sayName方法
  • 目前我们的方法是在构造函数内部创建的
  • 也就是构造函数每执行一次就会创建一个新的sayName方法
  • 也是所有实例的sayName都是唯一的
  • 这样就导致构造函数执行一次就会创建一个新的方法:① 执行10000次就会创建10000个新的方法,而10000个方法都是一模一样的 ② 这是完全没有必要,完全可以使所有的对象共享同一个方法

第一种方式

function Person(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    // 向对象中添加一个方法
    // this.sayName = function () {
    //     alert("Hello大家好,我是:" + this.name);
    // };
    // this.sayName = sayHello; 下面写了原型方法,内部就不需要在书写了
}

第二种方式 - 对第一种的改进

  • 改进就是将sayName方法在全局定义域中定义
  • 但是将函数定义在全局作用域中,污染了全局作用域的命名空间;而且定义在全局作用域中也很不安全
function fun() {
    alert("Hello大家好,我是:" + this.name);
};

第三种方式- 对第二种的改进

  • 使用原型方法,向原型中添加sayName方法
Person.prototype.sayName = function(){
    alert("Hello大家好,我是:" + this.name);
};
  • 创建实例
var per = new Person("孙悟空", 18, "男");
var per1 = new Person("猪八戒", 18, "男");
// 调用原型方法
per.sayName();
// 改进前
// console.log(per.sayName == per1.sayName); // false
// 改进后
console.log(per.sayName == per1.sayName); // true

原型对象

  • 原型prototype
  • 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
  • 这个属性对应着一个对象, 这个对象就是我们所谓的原型对象
  • 如果函数作为普通函数调用prototype没有任何作用
  • 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性;指向该构造函数的原型对象 我们可以通过__proto__来访问该属性
  • 原型对象相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象; 我们可以将对象中所有的内容,统一设置到原型对象中
  • 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用 ; 如果没有则会在原型对象中寻找,如果找到则直接使用,
  • 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象具有这些属性和方法
function Myclass() {

}

// 向Myclass的原型中添加属性a 
Myclass.prototype.a = 123;

// 向Myclass的原型中添加一个方法
Myclass.prototype.sayHello = function () {
    alert("hello");
};
var mc = new Myclass();
var mc2 = new Myclass();
//    console.log(Myclass.prototype); // Object 每一个函数都有自己的
console.log(mc.__proto__ == Myclass.prototype); // true
console.log(mc2.__proto__ == Myclass.prototype); // true
// 向mc中添加a属性
mc.a = "我是mc中的a";

console.log(mc.a); // 我是mc中的a
console.log(mc2.a); // 123

mc.sayHello(); // mc中虽然没有但是,原型中有,也是可以直接使用的

原型对象中的方法

  • 使用in 方法检查对象中是否含有某个属性,如果对象中没有但是原型中有,也会返回true
  • 可以使用对象的hasOwnProperty() 来检查对象自身中是否含有该属性 - 使用该方法只有当对象自身中含有属性时,才会返回true
/*
    创建一个构造函数
*/
function Myclass() {

}
// 向Myclass的原型中添加一个name属性
Myclass.prototype.name = "我是原型中的名字";
var mc = new Myclass();
mc.age = 18;
// console.log(mc.name);
// 使用in 检查对象中是否含有某个属性,如果对象中没有但是原型中有,也会返回true
// console.log("name" in mc); // true
// 可以使用对象的hasOwnProperty() 来检查对象自身中是否含有该属性
// 使用该方法只有当对象自身中含有属性时,才会返回true
console.log(mc.hasOwnProperty("name")); // false 确实没有定义name
console.log(mc.hasOwnProperty("age")); // 关于属性一定要用冒号冒起来
console.log(mc.hasOwnProperty("hasOwnProperty")); // 自己本身是没有的,是存在于原型当中
/*
      原型对象也是对象,所以它也是原型
      当我们使用一个对象的属性或方法时,会先在自身中寻找
          自身中如果有,则直接使用
          如果没有则去原型对象中寻找,如果原型对象中有,则使用
          如果没有则去原型的原型中寻找,直到找到Object对象的原型
          Object对象的原型没有原型,所以在Object依然没有找到,则返回undefined
          - 意思就是到Object就到头了,这一点还是很关键,就是如此。
*/
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); // true 原型中的原型是有的
//console.log(mc.__proto__.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); // null 已经找不到了,会报错
console.log(mc.__proto__.__proto__.__proto__); // null

toString() 的使用

function Person(name, age, gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
}
// 想要修改Person原型的toString,则要对原型进行相应的修改操作
Person.prototype.toString = function(){
    "Person[name = " + this.name +", age = " + this.age + ",gender =" + this.gender + "]";
};
  • 创建一个Person实例
var per = new Person("孙悟空", 18, "男");
var per2 = new Person("猪八戒", 19, "男");
  • 当我们直接在页面中打印一个对象时,实际上输出的是对象的toString() 方法的返回值
  • 如果我们希望在输出对象时不输出[Object Object]可以为对象添加一个toString() 方法,希望打印详细信息,可以 Person[name=孙悟空, age=18, gender=男] ,但是那只是针对一个对象进行修改。
per.toString = function(){
    // 为了防止写死,可以使用this关键字,
    return "Person[name = " + this.name +", age = " + this.age + ",gender =" + this.gender + "]";
}
// 测试
console.log(per); // 返回的一个Person对象
// console.log(per); // 返回的一个Person对象
var result = per.toString();
// console.log("result = " + result); // result = [object Object]
// 某一个对象的原型的原型就是Object
console.log(per.__proto__.__proto__.hasOwnProperty("toString"));// true

console.log("result = " + result); // result = 我是一个快乐的小Person
console.log(per);
console.log(per2); // 这样和per就变成是一样的了,都是Person类别

垃圾回收(GC)

  • 就像人生活的时间长了会产生垃圾一样,程序运行过程中也会产生垃圾
  • 这些垃圾积攒过多,会导致程序运行的速度过慢;所以我们需要一个垃圾回收机制,来处理程序运行过程中产生的垃圾
  • 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象; 此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行过慢; 所以这种垃圾必须进行清理
  • 在JS中拥有自动的垃圾回事机制,会自动将这些垃圾对象从内存中销毁, 我们不需要也不能进行垃圾回收机制
  • 我们需要做的只是将这些不要使用的对象设置为null即可
var obj = new Object();
// 对对象进行各种操作。。。,这个对象的地址
// 需要回收就进行下面这种操作即可
obj = null;

70 - 79

数组简介

  • 对象:内建对象、宿主对象、自定义对象
  • 数组(Array)
  • 数组也是一个对象;它和普通的对象类似,也是用来存储一些值的;不同的是普通对象是使用字符串作为属性名的;而数组是使用数字来作为索引操作元素的
  • 索引:从0开始的一个整数
  • 数组的存储性能比普通对象好,在开发中我们经常使用数组来存储一些数据
// 创建一个数组对象
var arr = new Array();
// 使用typeof检查一个数组时,会返回Object
// console.log(typeof arr);
/*
     向数组中添加元素
     语法:数组[索引] = 值
*/
arr[0] = 10;
arr[1] = 33;
arr[2] = 22;
console.log(arr);
  • 读取数组中的元素
/*
    读取数组中的元素
    语法:数组[索引]
    如果读取不存在的索引,它不会报错,而是返回undefined
*/
console.log(arr[1]); // 33
console.log(arr[3]); // undefined
  • 获取数组的长度,
  • 可以使用length属性来获取数组的长度(元素的个数)
  • 语法:数组.length
  • 对于连续的数组,使用length可以获取到数组的长度(元素的个数)
  • 对于非连续的数组,使用length会获取到数组的最大索引 + 1:① 其实就是数组的长度 ② 尽量不要创建非连续的数组
console.log(arr.length); // 3
  • 修改数组长度
  • 如果修改的length大于原长度,则多出部分会空出来
  • 如果修改的length小于原长度,则多出来的元素会被删除
arr.length = 10;
console.log(arr.length);

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

数组字面量

// 创建一个数组
// var arr = new Array();
  • 使用字面量来创建数组
// 语法:[] 更加简单方便
// var arr = [];
// console.log(typeof arr); // object
  • 使用字面量创建数组时,可以在创建时就指定数组中的元素
var arr = [1, 2, 3, 4, 5, 10];
console.log(arr); // 显示的就是一个数组
console.log(arr.length); // 6
console.log(arr[0]); // 1
  • 使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作为构造函数的参数传递
  • 元素之间使用,隔开
var arr2 = new Array(10, 20, 30); // 使用的是括号包裹住才行
// console.log(arr2);
// 创建一个数组,里面只有一个元素1
arr = [10];
// 创建一个长度为10的数组,用的不多,因为长度没有限制
arr2 = new Array(10);
console.log(arr.length);
  • 数组中的元素可以是任意的数据类型
arr = ["hello", 1, true, null, undefined];
console.log(arr);
  • 数组中也可以是一个对象
var obj = {name:"孙悟空"};
arr[arr.length] = obj;
console.log(arr[5]); // object 直接就是一个对象
  • 或者直接这样看,直接往数组里面存对象即可
arr = [{name:"孙悟空"}, {name:"沙和尚"}, {name:"猪八戒"}];
console.log(arr); // 打印出来就是三个对象
  • 数组中也可以存一个函数
// 也可以是一个函数
arr = [function(){alert(1)}, function(){alert(2)}];
// console.log(arr); // 直接就是两个函数
// arr[0](); // 弹出
  • 数组中也可以放数组,如下这种数组我们称为二维数组
arr = [[1, 2, 3], [3, 4, 5], [5, 6, 7]];
console.log(arr[1]);

数组中的四个方法

push()

  • 该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
  • 可以将要添加的元素作为方法的参数传递;这样这些元素将会自动添加到数组的末尾
  • 该方法会将数组新的长度作为返回值返回
var result = arr.push("唐僧", "蜘蛛精", "白骨精");
console.log(arr);
console.log("result = " + result); // 6

pop()

  • 该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
result = arr.pop();
console.log(arr);
console.log("result = " + result);

unshift()

  • 向数组开头添加一个或多个元素,并返回新的数组长度
  • 向前边插入元素以后,其他的元素索引会依次调整
console.log(arr);
arr.unshift("牛魔王");
console.log(arr); // 牛魔王向第一个位置添加即可

shift()

  • 可以删除数组的第一个元素,并将删除的元素作为返回值返回
console.log(arr);
var result = arr.shift();
console.log("result = " + result);
console.log(arr);

数组的遍历

// 创建一个数组
var arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"];
// 所谓的遍历,就是将数组中所有的元素都取出来
for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

数组的练习

  • 创建一个Person对象
// 练习
function Person(name, age){
    this.name = name;
    this.age = age;
}
  • 修改Person原型的toString方法
Person.prototype.toString = function(){
      return "Person[name = "+ this.name + ", age="+ this.age +"]";
 }
  • 创建一系列Person对象
var per = new Person("孙悟空", 18);
var per2 = new Person("猪八戒", 28);
var per3 = new Person("红孩儿", 8);
var per4 = new Person("蜘蛛精", 16);
var per5 = new Person("二郎神", 38);
// console.log(per);
  • 将这些person对象放入到一个数组当中
var perArr = [per, per2, per3, per4, per5];
  • 练习要求
/*
     创建一个函数,可以将perArr中的满18岁的Person提取出来
     然后封装到一个新的数组中并返回

     arr 
         形参,要提取信息的数组
*/
  • 具体实现步骤
function getAdult(arr){
    // 创建一个新的数组
    var newArr = [];

    // 遍历arr获取数组中的Person对象

    // 判断Person对象的age是否大于等于18

    // 如果大于等于18,则将这个对象添加到newArr中
    
    // 将这个新的数组返回
    return newArr;

}
var result = getAdult(arr);
console.log("result = " + result);
  • 题目要求就是求取符合要求的数组
// 练习
function Person(name, age, gender) {
    this.name = name;
    this.age = age;

}
// 修改Person原型的toString方法
Person.prototype.toString = function () {
    return "Person[name = " + this.name + ", age=" + this.age + "]";
}

// 创建一个Person对象
var per = new Person("孙悟空", 18);
var per2 = new Person("猪八戒", 28);
var per3 = new Person("红孩儿", 8);
var per4 = new Person("蜘蛛精", 16);
var per5 = new Person("二郎神", 38);
// console.log(per);

/*
    将这些person对象放入到一个数组当中
*/
var perArr = [per, per2, per3, per4, per5];
/*
     创建一个函数,可以将perArr中的满18岁的Person提取出来
     然后封装到一个新的数组中并返回

     arr 
         形参,要提取信息的数组
*/
function getAdult(arr) {
    // 创建一个新的数组
    var newArr = [];

    // 遍历arr获取数组中的Person对象
    for (var i = 0; i < arr.length; i++) {
        // console.log(arr[i]);
        var p = arr[i];
        // 判断Person对象的age是否大于等于18
        if (p.age >= 18) {
            // 如果大于等于18,则将这个对象添加到newArr中
            // 将对象放入到新数组当中
            newArr.push(p);
        }
    }
    // 将这个新的数组返回
    return newArr;
}
var result = getAdult(perArr); // 把所有符合结果的数组返回出来即可
console.log("result = " + result);

forEach

  • 一般我们都是使用for循环去遍历数组;
  • JS中还为我们提供了一个方法,用来遍历数组 – forEach()
  • 这个方法只支持ie8以上的浏览器;IE8及以下的浏览器不支持该方法,如果不兼容的时候,还是使用for循环会更加方便一点

创建一个数组

var arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"];

//    function fun(){

//    }

forEach()的关键点

  • 需要一个函数作为参数,为了方便使用我们会直接使用一个匿名函数
  • 像这种函数,由我们创建但是不是由我们进行调用,我们称之为回调函数。
  • 数组中有几个元素就执行几次,每次执行时,浏览器会将遍历到的元素; 以实参的形式传递进来,我们可以定义形参来读取这些内容
  • 浏览器会在回调函数中传递三个参数:① 第一个参数,就是当前正在遍历的元素 ② 第二个参数,就是当前正在遍历的元素的索引 ③ 第三个参数,就是正在遍历的数组
arr.forEach(function (value, index, obj) {
    // console.log("a = " + a);
    console.log(value); // 所有的元素
});

slice和splice

slice()

  • 可以来从数组中提取元素
  • 该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回
  • 参数:① 截取开始的位置的索引(包含开始) ② 截取结束的位置的索引(不包含结束索引)
  • 注意点:① 第二个参数可以省略不写,此时会截取从开始索引往后的所有元素 ② 索引可以传递一个负值,如果传递一个负值,则从后往前计算 — -1 倒数第一个,-2 倒数第二个
// 创建一个数组
var arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"];
var result = arr.slice(0, 2);
var result1 = arr.slice(1);
var result2 = arr.slice(1, -2);
console.log(arr); // 原数组不会被改变
console.log("result = " + result); // 孙悟空,猪八戒
console.log("result1 = " + result1); // 猪八戒,沙和尚,唐僧,白骨精
console.log("result2 = " + result2); // 猪八戒,沙和尚

splice()

  • 可以删除元素,也可以添加元素 ;可以删除数组中的指定元素
  • 使用splice() 会影响到原数组,会将指定元素从原数组中删除;并将被删除的元素作为返回值返回
  • 参数:① 第一个 表示开始位置的索引 ② 第二个 表示删除的数量
    ③ 第三个 及以后可以传递一些新的元素 - 可以插入多个元素;这些元素将会自动插入到开始位置索引的前面
// var result3 = arr.splice(0, 2);
// console.log(arr);
// console.log(result3); // ['孙悟空', '猪八戒']
arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"];
var result4 = arr.splice(0, 1, "牛魔王");
console.log(arr); // ['牛魔王', '猪八戒', '沙和尚', '唐僧', '白骨精'] 进行了一个简单的替换

去除数组中重复的元素

  • 注意那个j–
// 创建一个数组 思路一,自己的一个简单思路
var arr = [1, 2, 3, 2, 2, 2, 1, 3, 4, 2, 5];
for (var i = 0; i < arr.length; i++) {
    for (var j = i + 1; j < arr.length; j++) {
        if (arr[i] == arr[j]) {
            arr.splice(j, 1);
            // 当删除了当前j所在的元素以后,后边的元素会自动补位
            // 此时将不会比较这个元素,我需要在比较一次j所在位置的元素
            // 使得j--,这样就会接着往下面进行比较即可,下面这个步骤极其关键
            j--;
        }
    }
}
console.log(arr); // 确实还是可以的

数组的剩余方法

concat()

  • 可以连接两个或多个数组,并将新的数组返回
  • 该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
  • 在join() 中可以指定一个字符串作为参数,这个字符串会成为数组中元素的连接符
// 创建三个数组测试
var arr = ["孙悟空", "猪八戒", "沙和尚"];
var arr2 = ["白骨精", "玉兔精", "蜘蛛精"];
var arr3 = ["二郎神", "太上老君", "玉皇大帝"];
var result = arr.concat(arr2);
console.log(result); //  ['孙悟空', '猪八戒', '沙和尚', '白骨精', '玉兔精', '蜘蛛精']
var result2 = arr.concat(arr2, arr3, "kangkang"); // 里面不仅可以传数组还可以传元素
console.log(result2); // ['孙悟空', '猪八戒', '沙和尚', '白骨精', '玉兔精', '蜘蛛精', '二郎神', '太上老君', '玉皇大帝', 'kangkang']

join()

  • 该方法可以将数组转换为一个字符串
  • 该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
  • 如果不指定连接符,则默认使用,作为连接符
result = arr.join();
result2 = arr.join("hello");
console.log("result2 = " + result2); // 孙悟空hello猪八戒hello沙和尚
console.log("result = " + result); // 是一个字符串类型
console.log(typeof result); // string

reverse()

  • 该方法用来反转数组(前边的去后边,后边的去前边)
  • 该方法会直接修改原数组
arr.reverse();
console.log(arr); // ['沙和尚', '猪八戒', '孙悟空']
arr = ["b", "d", "e", "a", "c"];

sort()

  • 可以用来对数组中的元素进行排序;也会影响原数组。默认会按照Unicode编码进行排序
  • 即使对于纯数字的数组,使用sort排序时候也会使用Unicode编码进行排序 - 所以对数字进行排序的时候可能会得到错误的结果
  • 所以我们可以自己来指定排序的规则;我们可以在sort() 添加一个回调函数来指定排序规则;回调函数中需要定义两个形参
  • 浏览器将会分别使用数组中的元素作为实参去调用回调函数; 使用哪个元素调用不确定,但是肯定的是在数组中a一定在b的前面
  • 浏览器会根据回调函数的返回值来决定元素的顺序;如果返回一个大于0的值,则元素会交换位置;如果返回一个小于0的值,则元素位置不变;如果返回一个0,则认为两个元素值相等,则不会交换位置
  • 上面比较复杂,其实可以:如果需要升序排列,则返回a - b;如果需要降序排列,则返回b - a
arr = [5, 4, 3, 2, 1];
arr.sort(function (a, b) {
    // 前边的大
    /*
    if(a > b){
        return 1;
    }else if(a < b){
        return -1;
    }else{
        return 0;
    }*/
    return a - b;
    // return b - a;
});
console.log("arr = " + arr);
//    arr.sort();
//    console.log(arr); //  ['a', 'b', 'c', 'd', 'e']

//    arr = [3, 4, 11, 2, 5];
//    arr.sort();
//    console.log(arr); // [11, 2, 3, 4, 5]

call和apply

  • 这两个方法都是函数对象的方法,需要通过函数对象来调用;把括号去掉 fun 才是一个对象
  • 当对函数调用call() 和 apply() 都会调用函数执行
  • 在调用call和apply() 可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的一部分
  • call()方法可以将实参在对象之后依次传递
  • apply() 方法需要将实参 封装到一个数组中统一传递,
  • this的几种情况:① 以函数的形式调用时,this永远都是window ② 以方法的形式对象调用时, this是调用方法的对象 ③ 以构造函数的形式调用时,this是新创建的那个对象 ④ 使用call和apply调用时,this是指定的那个对象,第一个对象指定的是谁就是谁
function fun() {
     alert(this.name);
 }
 /*fun.call();
 fun.apply();
 fun();*/

 var obj = {};
 // fun.call(obj);

 // fun(); Object Window
 // fun.call(obj); object Object

 // obj = {name:"obj"};
 // var obj2 = {name:"obj2"};

 // fun.call(obj); // obj

 // 创建一个新的对象
 // var obj = {
 //     name:"obj", 
 //     sayName:function(){
 //         alert(this.name);
 //     }
 // };
 // var obj2 = {
 //     name:"obj2"
 // };


 // obj.sayName(); // obj
 // obj.sayName.apply(obj2); // obj2 参数是谁this就是谁


 // 接着演示,给函数定义两个形参
 function fun1(a, b) {
     console.log("a = " + a);
     console.log("b = " + b);
 }
 // 对象obj就是应该在这个位置
 var obj = {
     name: "obj",
     sayName: function () {
         alert(this.name);
     }
 };
 // call()方法可以将实参在对象之后依次传递
 fun1.call(obj, 2, 3);
 fun1.apply(obj, [2, 3]); // apply后面是要用到数组的形式

80-89

arguments

  • 在调用函数时,浏览器每次都会传递进两个隐含的参数:①
    函数的上下文对象, this ② 封装实参的对象 arguments
  • arguments是一个类数组对象,不是一个数组
  • 它也可以通过索引来操作数据,也可以获取长度
  • 在调用函数时,我们所传递的实参都会在arguments中保存
  • arguments可以获取实参的长度, 我们即使不定义形参,也可以通过arguments来使用实参;只不过比较麻烦 arguments[0] 表示第一个实参
  • 它里面还有一个属性callee; 这个属性对应一个函数对象,就是当前正在指向的函数的对象
function fun() {
    // console.log(arguments);
    console.log(arguments instanceof Array); // false
    console.log(Array.isArray(arguments)); // false
    console.log(arguments.length); // 不传的话就是0 
    console.log(arguments[0]); // kang
    // 下面这个就是指向函数的对象,里面包含了这个函数的一切
    console.log(arguments.callee);

}
fun("kang");

Date对象

  • 在JS中使用Date对象来表示一个时间
  • 创建一个Date对象,如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间。
var d = new Date(); 
  • 创建一个指定的时间对象,需要在构造函数中传递一个表示时间的字符串作为参数
  • 日期的格式:月份/日/年 时:分:秒 (年份要完整)
var d2 = new Date("12/04/2016 11:10:30");
console.log(d2);

getDate()

  • 获取当前日期对象是几日
var date = d2.getDate();

getDay()

  • 获取当前日期对象是周几
  • 0表示周日 1表示周一
var day = d2.getDay();

getMonth()

  • 获取当前时间对象的月份
  • 会返回一个0-11的值:0 表示1月;1 表示2月; 11表示12月…
var month = d2.getMonth();

getFullYear()

  • 获取当前日期对象的年份
d2 = new Date("12/04/2016 11:10:30");
var year = d2.getFullYear();
console.log("date = " + date);
console.log("day = " + day);
console.log("month = " + month); // 11
console.log("year = " + year); // 2016

getTime()

  • 获取当前日期对象的时间戳
  • 时间戳,指的是从格林威治标准时间的1970年1月1,0时0分0秒; 到当前日期所花费的毫秒数(1秒 = 1000毫秒)
  • 计算机底层在保存时间时使用的都是时间戳
  • 可以进行单位的换算,换成以年为单位
var time = d2.getTime();
console.log("time = " + time / 1000 / 60 / 60 / 24 / 365); // 46年

var d3 = new Date("1/1/1970 0:0:0");
time = d3.getTime();
console.log(time); // -28800000 因为是和北京时间有时差
  • 利用时间戳测试代码的执行的性能
  • 获取当前的时间戳
var start = Date.now();
for (var i = 0; i < 100; i++) {
    console.log(i);
}
var end = Date.now();
console.log("执行了:" + (end - start) + "ms"); // 加上括号要不然会有歧义

Math

  • Math和其他的对象不同,它不是一个构造函数
  • 它属于一个工具类不用创建对象,它里边封装了数学运算相关的属性和方法
  • 比如Math.PI 表示圆周率
console.log(Math.PI); // 3.141592653589793
  • abs() 可以用来计算一个数的绝对值
console.log(Math.abs(-1)); // 1
  • Math.ceil() - 可以对一个数进行向上取整,小数位只要有值就自动进1
console.log(Math.ceil(1.4)); // 2
  • Math.floor() - 可以对一个数进行向下取整,小数部分会被舍弃掉
console.log(Math.floor(1.99)); // 1
  • Math.round() - 可以对一个数进行四舍五入取整操作
console.log(Math.round(1.4)); // 1
  • Math.random():① 可以用来生成0-1之间的随机数 ② 生成一个0-10的随机数
  • 生成一0-x之间的随机数
Math.round(Math.random()*x)
  • 生成一个x-y之间的随机数
Math.round(Math.random()*(y-x) + x)
  • 生成100个随机数
// 生成100个随机数
for(var i = 0; i < 100; i++){
    console.log(Math.round(Math.random()*9) + 1); // 1-10
}
  • 练习:生成一个1-6之间的随机数
console.log(Math.round(Math.random() * 5 + 1));
  • max() 和 min()
  • max() 可以获取多个数中的最大值
  • min() 可以获取多个数中的最小值
var max = Math.max(10, 40, 30);
var min = Math.min(1, 4, 0.5);
console.log(max);
console.log(min);
  • **Math.pow(x, y) ** - 返回x的y次幂
  • Math.sqrt(x)- 返回x的开方即可
console.log(Math.pow(2, 3)); // 8
console.log(Math.sqrt(4)); // 2

包装类

  • 基本数据类型:String Number Boolean Null Undefined
  • 引用数据类型: Object
  • 三个包装类:在JS中为我们提供了三个包装类;通过这三个包装类可以将基本数据类型的数据转换为对象
  • String() - 可以将基本数据类型字符串转换为String对象
  • Number() - 可以将基本数据类型的数字转换为Number对象
  • Boolean() - 可以将基本数据类型的布尔值转换为Boolean对象
  • 但是注意,我们在实际应用中不会使用基本数据类型的对象;如果使用基本数据类型的对象,在做一些比较时,经常出现错误
  • 创建一个Number类型的对象
var num = new Number(3);
var num2 = new Number(3);
var str = new String("hello");
var bool = new Boolean(true);
console.log(typeof num); // object
  • 向num中添加一个属性
num.hello = "abcdef";
console.log(num.hello); // abcdef

console.log(num == num2); // false
  • 重点!!!
var b = new Boolean(false);
if (b) {
    alert("我运行了~~~"); // 因为b其实就是一个对象,任何对象转换成布尔值都为true
}
  • 方法和属性只能添加给对象,不能添加给基本数据类型
  • 当我们对一些基本数据类型的值去调用属性和方法时 - 先调用Number对象;浏览器会临时使用包装类将其转换为对象,然后在调用对象的属性和方法;调完以后,在将其转换为基本数据类型
var s = 123;
s = s.toString();

s.hello = "你好";
console.log(s);
console.log(typeof s);
console.log(s.hello); // undefined 实际上在转换的时候有两个对象,在调用的时候,对象2是没有hello属性的

字符串的方法

  • 创建一个字符串
var str = "Hello Atguigu";
  • 在底层字符串是以字符数组的形式保存的
["H", "e", ....llo Atguigu]

length属性 - 可以用来获取字符数组的长度

console.log(str.length);
console.log(str[1]); // e

charAt()

  • 可以返回字符串中指定位置的字符
  • 根据索引获取指定的字符
str = "Hello Atguigu";
var result = str.charAt(0);
console.log(str);
console.log("result = " + result); // H

charCodeAt()

  • 获取指定位置字符的字符编码(Unicode编码)
result = str.charCodeAt(0);
console.log("result = " + result); // 72

String.fromCharCode() - 通过构造函数调用的

  • 可以根据字符编码去获取字符
result = String.fromCharCode(72);
console.log("result = " + result); // H

concat()

  • 可以用来连接两个或多个字符串
  • 作用和 + 一样
result = str.concat("你好");
console.log(result); // Hello Atguigu你好

indexOf()

  • 该方法可以检索一个字符串中是否含有指定内容
  • 如果该字符串中含有该内容,则会返回其第一次出现的索引; 如果没有找到指定的内容,则返回-1
  • 可以指定一个第二个参数,指定开始查找的位置
str = "hello hAtGuigu";
result = str.indexOf("h");
console.log("result = " + result); // 0

result = str.indexOf("h", 1);
console.log("result = " + result); // 6

lastIndexOf()

  • 该方法的用法和indexOf() 一样;不同的是indexOf()是从前往后找, 而lastIndexOf()是从后往前找
  • 也可以指定第二个参数 - 指定开始查找的位置
result = str.lastIndexOf("h");
console.log("result = " + result); // 6

slice()

  • 可以从字符串中截取指定的内容
  • 不会影响原字符串,而是将截取到的内容返回
  • 参数:① 开始位置的索引(包括开始位置)② 结束位置的索引(不包括结束位置);如果省略第二个参数,则会截取到后面所有的
  • 也可以传递一个负数作为参数,负数的话将会从后边计算
str = "abcdefghijk";
result = str.slice(0, 2);
console.log("result = " + result);

subString()

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

console.log("result = " + result);
// 如果第二个参数小于第一个,则自动交换位置
result = str.substring(2, -1);
console.log("result = " + result);

substr()

  • 用来截取字符串,对原数组没有影响
  • 参数:第一个参数:截取开始位置的索引;第二个参数:截取的长度
str = "abcdefg";
result = str.substr(3, 2);
console.log("result = " + result); // de

split()

  • 可以将一个字符串拆分为一个数组
  • 参数:需要一个字符串作为参数,将会根据该字符串去拆分数组
 str = "abc,bcd,efg,hij";
 result = str.split(",");
 console.log("result = " + result);
 console.log(typeof result); // object
 console.log(Array.isArray(result)); // true
 console.log(result[0]); // abc
 console.log(result.length); // 4
  • 如果传递一个空串作为参数,则会将每个字符都拆分成为数组中的一个元素
result = str.split("");
console.log("result = " + result); // a,b,c,,,b,c,d,,,e,f,g,,,h,i,j
  • toUpperCase() - 将一个字符串转换为大写并返回
str = "abcdefg";
result = str.toUpperCase();
console.log("result = " + result); // ABCDEFG

result2 = result.toLowerCase();
console.log("result2 = " + result2); // abcdefg

正则表达式的简介

  • 正则表达式可用于邮件编写的测试

正则表达式
- admin
- [email protected]
- [email protected] 错误
- 邮件的规则:
1、前边可以是xxxx乱七八糟
2、跟着一个@
3、后边可以是xxxx乱七八糟
4、.com 获取其他的乱七八糟
- 正则表达式用于定义一些字符串的规则
计算机可以根据正则表达式,来检查一个字符串是否符合规则
获取将字符串中符合规则的内容提取出来

  • 创建正则表达式对象
  • 语法:
var 变量 = new RegExp("正则表达式", "匹配模式");
  • 使用typeof检查正则对象,会返回object
  • 这个正则表达式可以用来检查一个字符串中是否含有a
  • 在构造函数中可以传递一个匹配模式作为第二个参数:① i 忽略大小写 ② g 全局匹配模式
var reg = new RegExp("a", "i");
console.log(reg); /a/
console.log(typeof reg); // object

var str = "A";

/*
    正则表达式的方法
    test()
    - 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则
        如果符合则返回true,否则返回false

*/
var result = reg.test(str);
console.log("result = " + result); // true

正则语法

  • 使用字面量来创建正则表达式
  • 语法:
var 变量 = /正则表达式/匹配模式;
  • 使用字面量的方式创建更加简单;使用构造函数创建更加灵活
  • 第一种方式创建
// 第一种方式
var reg = new RegExp("a", "i");
console.log(reg.test("abc")); // true
  • 第二种方式,字面量的形式创建
// 第二种方式:字面量
reg = /a/i;
console.log(reg.test("abc"));
  • 创建一个正则表达式,检查一个字符串中是否含有a或b; 使用| 表示或者的意思
reg = /a|b|c/;
console.log(reg.test("acg")); // true 含有其中一个即可
  • 创建一个正则表达式检查一个字符串中是否有字母; []里的一个内容也是或的关系
  • [ab] == a | b ;[a-z] 任意小写字母 ; [A-Z] 任意大写字母; [A-z] 任意字母
reg = /[A-z]/;
console.log(reg.test("c")); // true
  • // 检查一个字符串中是否含有abc 或 adc 或 aec
reg = /a[bce]c/;
console.log(reg.test("aec")); // true
console.log(reg.test("aeec")); // false
  • [^ ] 除了
reg = /[^ab]/;
console.log(reg.test("abc")); // c 就是除了ab以外的东西,所以是true
  • 任意数字
reg = /[0-9]/;
console.log(reg.test(0)); // true 

字符串和正则表达式相关的方法

split()

  • 可以将一个字符串拆分为一个数组
  • 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
  • 这个方法即使不指定全局匹配,也会全部拆分
var result = str.split("c");
console.log(result.length); // 2
console.log("result = " + result); // 1a2b3,4d5e6f
  • 根据任意字母来将字符串拆分
var result = str.split(/[A-z]/);
console.log("result = " + result);

search()

  • 可以搜索字符串中是否含有指定内
  • 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1
  • 它可以接受一个正则表达式作为参数,然后会根据正则表达式检索字符串
  • 只会查找第一个,即使设置全局匹配也没用
str = "hello abc hello aec afc";
result = str.search("abc");
result2 = str.search("adc");
console.log(result); // 6
console.log(result2); // -1
  • 搜索字符串中是否含有abc或aec或afc – 正则表达式更加灵活
result = str.search(/a[bef]c/);
console.log(result); // 6

match()

  • 可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
  • 默认情况下match只会找到第一个符合要求的内容,找到以后就停止检索
  • 我们可以设置正则表达式为全局匹配模式,这样就会匹配到我们所有的内容 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
  • match() 会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
str = "1a2b3c4d5e6f7Ha";
result = str.match(/[A-z]/ig);
console.log(result);
console.log(Array.isArray(result)); // true 返回的就是一个数组
console.log(result[0]); // a

replace()

  • 可以将字符串中指定内容替换为新的内容
  • 参数:① 被替换的内容,可以接受一个正则表达式作为参数 ② 新的内容 ; 默认只会替换第一个,但是可以设置全局替换等
result = str.replace("a", "@_@"); // 1@_@2b3c4d5e6f7Ha
console.log("result = " + result);
// 使用正则表达式进行全局替换
result = str.replace(/a/ig, "@_@"); // 1@_@2b3c4d5e6f7H@_@
console.log("result = " + result);
// 使用空串替换字母就相当于把字母全部都删除了
result = str.replace(/[A-z]/g, "");
console.log(result);

正则表达式语法

  • 创建一个正则表达式检查一个字符串中是否含有三个a;下面这种写法比较不方便
var reg = /aaa/;
console.log(reg.test("aabc")); // false
console.log(reg.test("aaabc")); // true

量词

  • 通过量词可以设置一个内容出现的次数
  • 量词只对它前边的一个内容起作用
  • {n} 正好出现n次
  • {m,n} 出现m-n次
  • {m,} 出现m次以上
  • + 至少一个,相当于{1,}
  • * 0个或多个,相当于{0,}
  • ? 0个或1个,相当于{0,1}
var reg = /a{3}/;
console.log(reg.test("aaabc")); // true

reg = /ab{3}/;
console.log(reg.test("abbb"));

// 想要对连续字母起作用,需要使用到括号
reg = /(ab){3}/;
console.log(reg.test("ababab")); // true

reg = /ab{1,3}c/; // 写正则表达式时候中间不要空格隔开
console.log(reg.test("abc"));

reg = /ab{3,}c/;
console.log(reg.test("abbbbbc")); // true

reg = /ab+c/;
console.log(reg.test("abbbbc")); // true

reg = /ab*c/;
console.log(reg.test("ac")); // true

reg = /ab?c/;
console.log(reg.test("abbbc")); // false
  • 检查一个字符串是否以a开头; ^ 表示开头;$ 表示结尾
reg = /^a/; // 匹配开头的a
console.log(reg.test("bac")); // false

reg = /a$/; // 匹配结尾的a
console.log(reg.test("cca")); // true
  • 如果正则表达式中同时是用^和$ 则要求字符串必须完全符合正则表达式
reg = /^a$/;
console.log(reg.test("a")); // true
  • 以a开头或者是以a结尾,正则表达式中最好是不要经常出现空格的情况
reg = /^a|a$/;
console.log(reg.test("aaa")); // true

练习

  • 创建一个正则表达式,用来检查一个字符串是否是一个合法的手机号
/*
	手机号的规则:
	     1 8 379461493(11位置)
	     1、以1开头
	     2、第二位3-9任意数字
	     3、第三位及以后任意数字9个
	
	     ^1 [3-9] [0-9]{9}$ 
*/
var phoneStr = "18379461493";
var phoneReg = /^1[3-9][0-9]{9}$/;
console.log(phoneReg.test(phoneStr)); // true
console.log(phoneReg.test("110")); // false

正则表达式的语法2

  • 检查一个字符串中是否含有.
  • . 表示任意字符
  • 在正则表达式中使用\表示转义字符;\. 表示.
  • 注意使用构造函数时,由于它的参数是一个字符串, 而\是字符串中转义字符,如果要使用\则需要使用\\来代替
var reg = /./;
console.log(reg.test("abccde")); // true

reg = /\./
console.log(reg.test("b.")); // true

reg = new RegExp("\\.");
console.log(reg.test("ahighing")); // false
console.log(reg); // /\./

正则表达式中的一些重要符号

    \w
    - 任意字母、数字、_  [A-z 0-9 _]
    \W
    - 除了任意字母、数字、_   [^A-z 0-9 _]
    \d
    - 任意的数字[0-9]
    \D
    - 除了数字
    \s
    - 空格
    \S
    - 除了空格
    \b
    - 单词边界
    \B
    - 除了单词边界
  • 创建一个正则表达式检查一个字符串中是否含有单词child
reg = /child/;
console.log(reg.test("hello children")); // true

reg = /\bchild\b/;
console.log(reg.test("hello children")); // false
console.log(reg.test("hello child")); // true

// 接受用户的输入
// var str = prompt("请输入你的用户名:");
// console.log(str);
var str = "        he llo      ";
console.log(str);
// 去除掉字符串中前后的空格
// 去除空格就是使用""来替换空格
// str = str.replace(/\s/g, ""); // g 全局匹配模式 这种是去除全部的空格,包括字符中间的空格

// 去除开头的空格
// str = str.replace(/^\s*/, "");
// 去除结尾的空格
// str = str.replace(/\s*$/, "");

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

90-99

邮件的正则

  • 电子邮件的使用规则
/*
    电子邮件
    hello @abc.com.cn

    任意的字母数字下划线 .任意的字母数字下划线  @ 任意字母数字. 任意字母(2-5位). 任意字母(2-5位)
    \w{3,}             (\.\w+)*             @  [A-z 0-9]+ (\.  [A-z]{2,5}){1,2}
*/
var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
var email = "[email protected]";
var email1 = "haipgh11@[email protected]";
// 使用正则表达式过程中最好是不要有空格
console.log(emailReg.test(email)); // true
console.log(emailReg.test(email1)); // false

DOM简介

  • DOM - Document Object Model 文档对象模型
  • JS中通过DOM来对HTML文档进行操作,只要理解了DOM就可以随心所欲的操作WEB页面

文档

  • 文档表示的就是整个的HTML网页文档

对象

  • 对象表示将网页中的每一个部分都转换为了一个对象

模型(最难理解) - 一切都是对象

  • 使用模型来表示对象之间的关系,这样方便我们获取对象
  • 获取对象肯定离不开模型

节点(Node) - 构成HTML文档最基本的单元

  • 节点Node是构成我们网页的最基本的组成部分,网页中的每一个部分都可以称为是一个节点

  • 比如:html标签,属性,文本 虽然都是节点,但是类型也可能不一样

  • 分类:文档节点、元素节点(各种标签)、属性节点、文本节点(标签之间的文字) - 可以理解为四种对象
    节点的属性:nodeName、nodeType、nodeValue

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

<body>
    <button id="btn">我是一个按钮</button>
    <script>
        // 获取到button对象
        var btn = document.getElementById("btn");
        console.log(btn); // 这个btn对应的就是网页中的一个按钮

        // 先获取查看一下
        console.log(btn.innerHTML); // 我是一个按钮

        // 修改按钮的文字 修改的话要么调方法,要么改属性
        btn.innerHTML = "I'm Button";

    </script>
</body>

事件的简介

事件

  • 就是文档或浏览器窗口中发生的一些特定的交互瞬间
  • JavaScript与HTML之间的交互是通过事件实现的
  • 对于web应用来说,有下面这些代表性的事件:① 点击某个元素 ② 将鼠标移动至某个元素上方 ③ 按下键盘上某个键

JS实现事件方式一

  • 我们可以在事件对于的属性中设置一些JS代码;这样当事件被触发时,这些代码将会执行
  • 这种写法我们称为叫做结构和行为耦合,不方便维护,不推荐使用
<!-- <button id="btn" onclick="alert('讨厌,你点我干吗');">我是一个按钮</button> -->

JS实现事件方式二

  • 分开书写
    <button id="btn">我是kk</button>
    <script>
        /*
            事件,就是用户和浏览器之间的交互行为
                比如:点击按钮、鼠标移动、关闭窗口等
            
        */
        /*
            我们可以为按钮的对应事件绑定处理函数的形式来相应事件

        */
        // 获取按钮对象
        var btn = document.getElementById("btn");
        // console.log(btn);
        /*
            可以为按钮的对应事件绑定处理函数的形式来相应事件
            这样当事件被触发时,其对应的函数将会被调用
            属性 = 一个函数
        */
        // 绑定一个单击事件 onmousemove
        // 像这种为单击事件绑定的函数,我们称之为单击响应函数
        btn.onclick = function(){
            alert("你还点!!!");
        };
    </script>
</body>

文档的加载

浏览器加载页面的顺序

  • 是按照自上向下的顺序加载的,读取到一行就运行一行
  • 如果将script标签写到页面的上边,在代码执行时,页面还没有加载,页面没有加载DOM对象也没有加载;会导致无法获取到DOM对象

onload事件

  • onload事件会在整个页面加载完成之后才触发
  • 为window绑定一个onload事件;该事件对应的响应函数将会在页面加载完成之后执行;
  • 这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了
<script>
    /*
        浏览器加载页面的顺序
        - 是按照自上向下的顺序加载的,读取到一行就运行一行
        - 如果将script标签写到页面的上边,在代码执行时,页面还没有加载,页面没有加载DOM对象也没有加载
        - 会导致无法获取到DOM对象
        - 写在上面写在下面都可以,看你公司需求即可
    */

    /*
        onload事件会在整个页面加载完成之后才触发
        为window绑定一个onload事件
        该事件对应的响应函数将会在页面加载完成之后执行
        这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了
    */
    window.onload = function () {
        // 获取id为btn的按钮
        var btn = document.getElementById("btn");
        // 为按钮绑定一个单机响应函数 
        btn.onclick = function () {
            alert("hello");
        };
    };
</script>

<body>
    <button id="btn">点我一下</button>
    <script>
        /*
            将js代码编写到页面的下部就是为了可以在页面加载完毕以后再执行js代码
        */
        // 获取id为btn的按钮
        // var btn = document.getElementById("btn");
        // // 为按钮绑定一个单机响应函数
        // btn.onclick = function () {
        //     alert("hello");
        // };
    </script>
</body>

dom查询

  • 在函数里面,函数的参数也可以是函数
<!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">
    <link rel="stylesheet" href="css.css">
    <title>dom查询</title>

    <script>
        /*
            定义一个函数,专门用来为指定元素绑定单击响应函数
            - 不同的地方需要以实参的形式传递进去
            参数:
                1、idStr 要绑定单击响应函数的对象的id属性值
                2、fun 事件的回调函数, 当单击函数时,该函数将会被触发
        */
        function myClick(idStr, fun) {
            // 为id为btn01的按钮绑定一个单击响应函数
            var btn = document.getElementById(idStr);
            btn.onclick = fun;
        }

        /*
            标签 == 元素
            获取元素节点 - 通过document对象调用、
            1、getElementById() - 通过id属性获取一个元素节点对象 - (id具有唯一性)
            2、getElementsByTagName() - 通过标签名获取一组元素节点对象
            3、getElementsByName() - 通过name属性获取一组元素节点对象
        */
        window.onload = function () {
            // 为id为btn01的按钮绑定一个单击响应函数
            var btn01 = document.getElementById("btn01");
            btn01.onclick = function () {
                // 查找#bj节点
                var bj = document.getElementById("bj");
                // 打印bj
                // innerHTML通过这个属性可以获取到元素内部的html代码
                alert(bj.innerHTML);
            }

            // 为id为btn02的按钮绑定一个单击响应函数
            // 查找所有li节点
            var btn02 = document.getElementById("btn02");
            btn02.onclick = function () {
                // 查找所有li节点
                // getElementsByTagName() 可以根据标签名来获取一组元素节点对象
                // 这个方法会给我们返回一个类数组对象,所有查询到的元素都会封装到对象中
                // 即使查询到的函数只有一个,也会封装到数组中返回
                var lis = document.getElementsByTagName("li");
                // 打印lis
                // alert(lis.length); // 11
                // 遍历lis
                for (var i = 0; i < lis.length; i++) {
                    alert(lis[i].innerHTML);
                }
            }

            // 查找name=gender的所有节点
            // 为id为btn03的按钮绑定一个单击响应函数
            var btn03 = document.getElementById("btn03");
            btn03.onclick = function () {
                // 查找name=gender的所有节点
                var inputs = document.getElementsByName("gender");
                // 打印长度
                // alert(inputs.length);
                // 遍历inputs
                for (var i = 0; i < inputs.length; i++) {
                    /*
                        innerHTML用于获取元素内部的HTML代码
                            对于自结束标签没有意义
                    */
                    // alert(inputs[i].innerHTML); 没用
                    /*
                        如果需要读取元素节点属性,
                            直接使用元素.属性名
                            例子:元素.id 元素.name 元素.value
                            注意:class属性不能使用这种方式 - class保留字
                                 读取class属性时需要使用元素.className
                    */
                    // alert(inputs[i].value);
                    alert(inputs[i].className);
                }
            }

            // 查找#city下所有li节点
            // 为id为btn04的按钮绑定一个单击响应函数
            var btn04 = document.getElementById("btn04");
            btn04.onclick = function () {
                // 查找#city下所有li节点
                // 获取id为city的元素
                var city = document.getElementById("city");
                // 查找 #city下所有的li节点
                // document是在整个页面找到,而city是在某一个属性中找的(范围小一点)
                var lis = city.getElementsByTagName("li");
                // alert(lis.length); // 4
                // 进行一个简单的遍历
                for (var i = 0; i < lis.length; i++) {
                    alert(lis[i].innerHTML);
                }
            }

            // 返回#city的所有子节点
            // 为id为btn05的按钮绑定一个单击响应函数
            var btn05 = document.getElementById("btn05");
            btn05.onclick = function () {
                // 返回#city的所有子节点
                // 获取id为city的节点
                var city = document.getElementById("city");
                // 返回#city的所有子节点
                /*
                    childNodes属性会获取包括文本节点在内的所有节点
                    根据DOM标准,标签间的空白也会当成文本节点
                    注意:在IE8及以下的浏览器中,不会将空白文本当成子节点
                        所以该属性在ie8中会返回4个子元素,而其他浏览器是9个
                */
                var cns = city.childNodes;
                // alert(cns.length);
                // for(var i=0; i
                //     alert(cns[i]);
                // }
                /*
                    children 属性可以获取当前元素的所有子元素(推荐使用)
                */
                var cns2 = city.children;
                alert(cns2.length);
            }

            // 返回#phone的第一个子节点
            // 为id为btn06的按钮绑定一个单击响应函数
            var btn06 = document.getElementById("btn06");
            btn06.onclick = function () {
                // 获取id为phone的元素
                var phone = document.getElementById("phone");
                // 返回#phone的第一个子节点
                // firstChild可以获取到当前元素的第一个子节点(包括空白文本节点)
                var fir = phone.firstChild;
                // alert(fir); // Text
                /* 
                    firstElementChild 可以获取当前元素的第一个子元素
                    - 其不支持IE8及以下的浏览器
                    - 如果需要兼容他们尽量不要使用
                */
                fir = phone.firstElementChild;
                alert(fir.innerHTML); // IOS

            }

            // 返回#bj的父节点
            // 为id为btn07的按钮绑定一个单击响应函数.函数也是对象,是对象就可以作为参数
            myClick("btn07", function(){
                // 获取id为北京的节点
                var bj = document.getElementById("bj");
                // 返回#bj的父节点
                var pn = bj.parentNode;
                // alert(pn.innerHTML);  // 打印出了一大堆li

                /*
                    innerText
                    - 该属性可以获取到元素内部的文本内容
                    - 它和innerHTML类似,不同的是它会自动将html去除
                */
                alert(pn.innerText); // 没有标签
            });

            // 返回#android的前一个兄弟节点
            // 为id为btn08的按钮绑定一个单击响应函数
            myClick("btn08", function(){
                // 获取id为android的元素
                var and = document.getElementById("android");
                // 返回#android的前一个兄弟节点(也可能获取空白的文本,有间隔的时候)
                var ps = and.previousSibling;

                // previousElementSibling获取前一个兄弟元素,不包括兄弟元素
                // IE8及以下不兼容
                var pe = and.previousElementSibling;
                alert(ps);
            });

            // 返回#username的value属性值
            myClick("btn09", function(){
                // 获取id为username元素
                var um = document.getElementById("username");
                // 读取um的value属性值
                // 文本框的value属性值,就是文本框中填写的内容
                alert(um.value);

                // 设置#username的value属性值
                um.value = "kangkang";
            });

            // 返回#bj的文本值
            myClick("btn11", function(){
                // 获取id为bj的元素
                var bj = document.getElementById("bj");
                // alert(bj.innerHTML); // 北京

                // 获取北京中的文本节点
                var fc = bj.firstChild;
                // 文本节点的内容就是文本
                alert(fc.nodeValue);
            });
        };

    </script>
</head>

<body>
    <div id="total">
        <div class="inner">
            <p>
                你喜欢哪个城市?
            </p>

            <ul id="city">
                <li id="bj">北京</li>
                <li>上海</li>
                <li>东京</li>
                <li>首尔</li>
            </ul>

            <br>
            <br>

            <p>
                你喜欢哪款单机游戏?
            </p>

            <ul id="game">
                <li id="rl">红警</li>
                <li>实况</li>
                <li>极品飞车</li>
                <li>魔兽</li>
            </ul>

            <br />
            <br />

            <p>
                你手机的操作系统是?
            </p>

            <ul id="phone">
                <li>IOS</li>
                <li id="android">Android</li>
                <li>Windows Phone</li>
            </ul>
        </div>

        <div class="inner">
            gender:
            <input class="hello" type="radio" name="gender" value="male" />
            Male
            <input class="hello" type="radio" name="gender" value="female" />
            Female
            <br>
            <br>
            name:
            <input type="text" name="name" id="username" value="abcde" />
        </div>
    </div>
    <div id="btnList">
        <div><button id="btn01">查找#bj节点</button></div>
        <div><button id="btn02">查找所有li节点</button></div>
        <div><button id="btn03">查找name=gender的所有节点</button></div>
        <div><button id="btn04">查找#city下所有li节点</button></div>
        <div><button id="btn05">返回#city的所有子节点</button></div>
        <div><button id="btn06">返回#phone的第一个子节点</button></div>
        <div><button id="btn07">返回#bj的父节点</button></div>
        <div><button id="btn08">返回#android的前一个兄弟节点</button></div>
        <div><button id="btn09">返回#username的value属性值</button></div>
        <div><button id="btn10">设置#username的value属性值</button></div>
        <div><button id="btn11">返回#bj的文本值</button></div>
    </div>
</body>

</html>

图片切换的练习

<!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">
    <title>图片切换的练习</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #outer {
            width: 500px;
            margin: 50px auto;
            padding: 10px;
            background-color: yellow;
            /* 设置文本的一个居中效果 */
            text-align: center;
        }
    </style>
    <script>
        window.onload = function () {
            /*
                点击按钮,切换图片
            */
            // 获取两个按钮
            var prev = document.getElementById("prev");
            var next = document.getElementById("next");

            // 获取img标签
            // 下面这个方法即使只有一个元素返回的也是一个数组
            var img = document.getElementsByTagName("img")[0];

            // 创建一个数组,用来保存图片的路径
            var imgArr = ["img/1.jpg", "img/2.jpeg", "img/3.jpg", "img/4.jpg"];

            // 创建一个变量,来保存当前正在显示的图片的索引
            var index = 0;

            // 设置提示文字
            // 获取id为info的p元素
            var info = document.getElementById("info");
            // 设置提示文字
            info.innerHTML = "一共" + imgArr.length + "张图片,当前第" + (index+1) + "张";

            /*
                要切换图片就是要修改img标签的src属性
            */

            // 分别为两个按钮绑定单击响应函数
            prev.onclick = function () {
                /*
                    切换到上一张,索引自减, 这样一来索引index就变成了一个变量
                */
                index--;
                // 判断index是否小于0
                if (index < 0) {
                    index = imgArr.length-1;
                }
                img.src = imgArr[index];
                // 当点击按钮以后,重新设置信息
                info.innerHTML = "一共" + imgArr.length + "张图片,当前第" + (index+1) + "张";
            };
            next.onclick = function () {
                // alert("下一张");
                // 切换图片就是修改img的src属性
                // 要修改一个元素的属性,属性 = 属性值
                /*
                    切换到下一张index自增
                */
                index++;
                if (index > imgArr.length-1) {
                    index = 0;
                }
                img.src = imgArr[index];
                info.innerHTML = "一共" + imgArr.length + "张图片,当前第" + (index+1) + "张";
            };
        };
    </script>
</head>

<body>
    <div id="outer">
        <p id="info"></p>
        <img src="./img/1.jpg" alt="冰棍">
        <button id="prev">上一张</button>
        <button id="next">下一张</button>
    </div>
</body>

</html>

DOM查询

获取元素节点的子节点:通过具体的元素节点调用
1、getElementsByTagName() - 方法,返回当前节点的指定标签名后代节点
2、childNodes - 属性,表示当前节点的所有子节点
3、firstChild - 属性,表示当前节点的第一个子节点
4、lastChild - 属性,表示当前节点的最后一个子节点

  • 剩下的查询操作练习见前的dom查询

DOM查询2

获取父节点和兄弟节点:通过具体的节点调用
1、parentNode - 属性,表示当前节点的父节点
2、previousSibling - 属性,表示当前节点的前一个兄弟节点
3、nextSibling - 属性,表示当前节点的后一个兄弟节点

  • 剩下的查询操作练习见前的dom查询

全选练习(98-100)

  • 具体见代码
<!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">
    <title>全选练习三</title>
    <script>
        window.onload = function () {
            // 这种全局性的东西,我们后面想要设置可以放在全局的位置即可
            // 获取四个多选框items
            var items = document.getElementsByName("items");
            // 为checkedAllBox绑定一个单击响应函数
            // 获取全选以及全不选的多选框
            var checkedAllBox = document.getElementById("checkedAllBox");
            /*
                全选按钮
                - 点击按钮以后,四个多选框全都被选中
            */
            // 1、#checkedAllBtn
            // 为id为checkedAllBtn的按钮绑定一个单击响应函数
            var checkedAllBtn = document.getElementById("checkedAllBtn");
            checkedAllBtn.onclick = function () {
                // alert("全都选中了");
                // alert(items.length); // 4
                // 遍历items
                for (var i = 0; i < items.length; i++) {
                    // 设置四个多选框变成选中状态 - 无非是调个方法或者是弄个属性
                    // 通过多选框的checked属性可以来获取或设置多选框的选中状态
                    // alert(items[i].checked); // 判断是否被选中,选中返回true,否则返回false
                    items[i].checked = true;
                }
                // 将全选|全不选设置为选中
                checkedAllBox.checked = true;
            };
            /*
                全不选
                - 点击按钮以后,四个多选框都变成没选中状态

            */
            // 2. #checkedNoBtn
            // 为id为checkedNoBtn的按钮绑定一个单击响应函数
            var checkedNoBtn = document.getElementById("checkedNoBtn");
            checkedNoBtn.onclick = function () {
                for (var i = 0; i < items.length; i++) {
                    // 将四个多选框设置为没选中的状态
                    items[i].checked = false;
                }
                // 将全选|全不选设置为选中
                checkedAllBox.checked = false;
            }

            /*
                反选按钮
                - 点击按钮以后,选中的变成没选中,没选中的变成选中
            */
            // 3. #checkedRevBtn
            var checkedRevBtn = document.getElementById("checkedRevBtn");
            checkedRevBtn.onclick = function () {
                for (var i = 0; i < items.length; i++) {
                    // 判断多选框的一个状态,前面本身就是一个bool值
                    // if(items[i].checked){
                    //     // 证明多选框已被选中,则设置为没选中状态
                    //     items[i].checked = false;
                    // }else{
                    //     items[i].checked = true;
                    // }
                    items[i].checked = !items[i].checked;
                }
                // 在反选时也需要判断四个多选框是否选中
                // 设置checkedAllBox为选中状态
                checkedAllBox.checked = true;
                // alert("hello");
                // 判断四个多选框是否全选
                for (var j = 0; j < items.length; j++) {
                    // 判断四个多选框是否全选
                    // 正面判断不好判断,可以反正来进行判断
                    // 只要有一个没选中,则就不是全选
                    if (!items[j].checked) {
                        // 一旦进入判断,则证明不是全选状态
                        // 将checkedAllBox设置为没选中状态
                        checkedAllBox.checked = false;
                        // 一单进入判断,则已经得出结果,不用在继续执行循环
                        break;
                    }
                }

            }

            /*
                提交按钮
                - 点击按钮以后,将所有选中的多选框的value属性值弹出
            */
            // 4、#sendBtn
            // 为sendBtn绑定单击响应函数
            var sendBtn = document.getElementById("sendBtn");
            sendBtn.onclick = function () {
                // 遍历items
                for (var i = 0; i < items.length; i++) {
                    // 判断多选框是否选中
                    if (items[i].checked) {
                        alert(items[i].value);
                    }
                }
            }
            // 5、#checkedAllBox
            /*
                全选、全不选 多选框
                - 当它选中时,其余的也选中,当它取消时其余的也取消

                在事件响应函数中,响应函数是给谁绑定的this就是谁
                
            */
            // 为checkedAllBox绑定一个单击响应函数
            var checkedAllBox = document.getElementById("checkedAllBox");
            checkedAllBox.onclick = function () {
                // alert(this == checkedAllBox); // true
                // 在实际开发中最好一步一步进行相应测试
                // alert("全都选中了");
                // 设置多选框的选中状态
                for (var i = 0; i < items.length; i++) {
                    // 观察自己每次对应的对象是什么
                    items[i].checked = checkedAllBox.checked;
                }
            }

            // 6、items 
            /*
                如果四个多选框全都选中,则checkedAllBox也应该选中
                如果四个多选框没都选中,则checkedAllBox也不应该选中
                
            */
            // 为四个多选框分别绑定点击响应函数
            for (var i = 0; i < items.length; i++) {
                items[i].onclick = function () {
                    // 设置checkedAllBox为选中状态
                    checkedAllBox.checked = true;
                    // alert("hello");
                    // 判断四个多选框是否全选
                    for (var j = 0; j < items.length; j++) {
                        // 判断四个多选框是否全选
                        // 正面判断不好判断,可以反正来进行判断
                        // 只要有一个没选中,则就不是全选
                        if (!items[j].checked) {
                            // 一旦进入判断,则证明不是全选状态
                            // 将checkedAllBox设置为没选中状态
                            checkedAllBox.checked = false;
                            // 一单进入判断,则已经得出结果,不用在继续执行循环
                            break;
                        }
                    }
                };
            }
        };
    </script>

</head>

<body>
    <form method="post" action="">
        你爱好的运动是?<input type="checkbox" id="checkedAllBox" />全选/全不选

        <br />
        <input type="checkbox" name="items" value="足球" />足球
        <input type="checkbox" name="items" value="篮球" />篮球
        <input type="checkbox" name="items" value="羽毛球" />羽毛球
        <input type="checkbox" name="items" value="乒乓球" />乒乓球
        <br />
        <input type="button" id="checkedAllBtn" value="全 选" />
        <input type="button" id="checkedNoBtn" value="全不选" />
        <input type="button" id="checkedRevBtn" value="反 选" />
        <input type="button" id="sendBtn" value="提 交" />
    </form>
</body>

</html>

100-109

dom查询的剩余方法

获取body标签

  • 因为本身返回的是一个类数组,而其中只有一个元素,所以使用一个索引获取

方式一

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

方式二

  • 在document中有一个属性body,它保存的是body的引用
var body = document.body;
  • document.documentElement保存的是html根标签
var html = document.documentElement;
  • document.all代表的是页面中所有的元素
var all = document.all;
// console.log(body);
// console.log(html);
// console.log(all.length); // 有多少个元素值就是多少
// for(var i = 0; i < all.length; i++){
//     console.log(all[i]); // 页面中的所有元素,对应的是相应的标签
// }
// 作用和上方是一样的
all = document.getElementsByTagName("*");
console.log(all.length); // 12

getElementsByClassName()

  • 根据元素的class属性值,查询一组元素节点对象
  • 但是该方法不支持IE8及以下浏览器
// var box1 = document.getElementsByClassName("box1");
// console.log(box1.length); // 3
// 获取页面中的div
// var divs = document.getElementsByTagName("div");
// 获取class为box1中的所有的div
// .box1 div

document.querySelector()

  • 需要一个选择器的字符串作为参数,可以根据一个CSS选择器来查询一个元素节点对象
  • 虽然IE8中没有getElementsByTagName() 但是可以使用querySelector
  • 使用该方法总是返回唯一的一个元素,如果满足条件的元素有多个,那么只会返回第一个,所以有时候局限还是
var div = document.querySelector(".box1 div");
var box1 = document.querySelector(".box1"); // 也可以使用id进行查询
// console.log(divs.length);
// console.log(div.innerHTML); // 我是box1中的div
// console.log(box1); // 把class为box1的div给打印了出来
// 前面的方法都有一定的局限性

querySelectorAll()

  • 该方法和querySelector() 方法类似,不同的是它会将符合条件的元素封装到一个数组中返回
  • 即使符合条件的元素只有一个,它也会返回数组!!!
  • 所以总结来说就是需要使用第一个就用上面的,想要全部获取使用就使用下面的即可
var box1 = document.querySelectorAll(".box1");
console.log(box1.length); // 2

dom增删改

document.createElement()

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

document.createTextNode()

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

appendChild()

  • 向一个父节点中添加一个新的子节点
  • 用法: 父节点.appendChild(子节点)
li.appendChild(gzText);
// 获取id为city的节点
var city = document.getElementById("city");
// 将广州添加到city下
city.appendChild(li);

insertBefore()

  • 在指定的子节点前面插入新的子节点 - 父节点调用
  • 用法:父节点.insertBefore(新节点, 旧节点);
// 获取city 
var city = document.getElementById("city");
city.insertBefore(li, bj);

replaceChild()

  • 可以使用指定的子节点替换已有的子节点
  • 语法: 父节点.replaceChild(新节点, 旧节点);
city.replaceChild(li, bj);

removeChild()

  • 可以删除一个子节点
  • 语法:父节点.removeChild(子节点);
  • 子节点.parentNode.removeChild(子节点); - 更常用

使用innerHtml也可以完成DOM的增删改的相关操作

  • 一般我们会两种方式结合使用,具体见编辑器102
// 7、创建一个"广州"节点,添加到#city下
myClick("btn07", function () {
    // 向city中添加广州
    var city = document.getElementById("city");

    /*
        使用innerHtml也可以完成DOM的增删改的相关操作
        一般我们会两种方式结合使用
    */
    // city.innerHTML += "
  • 广州
  • " - 使用这种创建时每次都会全部重新创建,
    // 创建一个li var li = document.createElement("li"); // 直接向li中设置文本 li.innerHTML = "广州"; // 将li添加到city city.appendChild(li); });

    添加删除记录1

    目的:点击超链接,删除一个员工的信息
    使用到的内容
    confirm()

    • 用于弹出一个带有确认和取消按钮的提示框
    • 需要一个字符串作为参数,该字符串将会作为提示文字显示出来
    • 如果用户返回确认返回true,点击取消返回false

    点击超链接以后希望页面不跳转

    • 单击超链接以后,超链接会跳转页面,这个是超链接的默认行为
      方式一:但是此时我们不希望出现默认行为,可以通过在响应函数的最后return false来取消默认行为
      方式二:在a标签里面进行相应设置
    <a href="javascript:;">Delete</a>
    
    <script>
        window.onload = function () {
            /*
                点击超链接,删除一个员工的信息
            */
            // 获取所有的超链接
            var allA = document.getElementsByTagName("a");
            // 为每一个超链接都绑定一个单击数响应函
            for (var i = 0; i < allA.length; i++) {
                allA[i].onclick = function () {
                    // alert("hello");
    
                    // 点击超链接以后删除超链接所在的行
                    // alert(this);
                    // 这里我们点击哪个超链接this就是谁
                    // 获取当前的tr
                    var tr = this.parentNode.parentNode;
    
                    // 为了更加的友好,可以再删除的时候,获取员工的名字,更好的交互
                    // 方式一
                    // var name = tr.getElementsByTagName("td")[0].innerHTML;
                    // 方式二
                    var name = tr.children[0].innerHTML;
    
                    // 为了更加友好,删除之前弹出一个提示框
                    /*
                        confirm()
                        - 用于弹出一个带有确认和取消按钮的提示框
                        - 需要一个字符串作为参数,该字符串将会作为提示文字显示出来
                        如果用户返回确认返回true,点击取消返回false
                    */
                    var flag = confirm("确认删除" + name + "吗?");
                    // 如果用户点击确认
                    if (flag) {
                        // 删除tr
                        tr.parentNode.removeChild(tr);
                    }
                    /*
                        单击超链接以后,超链接会跳转页面,这个是超链接的默认行为
                            但是此时我们不希望出现默认行为,可以通过在响应函数的最后return false来取消默认行为
                    */
                    return false;
                }
            }
        };
    </script>
    

    添加删除记录2

    目的:添加员工的功能

    • 点击按钮以后,将员工信息添加到表格中

    方式一:比较麻烦

    • 对于每一个标签都进行相应创建
    <script>
        window.onload = function () {
            /*
                添加员工的功能
                - 点击按钮以后,将员工信息添加到表格中,
                - 
            */
            // 为提交按钮绑定一个单击响应函数, 
            var addEmpButton = document.getElementById("addEmpButton");
            addEmpButton.onclick = function () {
                // alert("hello");
                // 获取用户添加的员工信息
                // 获取员工的名字
                var name = document.getElementById("empName").value;
                // alert(name);
                // 获取员工的噩email和salary
                var email = document.getElementById("email").value;
                var salary = document.getElementById("salary").value;
                // alert(name + "," + email + "," + salary);
                /*
                            
                                Tom
                                [email protected]
                                5000
                                Delete
                            
                        需要做的就是将获取到的信息保存到tr中
                */
                // 创建一个tr
                var tr = document.createElement("tr");
                // 创建四个td
                var nameTd = document.createElement("td");
                var emailTd = document.createElement("td");
                var salaryTd = document.createElement("td");
                var aTd = document.createElement("td");
    
                // 创建一个a元素
                var a = document.createElement("a");
    
                // 创建一个文本节点
                var nameText = document.createTextNode(name);
                var emailText = document.createTextNode(email);
                var salaryText = document.createTextNode(salary);
                var delText = document.createTextNode("Delete");
    
                // 将文本添加到td中
                nameTd.append(nameText);
                emailTd.append(emailText);
                salaryTd.append(salaryText);
    
                // 向a中添加文本
                a.appendChild(delText);
                // 将a添加到td中
                aTd.appendChild(a);
    
                // 将td添加到tr中
                tr.appendChild(nameTd);
                tr.appendChild(emailTd);
                tr.appendChild(salaryTd);
                tr.appendChild(aTd);
    
                // 向a中添加href属性
                a.href = "javaScript:;";
    
                // 为新添加的a再绑定一次单击响应函数
                a.onclick = function () {
                    // 点击超链接以后删除超链接所在的行
                    // alert(this);
                    // 这里我们点击哪个超链接this就是谁
                    // 获取当前的tr
                    var tr = this.parentNode.parentNode;
    
                    // 为了更加的友好,可以再删除的时候,获取员工的名字,更好的交互
                    // 方式一
                    // var name = tr.getElementsByTagName("td")[0].innerHTML;
                    // 方式二
                    var name = tr.children[0].innerHTML;
    
                    // 为了更加友好,删除之前弹出一个提示框
                    /*
                        confirm()
                        - 用于弹出一个带有确认和取消按钮的提示框
                        - 需要一个字符串作为参数,该字符串将会作为提示文字显示出来
                        如果用户返回确认返回true,点击取消返回false
                    */
                    var flag = confirm("确认删除" + name + "吗?");
                    // 如果用户点击确认
                    if (flag) {
                        // 删除tr
                        tr.parentNode.removeChild(tr);
                    }
                    /*
                        单击超链接以后,超链接会跳转页面,这个是超链接的默认行为
                            但是此时我们不希望出现默认行为,可以通过在响应函数的最后return false来取消默认行为
                    */
                    return false;
                }
    
                // 获取table
                var employeeTable = document.getElementById("employeeTable");
    
                // 获取employeeTable中的tbody
                var tbody = employeeTable.getElementsByTagName("tbody")[0];
                // // 将tr添加到table中
                // employeeTable.appendChild(tr);
                // 将tr添加到tbody中
                tbody.appendChild(tr);
            }
        };
    </script>
    

    上述代码的一个小改进

    • 在进行点击超链接,删除一个员工的信息和添加员工信息的功能时候都用到了对超链接a标签进行操作,
    • 所以将a标签的触发操作提取到全局作用域
    <script>
        /*
           删除tr的单击响应函数
        */
        function delA() {
            // 点击超链接以后删除超链接所在的行
            // alert(this);
            // 这里我们点击哪个超链接this就是谁
            // 获取当前的tr
            var tr = this.parentNode.parentNode;
    
            // 为了更加的友好,可以再删除的时候,获取员工的名字,更好的交互
            // 方式一
            // var name = tr.getElementsByTagName("td")[0].innerHTML;
            // 方式二
            var name = tr.children[0].innerHTML;
    
            // 为了更加友好,删除之前弹出一个提示框
            /*
                confirm()
                - 用于弹出一个带有确认和取消按钮的提示框
                - 需要一个字符串作为参数,该字符串将会作为提示文字显示出来
                如果用户返回确认返回true,点击取消返回false
            */
            var flag = confirm("确认删除" + name + "吗?");
            // 如果用户点击确认
            if (flag) {
                // 删除tr
                tr.parentNode.removeChild(tr);
            }
            /*
                单击超链接以后,超链接会跳转页面,这个是超链接的默认行为
                    但是此时我们不希望出现默认行为,可以通过在响应函数的最后return false来取消默认行为
            */
            return false;
        };
        window.onload = function () {
            /*
                点击超链接,删除一个员工的信息
            */
            // 获取所有的超链接
            var allA = document.getElementsByTagName("a");
            // 为每一个超链接都绑定一个单击响应函数
            for (var i = 0; i < allA.length; i++) {
                allA[i].onclick = delA;
            }
    
            /*
                添加员工的功能
                - 点击按钮以后,将员工信息添加到表格中,
                - 
            */
            // 为提交按钮绑定一个单击响应函数, 
            var addEmpButton = document.getElementById("addEmpButton");
            addEmpButton.onclick = function () {
                // alert("hello");
                // 获取用户添加的员工信息
                // 获取员工的名字
                var name = document.getElementById("empName").value;
                // alert(name);
                // 获取员工的噩email和salary
                var email = document.getElementById("email").value;
                var salary = document.getElementById("salary").value;
                // alert(name + "," + email + "," + salary);
                /*
                            
                                Tom
                                [email protected]
                                5000
                                Delete
                            
                        需要做的就是将获取到的信息保存到tr中
                */
                // 创建一个tr
                var tr = document.createElement("tr");
                // 创建四个td
                var nameTd = document.createElement("td");
                var emailTd = document.createElement("td");
                var salaryTd = document.createElement("td");
                var aTd = document.createElement("td");
    
                // 创建一个a元素
                var a = document.createElement("a");
    
                // 创建一个文本节点
                var nameText = document.createTextNode(name);
                var emailText = document.createTextNode(email);
                var salaryText = document.createTextNode(salary);
                var delText = document.createTextNode("Delete");
    
                // 将文本添加到td中
                nameTd.append(nameText);
                emailTd.append(emailText);
                salaryTd.append(salaryText);
    
                // 向a中添加文本
                a.appendChild(delText);
                // 将a添加到td中
                aTd.appendChild(a);
    
                // 将td添加到tr中
                tr.appendChild(nameTd);
                tr.appendChild(emailTd);
                tr.appendChild(salaryTd);
                tr.appendChild(aTd);
    
                // 向a中添加href属性
                a.href = "javaScript:;";
    
                // 为新添加的a再绑定一次单击响应函数
                a.onclick = delA;
    
                // 获取table
                var employeeTable = document.getElementById("employeeTable");
    
                // 获取employeeTable中的tbody
                var tbody = employeeTable.getElementsByTagName("tbody")[0];
                // // 将tr添加到table中
                // employeeTable.appendChild(tr);
                // 将tr添加到tbody中
                tbody.appendChild(tr);
    
            }
        };
    </script>
    

    添加删除记录-修改(简单改进)

    • 不再一一进行创建元素, 而是使用innerHTML进行拼串插入
    /*
        添加员工的功能
        - 点击按钮以后,将员工信息添加到表格中,
        - 
    */
    // 为提交按钮绑定一个单击响应函数, 
    var addEmpButton = document.getElementById("addEmpButton");
    addEmpButton.onclick = function () {
        // alert("hello");
        // 获取用户添加的员工信息
        // 获取员工的名字
        var name = document.getElementById("empName").value;
        // alert(name);
        // 获取员工的噩email和salary
        var email = document.getElementById("email").value;
        var salary = document.getElementById("salary").value;
        // alert(name + "," + email + "," + salary);
        /*
                    
                        Tom
                        [email protected]
                        5000
                        Delete
                    
                需要做的就是将获取到的信息保存到tr中
        */
        // 创建一个tr
        var tr = document.createElement("tr");
        // 方式二进行创建
        tr.innerHTML = "" + name + "" +
                        "" + email + "" +
                        "" + salary + "" +
                        "Delete";
                        // 上面在进行拼串的时候,a标签是放在td整个标签里面的,不需要进行拼串操作
    
        // 获取刚刚添加的a元素,并为其绑定单击响应函数
        var a = tr.getElementsByTagName("a")[0];
        a.onclick = delA;
        // 获取table
        var employeeTable = document.getElementById("employeeTable");
    
        // 获取employeeTable中的tbody
        var tbody = employeeTable.getElementsByTagName("tbody")[0];
        // // 将tr添加到table中
        // employeeTable.appendChild(tr);
        // 将tr添加到tbody中
        tbody.appendChild(tr);
    
        // 拼串 "+ +" 这种拼串操作还是很关键
    }
    

    a的索引问题

    • for循环会在页面加载完成之后立即执行
    • 而响应函数会在超链接被点击时才执行;当响应函数执行,for循环早已执行完毕
    • 所以在这里this 不等于 allA[i]
    <script>
        window.onload = function () {
            /*
                点击超链接,删除一个员工的信息
            */
            // 获取所有的超链接
            var allA = document.getElementsByTagName("a");
            // 为每一个超链接都绑定一个单击响应函数
            for (var i = 0; i < allA.length; i++) {
                alert("for循环正在执行" + i);
                allA[i].onclick = function () {
                    alert("响应函数正在执行" + i);
                    // alert(allA[i] == this);
                }
            }
        };
    </script>
    

    操作内联样式

    • 修改box1的宽度,通过js修改元素的样式
    • 语法:元素.style.样式名 = 样式值;

    注意

    • 如果css的样式名中含有 - , 这种名称在我们的js中是不合法的,比如background-color
    • 需要将这种样式名修改为驼峰命名法,去掉 - , 将 - 后的字母大写 例如:borderTopWidth - 使用驼峰命名法进行即可
    • 我们通过style属性设置的样式都是内联样式;而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示
    • 但是如果在我们的样式中 !important,则此时样式会有最高的优先集,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效; 所以尽量不要为样式添加 !important
    • 通过style属性设置和读取的都是内联样式
    box1.style.width = "300px";
    box1.style.backgroundColor = "yellow";
    

    读取元素样式

    • 语法:元素.style.样式名
    • 通过style属性设置和读取的都是内联样式;无法读取样式表中的样式
    alert(box1.style.width);
    

    获取元素的样式

    获取元素的当前显示的样式

    • 语法:元素.currentStyle.样式名
    • 它可以用来读取当前元素正在显示的样式
    • 如果当前元素没有设置该样式,则获取它的默认值
    • 但是: currentStyle只有ie浏览器支持
    alert(box1.currentStyle.width); // chrome浏览器目前是不兼容的
    

    在其他浏览器中可以使用

    • getComputedStyle() 这个方法来获取元素当前的样式
    • 这个方法是window的方法,可以直接使用
    • 需要两个参数:① 要获取样式的元素 ② 可以传递一个伪元素,一般都传null
    • 该方法会返回一个对象,对象中封装了当前元素对应的样式;可以通过对象.样式名来读取样式
    • 如果获取的样式没有设置,则会获取到真实的值,而不是默认值;比如:没有设置width,它不会获取到auto,而是一个长度 0px
    • 但是:该方法它不支持IE8及以下的浏览器
    • 通过currentStyle和getComputedStyle() 读取到的样式都是只读的
    • 不能进行修改,如果要修改必须通过style属性

    getStyle方法

    • 因为两种方式用于获取样式都有一定的局限性,所以在判定某种方式浏览器是否能使用时才行
    /*
        定义一个函数,用来获取指定元素的当前的样式
        参数:
            obj 要获取样式的元素
            name 要获取的样式名
    
    */
    function getStyle(obj, name) {
        // alert(getComputedStyle);
        // 推荐使用这种,结构更清晰
        if (window.getComputedStyle) {
            // 正常浏览器具有getComputedStyle() 方法
            return getComputedStyle(obj, null)[name];
        } else {
            // IE8的方式,没有getComputedStyle方法
            return obj.currentStyle[name];
        }
        // 正常浏览器的方式
        // return getComputedStyle(obj, null)[name];
        // IE8的方式
        // return obj.currentStyle[name];
    
        // 三目运算符
        // return window.getComputedStyle? getComputedStyle(obj, null)[name]:obj.currentStyle[name];
    }
    

    其他样式的相关属性

    #box1 {
    	    width: 100px;
    	    height: 100px;
    	    background-color: red;
    	    padding: 10px;
    	    border: 10px solid yellow;
    }
    

    clientWidthclientHeight

    • 这两个属性可以获取元素的可见高度和可见宽度
    • 这些属性都是不带px,返回都是一个数值,可以直接进行计算
    • 会获取元素宽度和高度,包括内容区和内边距
    • 这些属性都是只读的,不能进行修改
    // alert(box1.clientWidth); // 120
    // alert(box1.clientHeight); // 120
    // box1.clientHeight = 300; // 不行
    

    offsetWidthoffsetHeight

    • 获取元素整个的宽度和高度,包括内容区和内边距以及边框
    alert(box1.offsetHeight); // 140
    

    offsetParent

    • 可以用来获取当前元素的定位父元素
    • 会获取到距离当前元素最近的开启了定位的祖先元素
    • 如果所有的祖先元素没有开启定位,则返回body
    // var op = box1.offsetParent;
    // alert(op.id); // box2
    
    // 背景
    <div id="box3">
        <div id="box2" style="position: relative;">
            <div id="box1"></div>
        </div>
    </div>
    

    offsetLeft

    • 当前元素相对于其定位父元素的水平偏移量
    alert(box1.offsetLeft); // 100
    

    offsetTop

    • 当前元素相对于其定位父元素的垂直偏移量

    scrollHeightscrollWidth

    • 可以获取元素整个滚动区域的高度和宽度
    alert(box4.scrollHeight); // 600
    

    scrollLeft

    • 可以获取水平滚动条滚动的距离

    scrollTop

    • 可以获取垂直滚动条滚动的距离
    alert(box4.scrollTop); // 38 看你自己挪了多少
    

    当满足scrollHeight - scrollTop == clientHeight说明垂直滚动条滚动到底了

    alert(box4.clientHeight); // 300
    alert(box4.scrollHeight - box4.scrollTop); // 300
    

    当满足scrollWidth - scrollLeft == clientWidth说明水平滚动条滚动到底

    利用上述等式可以做一个在网页中经常用到的操作,滑动鼠标滚动到最底下才能进行打钩注册

    <!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">
        <title>练习</title>
        <style>
            #info{
                width: 300px;
                height: 500px;
                background-color: #bfa;
                overflow: auto;
            }
        </style>
        <script>
            window.onload = function(){
                /*
                    当垂直滚动条滚动到底时使表单项可用
                    onscroll
                    - 该事件会在元素滚动条滚动时触发
    
                */
                // 获取id为info的p元素
                var info = document.getElementById("info");
                // 获取两个表单项
                var inputs = document.getElementsByTagName("input");
                // 为info绑定一个滚动条滚动的事件
                info.onscroll = function(){
                    // 检查垂直滚动条是否滚动到底
                    if(info.scrollHeight - info.scrollTop == info.clientHeight){
                        // 滚动条滚动到底,使表单项可用
                        /*
                            disabled属性可以设置一个元素是否禁用
                            如果设置为true, 则元素禁用
                            如果设置为false,则元素可用
                        */
                        inputs[0].disabled = false;
                        inputs[1].disabled = false;
                    }
                }
            };
        </script>
    </head>
    <body>
        <h3>欢迎亲爱的用户注册</h3>
        <p id="info">
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议
            亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议亲爱的用户,请仔细阅读协议
        </p>
        <!-- 
            如果为表单项添加disabled="disabled",则表单项变成不可用状态
         -->
        <input type="checkbox" disabled="disabled"/>我已仔细阅读协议,一定遵守
        <input type="submit" value="注册" disabled="disabled"/>
    </body>
    </html>
    

    110-119

    其他样式的相关属性

    样式背景

    <style>
        #box1 {
            width: 100px;
            height: 100px;
            background-color: red;
            padding: 10px;
            border: 10px solid yellow;
        }
        #box2{
            padding: 100px;
            background-color: aqua;
        }
        #box4{
            width: 200px;
            height: 300px;
            background-color: #bfa;
            overflow: auto;
        }
        #box5{
            width: 150px;
            height: 600px;
            background-color: yellow;
        }
    </style>
    

    clientWidthclientHeight

    • 这两个属性可以获取元素的可见高度和可见宽度
    • 这些属性都是不带px,返回都是一个数值,可以直接进行计算
    • 会获取元素宽度和高度,包括内容区和内边距
    • 这些属性都是只读的,不能进行修改
    alert(box1.clientWidth); // 120
    alert(box1.clientHeight); // 120
    box1.clientHeight = 300; // 不行
    

    offsetWidthoffsetHeight

    • 获取元素整个的宽度和高度,包括内容区和内边距以及边框
    alert(box1.offsetHeight); // 140
    

    页面主体代码

    <body id="body">
        <div id="box4">
            <div id="box5"></div>
        </div>
    
        <button id="btn01">点我一下</button>
        <br /><br />
        <div id="box3">
            <div id="box2" style="position: relative;">
                <div id="box1"></div>
            </div>
        </div>
    </body>
    

    offsetParent

    • 可以用来获取当前元素的定位父元素
    • 会获取到距离当前元素最近的开启了定位的祖先元素
    • 如果所有的祖先元素没有开启定位,则返回body
    var op = box1.offsetParent;
    alert(op.id); // box2
    

    offsetLeft

    • 当前元素相对于其定位父元素的水平偏移量

    offsetTop

    • 当前元素相对于其定位父元素的垂直偏移量
    alert(box1.offsetLeft); // 100
    

    scrollHeightscrollWidth

    • 可以获取元素整个滚动区域的高度
    alert(box4.scrollHeight); // 600
    

    scrollLeft

    • 可以获取水平滚动条滚动的距离

    scrollTop

    • 可以获取垂直滚动条滚动的距离

    两个等式如下:

    alert(box4.scrollTop); // 38 看你自己挪了多少
    
    // 当满足scrollHeight - scrollTop == clientHeight
    // 说明垂直滚动条滚动到底了
    alert(box4.clientHeight); // 300
    alert(box4.scrollHeight - box4.scrollTop); // 300
    
    // 当满足scrollWidth - scrollLeft == clientWidth
    // 说明水平滚动条滚动到底
    // 利用上述知识点做一个小的练习
    

    JS事件对象

    onmousemove

    • 该事件将会在鼠标在元素移动时被触发

    事件对象

    • 当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数
    • 在事件对象中封装了当前事件相关的一切信息,比如鼠标的坐标,键盘哪个按键被按下,鼠标滚轮滚动的方向
    • 事件的信息或者是相关调整用的都是event
    • 在IE8中,响应函数被触发时,浏览器不会传递事件对象;在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的

    目的
    当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标

    • clientX 可以获取鼠标指针的水平坐标; clientY 可以获取鼠标指针的垂直坐标
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>事件对象</title>
        <style type="text/css">
            #areaDiv {
                border: 1px solid black;
                width: 300px;
                height: 50px;
                margin-bottom: 10px;
            }
    
            #showMsg {
                border: 1px solid black;
                width: 300px;
                height: 20px;
            }
        </style>
        <script type="text/javascript">
            window.onload = function(){
                /*
                    当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标
                */
                // 获取两个div
                var areaDiv = document.getElementById("areaDiv");
                var showMsg = document.getElementById("showMsg");
                areaDiv.onmousemove = function(event){
                    // 第一种写法
                    // if(!event){
                    //     event = window.event;
                    // }
                    // 第二种写法;解决事件对象的兼容性问题
                    event = event || window.event;
                    var x = event.clientX;
                    var y = event.clientY;
                    // alert("x = " + x + "," + "y = " + y);
    
                    // 在showMsg中显示鼠标的坐标
                    showMsg.innerHTML = "x = " + x + "," + "y = " + y;
                };
            };
        </script>
    </head>
    
    <body>
        <div id="areaDiv"></div>
        <div id="showMsg"></div>
    </body>
    </html>
    

    div跟随鼠标移动

    获取到鼠标的坐标
    clientX和clientY

    • 用于获取鼠标在当前的可见窗口的坐标
    • div的偏移量,是相对于整个页面的

    pageX和pageY

    • 可以获取鼠标相对于当前页面的坐标
    • 但是这两个属性在IE8中不支持,所以如果需要兼容IE8,则不需要使用,

    要处理滚动条出现时,鼠标的点不变
    代码实现

    <script>
        window.onload = function () {
            /*
                使div可以跟随鼠标移动
            */
            // 获取box1
            var box1 = document.getElementById("box1");
            // 绑定鼠标移动事件,想要的是整个对象,所以用到的对象是document
            document.onmousemove = function (event) {
                // 解决兼容问题
                event = event || window.event;
                /*
                    chrome认为浏览器滚动条是body的,可以通过body.scrollTop来获取
                    火狐等浏览器认为浏览器的滚动条是html的
                */
                // 获取滚动条滚动的距离
                var st = document.body.scrollTop || document.documentElement.scrollTop;
                var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
                // var st = document.documentElement.scrollTop;
                // console.log(st);
                // 获取到鼠标的坐标
                /*
                    clientX和clientY
                    - 用于获取鼠标在当前的可见窗口的坐标
                    div的偏移量,是相对于整个页面的
    
                    pageX和pageY可以获取鼠标相对于当前页面的坐标
                    但是这两个属性在IE8中不支持,所以如果需要兼容IE8,则不需要使用,
                */
                var left = event.clientX;
                var top = event.clientY;
                // var left = event.pageX;
                // var top = event.pageY;
    
                // 设置div的偏移量 - 只对定位的时候起作用
                box1.style.left = left + sl + "px";
                box1.style.top = top + st + "px";
            };
            // 将box2处的div设置为非冒泡进行查看观察
            var box2 = document.getElementById("box2");
            box2.onmousemove = function (event) {
                event = event || window.event;
                event.cancelBubble = true;
            };
        };
    </script>
    

    事件的冒泡

    事件的冒泡(Bubble)

    • 所谓的冒泡指的是事件的向上传导, 当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
    • 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
    • 取消冒泡,则后代元素被触发时候,祖先元素就不会受到影响
    <!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">
        <title>事件的冒泡</title>
        <style>
            #box1 {
                width: 200px;
                height: 200px;
                background-color: yellowgreen;
    
            }
    
            #s1 {
                background-color: yellow;
            }
        </style>
        <script>
            window.onload = function () {
                /*
                    事件的冒泡(Bubble)
                    - 所谓的冒泡指的是事件的向上传导,
                        当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
                    - 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
                */
                // 为了s1绑定一个单击响应函数
                var s1 = document.getElementById("s1");
                s1.onclick = function (event) {
                    event = event || window.event;
                    alert("我是span的单击响应函数");
    
                    // 取消冒泡
                    // 可以将事件对象的cancelBubble设置为true,即可取消冒泡
                    event.cancelBubble = true;
    
                }; // 每一个函数结束以后最好也加上分号
    
                // 为了box1绑定一个单击响应函数
                var box1 = document.getElementById("box1");
                box1.onclick = function (event) {
                    event = event || window.event;
                    alert("我是div的单击响应函数");
                    event.cancelBubble = true;
                };
                // 为body绑定一个单击响应函数
                document.body.onclick = function () {
                    alert("我是body的单击响应函数");
                };
            };
        </script>
    </head>
    
    <body>
        <!-- 在书写的时候直接写上 div#box1 是可以直接当快捷键用 -->
        <div id="box1">
            我是box1
            <span id="s1">我是一个span</span>
        </div>
    </body>
    
    </html>
    

    事件的委派

    比如:

    • 在为每一个超链接都绑定一个单击响应函数, 这里为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦
    • 而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定
    • 我们希望, 只绑定一次事件,即可应用到多个元素上,即使元素是后添加的,我们可以尝试将其绑定给元素的共同祖先元素

    事件的委派

    • 指的是将事件统一绑定给元素的共同的祖先, 这样当后代元素上的事件触发时,会一直冒泡到祖先元素. 从而通过祖先元素的响应函数来处理事件
    • 事件委派利用了冒泡,利用委派可以减少事件绑定的次数,提高程序的性能

    event中的target

    • event中的target表示的是触发事件的对象
    • 如果触发事件的对象是我们期望的元素,则执行否则不执行;就是为了防止在其他的位置点也会执行
    • 为了便于使用target可以在相关元素中设置相应的属性标签
    <!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">
        <title>事件的委派</title>
        <script>
            window.onload = function () {
                // 点击按钮以后添加超链接
                var btn01 = document.getElementById("btn01");
                btn01.onclick = function () {
                    // 创建一个li
                    var li = document.createElement("li");
                    // 单引号记得改成双引号里面的,要不然双引号前后匹配会出错
                    li.innerHTML = "新建的超链接";
    
                    // 将li添加到ul中,父元素要用到的是id选择器中的东西
                    u1.appendChild(li);
                };
                /*
                    为每一个超链接都绑定一个单击响应函数
                    这里为每一个超链接都绑定了一个单击响应函数,
                        这种操作比较麻烦
                    而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定
                */
                // 获取所有的a
                var allA = document.getElementsByTagName("a");
                // 遍历
                // for(var i = 0; i < allA.length; i++){
                //     allA[i].onclick = function(){
                //         alert("我是a的单击响应函数");
                //     };
                // }
    
                /*
                    我们希望, 只绑定一次事件,即可应用到多个元素上,即使元素是后添加的
                    我们可以尝试将其绑定给元素的共同祖先元素
    
                    事件的委派
                    - 指的是将事件统一绑定给元素的共同的祖先, 这样当后代元素上的事件触发时,会一直冒泡到祖先元素
                        从而通过祖先元素的响应函数来处理事件
                    - 事件委派利用了冒泡,利用委派可以减少事件绑定的次数,提高程序的性能
    
                */
                // 为ul绑定一个单击响应函数
                u1.onclick = function (event) {
                    event = event || window.event;
                    /*
                        target
                        - event中的target表示的是触发事件的对象
                    */
                    // 如果触发事件的对象是我们期望的元素,则执行否则不执行
                    // 就是为了防止在其他的位置点也会执行
                    if(event.target.className == "link"){
                        alert("我是ul的单击响应函数");
                    }
                };
            };
        </script>
    </head>
    
    <body>
        <button id="btn01">添加超链接</button>
        <ul id="u1" style="background-color: #bfa;">
            <li><a href="javascript:;" class="link">超链接一</a></li>
            <li><a href="javascript:;" class="link">超链接二</a></li>
            <li><a href="javascript:;" class="link">超链接三</a></li>
        </ul>
    </body>
    
    </html>
    

    事件的绑定

    目的:点击按钮以后弹出一个内容

    • 使用 对象.事件 = 函数的形式绑定响应函数;只能同时为事件绑定一个响应函数,不能绑定多个,如果绑定了多个,则后边会覆盖前边的

    介绍两个事件绑定函数
    1、addEventListener()

    • 通过这个方法也可以为元素绑定响应函数
    • 参数:① 事件的字符串,不要on ② 回调函数 - 当事件触发时该函数会被调用 ③ 是否在捕获阶段触发事件,需要布尔值,一般都传false
    • 使用addEventListener() 可以同时为一个元素的相同事件同时绑定多个响应函数
    • 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行;这个方法不支持IE8及以下的浏览器

    2、attachEvent()

    • 在IE8中可以使用attachEvent() 来绑定事件
    • 参数:① 事件的字符串,要on ② 回调函数
    • 这个方法也可以同为一个事件同时绑定多个处理函数, 不同的是它是后绑定先执行,执行顺序和addEventListener() 相反

    注意点

    • addEventListener() 中的this,是绑定事件的对象,attachEvent() 中的this是window,需要统一两个方法this
    <!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">
        <title>事件的绑定</title>
        <script>
            window.onload = function () {
                /*
                    点击按钮以后弹出一个内容
                */
                /*
                     使用 对象.事件 = 函数的形式绑定响应函数
                     它只能同时为事件绑定一个响应函数,
                     不能绑定多个,如果绑定了多个,则后边会覆盖前边的
                */
                // 获取按钮对象
                var btn01 = document.getElementById("btn01");
                //    btn01.onclick = function(){
                //        alert("hello");
                //    };
                // 为btn01 绑定第二个响应函数,
                //    btn01.onclick = function(){
                //        alert(2);
                //    };
    
                /*
                    addEventListener()
                    - 通过这个方法也可以为元素绑定响应函数
                    - 参数:
                        1、事件的字符串,不要on
                        2、回调函数 - 当事件触发时该函数会被调用
                        3、是否在捕获阶段触发事件,需要布尔值,一般都传false
    
                    使用addEventListener() 可以同时为一个元素的相同事件同时绑定多个响应函数
                        - 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
                        - 这个方法不支持IE8及以下的浏览器
    
    
                */
                /* btn01.addEventListener("click", function () {
                    alert(1);
                }, false);
    
                btn01.addEventListener("click", function () {
                    alert(2);
                }, false);
                */
                /*
                     attachEvent()
                     - 在IE8中可以使用attachEvent() 来绑定事件
                     - 参数:
                         1、事件的字符串,要on
                         2、回调函数
                    - 这个方法也可以同为一个事件同时绑定多个处理函数, 
                        不同的是它是后绑定先执行,执行顺序和addEventListener() 相反
    
                */
                btn01.attachEvent("onclick", function () {
                    alert(1);
                });
                btn01.attachEvent("onclick", function () {
                    alert(2);
                });
            };
    
            // 定义一个函数,用来为指定元素绑定响应函数
            /* 
                addEventListener() 中的this,是绑定事件的对象
                attachEvent() 中的this是window,
                需要统一两个方法this
            */
    
            /*
                参数:
                obj 要绑定事件的对象
                eventStr 事件的字符串
                callback 回调函数
            */
            function bind(obj, eventStr, callback){
    
            }
        </script>
    
    </head>
    
    <body>
        <button id="btn01">点我一下</button>
    </body>
    
    </html>
    

    完成bind函数

    /*
        参数:
        obj 要绑定事件的对象
        eventStr 事件的字符串
        callback 回调函数
    */
    function bind(obj, eventStr, callback) {
        if (obj.addEventListener) {
            // 大部分浏览器兼容的方式
            obj.addEventListener(eventStr, callback, false);
        } else {
            /*
                this是谁由调用方式决定
                callback.call(obj) call方法可以改变调用方式
            */
            // IE8及以下
            obj.attachEvent("on" + eventStr, function () {
                // 在匿名函数中调用回调函数
                callback.call(obj);
            });
        }
    };
    

    事件的传播(了解)

    • 关于事件的传播网景公司和微软公司有不同的理解
    • 微软公司认为事件应该由内向外传播的,也就是事件触发时,应该先触发当前元素上的事件;然后再向当前元素的祖先元素,也就是说事件应该在冒泡阶段执行
    • 网景公司认为事件是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件然后向内传播给后代
    • W3C综合了两个公司的方案,将事件传播分成了三个阶段:
      1、捕获阶段
    • 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
      2、目标阶段
    • 事件捕获到目标元素,捕获结束,开始在目标元素上触发事件
      3、冒泡阶段
    • 事件从目标元素向祖先元素传递,依次触发祖先元素上的事件
    • 如果希望在捕获阶段就触发事件,可以将addEventListener() 的第三个参数设置为true; 一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
    • IE8及以下的浏览器中没有捕获阶段

    拖拽

    拖拽的流程

    • 当鼠标在被拖拽元素上按下时,开始拖拽
    • 鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
    • 当鼠标松开时,被拖拽元素被固定在当前位置 onmouseup

    代码实现

    <script>
        window.onload = function () {
            /*
                拖拽box1元素
                - 拖拽的流程
                    1、当鼠标在被拖拽元素上按下时,开始拖拽
                    2、鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                    3、当鼠标松开时,被拖拽元素被固定在当前位置 onmouseup
    
            */
            /*
                onmousedown
            */
            // 获取box1
            var box1 = document.getElementById("box1");
            // 为box1绑定一个鼠标按下事件
            box1.onmousedown = function () {
                //  alert("鼠标开始拖拽");
                // 为document绑定一个onmousemove事件
                document.onmousemove = function (event) {
                    event = event || window.event;
                    // 鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                    // 获取鼠标的坐标
                    var left = event.clientX;
                    var top = event.clientY;
                    // 修改box1的位置
                    box1.style.left = left + "px";
                    box1.style.top = top + "px";
                }
            };
            // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
            document.onmouseup = function () {
                // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
                // 当鼠标在结束以后相应的事件该结束就应该结束
                // 取消document的onmousemove事件
                document.onmousemove = null;
                // 取消document的onmouseup事件
                document.onmouseup = null;
            };
        };
    </script>
    

    上述实现方式会出现鼠标经常会进行移动的操作
    所以应该实时获取到鼠标的坐标

    拖拽二

    <script>
        window.onload = function () {
            /*
                拖拽box1元素
                - 拖拽的流程
                    1、当鼠标在被拖拽元素上按下时,开始拖拽
                    2、鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                    3、当鼠标松开时,被拖拽元素被固定在当前位置 onmouseup
    
            */
            /*
                onmousedown
            */
            // 获取box1
            var box1 = document.getElementById("box1");
            // 为box1绑定一个鼠标按下事件
            box1.onmousedown = function (event) {
                event = event || window.event;
                //  alert("鼠标开始拖拽");
                // div的偏移量,鼠标.clientX - 元素.offsetLeft
                // div的偏移量,鼠标.clientY - 元素.offsetTop
                var ol = event.clientX - box1.offsetLeft;
                var ot = event.clientY - box1.offsetTop;
    
    
                // 为document绑定一个onmousemove事件
                document.onmousemove = function (event) {
                    event = event || window.event;
                    // 鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                    // 获取鼠标的坐标
                    var left = event.clientX - ol;
                    var top = event.clientY - ot;
                    // 修改box1的位置
                    box1.style.left = left + "px";
                    box1.style.top = top + "px";
                }
                // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
                document.onmouseup = function () {
                    // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
                    // 当鼠标在结束以后相应的事件该结束就应该结束
                    // 取消document的onmousemove事件
                    document.onmousemove = null;
                    // 取消document的onmouseup事件
                    document.onmouseup = null;
                };
            };
        };
    
    </script>
    

    拖拽三

    setCapture()

    • 当调用一个元素的setCapture() 方法以后,这个元素将会把下一次所有的鼠标按下相关的事件捕获到自身上
    <script>
        window.onload = function(){
            // 分别为两个按钮绑定单击响应函数
            var btn01 = document.getElementById("btn01");
            var btn02 = document.getElementById("btn02");
            btn01.onclick = function(){
                alert(1);
            };
            btn02.onclick = function(){
                alert(2);
            };
    
            // 设置btn01 对鼠标按下相关事件进行捕获
            // 当调用一个元素的setCapture() 方法以后,这个元素将会把下一次所有的鼠标按下相关的事件捕获到自身上
            btn01.setCapture();
        };
    </script>
    
    • 上述代码按住按钮1,所有的鼠标按下相关的事件捕获到btn01上面
    • 只有IE支持,但是在火狐调用中不报错,而如果使用chrome调用,会报错
    <script>
        window.onload = function () {
            /*
                拖拽box1元素
                - 拖拽的流程
                    1、当鼠标在被拖拽元素上按下时,开始拖拽
                    2、鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                    3、当鼠标松开时,被拖拽元素被固定在当前位置 onmouseup
    
            */
            /*
                onmousedown
            */
            // 获取box1
            var box1 = document.getElementById("box1");
            // 为box1绑定一个鼠标按下事件
            box1.onmousedown = function (event) {
                // 设置box1捕获所有鼠标按下的事件
                /*
                    setCapture()
                    - 只有IE支持,但是在火狐调用中不报错
                    而如果使用chrome调用,会报错
    
                */
               // 写法一
                // if(box1.setCapture){
                //     box1.setCapture();
                // }
                // 写法二: 如果前面为true,看后面的,如果前面为false,不看了
                box1.setCapture && box1.setCapture();
                event = event || window.event;
                //  alert("鼠标开始拖拽");
                // div的偏移量,鼠标.clientX - 元素.offsetLeft
                // div的偏移量,鼠标.clientY - 元素.offsetTop
                var ol = event.clientX - box1.offsetLeft;
                var ot = event.clientY - box1.offsetTop;
    
    
                // 为document绑定一个onmousemove事件
                document.onmousemove = function (event) {
                    event = event || window.event;
                    // 鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                    // 获取鼠标的坐标
                    var left = event.clientX - ol;
                    var top = event.clientY - ot;
                    // 修改box1的位置
                    box1.style.left = left + "px";
                    box1.style.top = top + "px";
                };
                // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
                document.onmouseup = function () {
                    // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
                    // 当鼠标在结束以后相应的事件该结束就应该结束
                    // 取消document的onmousemove事件
                    document.onmousemove = null;
                    // 取消document的onmouseup事件
                    document.onmouseup = null;
                    // 当鼠标松开时,取消对事件的捕获
                    box1.releaseCapture && box1.releaseCapture();
                };
                /*
                    当我们拖拽一个网页中内容时,浏览器会默认去搜索引擎中搜索内容
                    此时会导致拖拽功能的异常,这个是浏览器提供的默认行为
                    如果不希望发生这个行为,则可以通过return false 来取消这个默认行为
    
                    但是这招对IE8不管用
                */
                return false;
    
            };
        };
    </script>
    
    • 对上述代码进行一个改进总结,方便实现对每次传入一个对象都可以进行拖拽
    <script>
         window.onload = function () {
             /*
                 拖拽box1元素
                 - 拖拽的流程
                     1、当鼠标在被拖拽元素上按下时,开始拖拽
                     2、鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                     3、当鼠标松开时,被拖拽元素被固定在当前位置 onmouseup
    
             */
             /*
                 onmousedown
             */
             // 获取box1
             var box1 = document.getElementById("box1");
             var box2 = document.getElementById("box2");
             var img1 = document.getElementById("img1");
    
             // 开启box1的拖拽
             drag(box1);
             drag(box2);
             drag(img1);
         };
         /*
             提取一个专门用来设置拖拽的函数
             参数,
         */
         function drag(obj) {
             obj.onmousedown = function (event) {
                 // 设置box1捕获所有鼠标按下的事件
                 /*
                     setCapture()
                     - 只有IE支持,但是在火狐调用中不报错
                     而如果使用chrome调用,会报错
    
                 */
                 // 写法一
                 if (obj.setCapture) {
                     obj.setCapture();
                 }
                 // 写法二: 如果前面为true,看后面的,如果前面为false,不看了
                 obj.setCapture && obj.setCapture();
                 event = event || window.event;
                 //  alert("鼠标开始拖拽");
                 // div的偏移量,鼠标.clientX - 元素.offsetLeft
                 // div的偏移量,鼠标.clientY - 元素.offsetTop
                 var ol = event.clientX - obj.offsetLeft;
                 var ot = event.clientY - obj.offsetTop;
    
    
                 // 为document绑定一个onmousemove事件
                 document.onmousemove = function (event) {
                     event = event || window.event;
                     // 鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
                     // 获取鼠标的坐标
                     var left = event.clientX - ol;
                     var top = event.clientY - ot;
                     // 修改box1的位置
                     obj.style.left = left + "px";
                     obj.style.top = top + "px";
                 };
                 // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
                 document.onmouseup = function () {
                     // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
                     // 当鼠标在结束以后相应的事件该结束就应该结束
                     // 取消document的onmousemove事件
                     document.onmousemove = null;
                     // 取消document的onmouseup事件
                     document.onmouseup = null;
                     // 当鼠标松开时,取消对事件的捕获
                     obj.releaseCapture && obj.releaseCapture();
                 };
                 /*
                     当我们拖拽一个网页中内容时,浏览器会默认去搜索引擎中搜索内容
                     此时会导致拖拽功能的异常,这个是浏览器提供的默认行为
                     如果不希望发生这个行为,则可以通过return false 来取消这个默认行为
     
                     但是这招对IE8不管用
                 */
                 return false;
    
             };
         };
    </script>
    

    你可能感兴趣的:(web前端技术,javascript,前端)