JavaScript教程(一)

计算机语言

机器语言、汇编语言和高级语言

  • 计算机语言指用于人与计算机之间通讯的语言,它是人与计算机之间传递信息的媒介;
  • 计算机语言的种类非常多,总的来说可以分成【机器语言】、【汇编语言】和【高级语言】三大类;
  • 实际上计算机最终所执行的都是【机器语言】,它是由“0”和“1”组成的二进制数,二进制是计算机语言的基础;
    在这里插入图片描述
  • 编程语言是用来控制计算机的一系列指令,它有固定的格式和词汇(不同编程语言的格式和词汇不一样),必须遵守;
  • 如今通用的编程语言有两种形式:【汇编语言】和【高级语言】;
  • 【高级语言】主要是相对于低级语言而言的,它并不是特指某一种具体的语言,而是包括了很多编程语言,常用的有:C语言、C++、Java、C#、Python、PHP、Go语言、Objective、Swift等;
  • 【翻译器】:高级语言所编制的程序不能直接被计算机识别,必须经过转换才能被执行,为此,我们需要一个翻译器;翻译器可以将我们所编写的源代码转换为机器语言,这也被称为二进制化。记住1和0;
    JavaScript教程(一)_第1张图片

【编程语言】和【标记语言】的区别?

  • 【编程语言】有很强的逻辑和行为能力。在编程语言里,会看到很多if else 、for、while等具有逻辑性和行为能力的指令,这是主动的;
  • 【标记语言】(html)不用于向计算机发出指令,常用于格式化和链接。标记语言的存在是用来被读取的,它是被动的;

计算机基础

计算机组成

JavaScript教程(一)_第2张图片
JavaScript教程(一)_第3张图片

数据存储

  • 计算机内部使用二进制0和1来表示数据;
  • 所有数据,包括文件、图片等最终都是以二进制数据(0和1)的形式存放在硬盘中的;
  • 所有程序,包括操作系统,本质都是各种数据,也以二进制数据的形式放在硬盘中。平时我们所说的安装软件,其实就是把程序文件复制到硬盘中;
  • 硬盘、内存都是保存的二进制数据;

数据存储单位

JavaScript教程(一)_第4张图片

程序运行

JavaScript教程(一)_第5张图片

初识JavaScript

JavaScript简介

  • 发明者:布兰登 艾奇
  • JavaScript是一种运行在客户端的脚本语言(script是脚本的意思);
  • 脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行;
  • 现在也可以基于Node.js技术进行服务器端编程;
    JavaScript教程(一)_第6张图片
    JavaScript教程(一)_第7张图片

浏览器执行JS简介

  • 浏览器分成两部分:【渲染引擎】和【JS引擎】;
  • 【渲染引擎】:用来解析HTML与CSS,俗称【内核】,比如:chrome浏览器的blink,老版本的webkit;
  • 【JS引擎】:也称为【JS解释器】。用来读取网页中的JavaScript代码,对其处理后运行,比如chrome浏览器的V8;
  • 浏览器本身并不会执行JS代码,而是通过内置JavaScript引擎(解释器)来执行JS代码。JS引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以JavaScript语言归为脚本语言,会逐行解释执行;

JS组成

JavaScript教程(一)_第8张图片

ECMAScript

JavaScript教程(一)_第9张图片

DOM

JavaScript教程(一)_第10张图片

BOM

JavaScript教程(一)_第11张图片

JS的输入和输出语句

JavaScript教程(一)_第12张图片

变量

什么是变量?

  • 通俗:变量是用于存放数据的容器。我们通过【变量名】获取数据,甚至数据可以修改;

变量在内存中的存储

  • 本质:变量是程序在内存中申请的一块用来存放数据的空间;

变量的使用

  • 变量在使用时分为两步:1、声明变量;2、赋值
    JavaScript教程(一)_第13张图片
    JavaScript教程(一)_第14张图片
    JavaScript教程(一)_第15张图片

变量案例-弹出输入的用户名

<!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>
</head>

<body>
    <script>
        // 1、输入用户姓名,存储到一个 myName 的变量中
        var myName = prompt('请输入用户名')
        // 2、输出这个用户名
        alert(myName)
    </script>
</body>

</html>

变量的语法扩展

  • 更新变量:一个变量被重新赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准;
  • 同时申明多个变量时,只需要写一个 var ,多个变量名之间使用英文逗号隔开;
    在这里插入图片描述
  • 声明变量的特殊情况:
    (1)、只声明不赋值,程序也不知道里面存的是啥,所以结果是 undefined(未定义的);
    (2)、不声明 不赋值 直接使用某个变量,会报错(xxx is not defined);
    (3)、不声明 直接赋值使用:可以正常使用,是一个全局变量;

变量的命名规范

JavaScript教程(一)_第16张图片

  • 我们尽量不要使用“name”作为变量名;
    JavaScript教程(一)_第17张图片
案例:显示年龄案例
<body>
    <script>
        var age = prompt("请输入你的年龄");
        var str = '你今年已经' + age + '岁了';
        alert(str)
    </script>
</body>

数据类型

为什么需要数据类型?

JavaScript教程(一)_第18张图片

变量的数据类型

JavaScript教程(一)_第19张图片

<script>
        // int num=10;  java
        // var num; //这里的num 我们是不确定属于哪种数据类型的 

        var num = 10; //num属于数字型
        // js 的变量数据类型是只有程序在运行过程中,根据等号右边的值来确定的

        // js是动态语言 变量的数据类型是可以变化的
        var x = 10; // x 是数字型
        x = 'pink'; //x 是字符串
</script>

数据类型的分类

JavaScript教程(一)_第20张图片
JavaScript教程(一)_第21张图片
JavaScript教程(一)_第22张图片
JavaScript教程(一)_第23张图片

数据类型转换

JavaScript教程(一)_第24张图片
JavaScript教程(一)_第25张图片
JavaScript教程(一)_第26张图片

  • 注意:代表【空】、【否定的值】会被转换为【false】,如:‘’ 0 NaN null undefined;其余值都会被转换为 true;
隐式转换
  • 【隐式转换】是我们在进行算数运算的时候,JS自动转换了数据类型;
//利用算数运算 - * / 来隐式转换;
<script>
	console.log('12'-0);//隐式转换为 数字型12
	console.log('123'-'120');
</script>
案例:计算年龄案例
<body>
    <!-- 此案例要求在页面中弹出一个输入框,我们输入出生年份后,能计算出我们的年龄 -->
    <!-- 
        案例分析:
          1、弹出一个输入框(prompt),让用户输入出生年份(用户输入);
          2、把用户输入的值用变量保存起来,然后用今年的年份减去变量值,结果就是现在的年龄(程序内部处理);
          3、弹出警示框(alert),把计算的结果输出(输出结果);
     -->
     <script>
        var year=prompt("请输入你的出生年份");
        var age=2022-year;//按道理year取过来的是字符串型,做减法操作这里做了隐式转换;
        alert('你的年龄是'+age+'岁');
     </script>
</body>
案例:简单加法器案例
<body>
    <!-- 计算两个数的值,用户输入第一个值后,继续弹出第二个输入框并输入第二个值,最后通过弹出框口显示出两次输入值相加的结果 -->
    <script>
        var num1 = prompt("请输入第一个值");
        var num2 = prompt("请输入第二个值");
        var result = parseFloat(num1) + parseFloat(num2);
        alert("你的结果是:" + result);
    </script>
</body>

补充:解释型语言和编译型语言

JavaScript教程(一)_第27张图片

运算符(算数运算符、递增和递减运算符、比较运算符、逻辑运算符、赋值运算符)

  • 运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号;JavaScript中常用的运算符有:算数运算符、递增和递减运算符、比较运算符、逻辑运算符、赋值运算符;
    JavaScript教程(一)_第28张图片

补充:表达式和返回值

  • 表达式:是由数字、运算符、变量等以能求得数值的有意义排列方法所得的组合;简单理解:是由数字、运算符、变量等组成的式子;【表达式最终都会有一个结果,返回给我们,我们称之为返回值。】

短路运算(逻辑中断)

  • 短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;

逻辑与

  • 语法:表达式1 && 表达式2;
  • 如果第一个表达式的值为真,则返回表达式2;
  • 如果第一个表达式的值为假,则返回表达式1;
<body>
    <!-- 
        1、用我们的布尔值参与的逻辑运算 true && false == false;  
     -->
    <script>
        // 3、逻辑与短路运算
        // 3.1、逻辑与短路运算 如果表达式1结果为真,则返回表达式2;
        console.log(123 && 456);//456
        // 3.2、逻辑与短路运算 如果第一个表达式的值为假,则返回表达式1;
        console.log(0 && 456);//0
        // 如果有空的或者否定的为假(如:0、''、null、undefined、NaN),其余是真的;

        // 4、逻辑或短路运算
        // 4.1、如果表达式1结果为真,则返回的是表达式1;
        console.log(123 || 456);//123
        // 4.2、如果表达式1结果为假,则返回的是表达式2;
        console.log(0 || 456);//456

	// 案例分析(123为真,直接返回123,后面的 num++ 就不再执行了,所以是结果是0)
        var num=0;
        console.log(123 || num++);
        console.log(num);//0
	</script>
</body>

赋值运算符

  • 概念:用来把数据赋值给变量的运算符;
    JavaScript教程(一)_第29张图片
<script>
        var num = 10;
        //num=num+1; num++
        //num = num + 2; ==> num += 2;
        num += 2;
        console.log(num);//12
    </script>

运算符优先级

JavaScript教程(一)_第30张图片

  • 一元运算符里面的逻辑非(!)优先级很高;
  • 逻辑与比逻辑或优先级高;

流程控制(顺序结构、分支结构、循环结构)

  • 在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候,我们要通过控制代码的执行顺序来实现我们要完成的功能;
  • 简单理解:流程控制就是来控制我们的代码按照什么结构顺序来执行;
  • 流程控制主要有三种结构,分别是:顺序结构分支结构循环结构,这三种结构代表三种代码执行的顺序;
    JavaScript教程(一)_第31张图片
  • 顺序结构:是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的;
  • 分支结构:由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果;JS语言提供了两种分支结构语句:if语句、switch语句;

流程控制-分支(if分支语句、switch分支语句、三元表达式)

案例:判断平年、闰年案例

<body>
    <!-- 
        算法:能被4整除且不能整除100的为闰年(如2004年就是闰年,1901年不是闰年)或者能被400整除的就是闰年;
     -->
     <script>
        var year=prompt("请输入年份:");
        if(year % 4 ==0 && year % 100 !== 0 || year % 400 ==0){
            alert("你输入的年份是闰年");
        }else{
            alert("你输入的年份是平年");
        }
     </script>
</body>

案例:数字补零

<body>
    <!-- 
        案例描述:用户输入数字,如果数字小于0,则在前面补零;如果数字大于0,则不需要补。
     -->
    <script>
        var time = prompt("请输入一个0~59之间的一个数字");
        var result = time < 10 ? "0" + time : time
        alert(result);
    </script>
</body>

switch语句

  • 当要针对变量设置一系列的特定值的选项时,就可以用switch语句;
  • switch是转换、开关的意思;case小例子或者选项的意思;
  • 语法结构:
switch(表达式){
	case value1:
		执行语句1break;
	case value2:
		执行语句2break;
	...
	default:
		执行最后的语句;
}
  • 执行思路:利用我们的【表达式的值】和【case后面的选项值】相匹配,如果匹配上,就执行该case里面的语句;如果都没有匹配上,那么执行default里面的语句。
  • 代码验证:
switch(2){
	case 1:
		console.log("这是1")break;
	case 2:
		console.log("这是2");;
		break;
	case 3:
		console.log("这是3");;
		break;
	default:
		console.log("没有匹配结果");;
}
  • switch注意事项:
    (1)、我们开发时,表达式经常写成变量;
    (2)、我们num的值和case里面的值相匹配的时候是【全等】(必须是值和数据类型一致才可以);
    (3)、break如果当前的case里面没有break,则不会退出switch,而是继续执行下一个case

案例:查询水果案例

<body>
    <script>
        var fruit = prompt("请输入水果:");
        switch (fruit) {
            case '苹果':
                alert('苹果');
                break;
            case '榴莲':
                alert('榴莲');
                break;
            default:
                alert('没有此水果');
        }
    </script>
</body>
  • switch语句和if else if语句的区别:
    (1)、一般情况下,它们两个语句可以相互替换;
    (2)、switch...case语句通常处理case为比较确定值的情况,而if...else...语句更加灵活,常用于范围判断(大于、等于某个范围);
    (3)、switch语句进行条件判断后直接执行到程序的条件语句,效率更高。而if...else...语句有几种条件,就得判断多少次;
    (4)、当分支比较少时,if...else...语句的执行效率比switch语句高;
    (5)、当分支比较多时,switch语句的执行效率比较高,而且结构更清晰;

流程控制-循环(for循环、while循环、do while循环)

  • 循环的目的:在实际问题中,有许多具有规律性的重复操作,因此在程序中要完成这类操作就需要重复执行某些语句;
  • 在JS中,主要有三种类型的循环语句:for循环、while循环、do while循环;
  • 在程序中,一组被重复执行的语句被称为【循环体】,能否继续重复执行,取决于循环的【终止条件】。由循环体及循环的终止条件组成的语句,被称为【循环语句】;
//for语法结构
for(初始化变量;条件表达式;操作表达式){
	//循环体
}
//初始化变量:就是用var声明的一个普通变量,通常用于作为计数器使用;
//条件表达式:就是用来决定每一次循环是否继续执行,就是终止的条件;
//操作表达式:就是每次循环最后执行的代码,经常用于我们计数器变量进行更新(递增或者递减);
  • for循环可以重复执行不同的代码,因为我们有计数器变量i的存在,i每次循环值都会变化;
//我们想要输出1个人1~100岁
for(var i=1;i<=100;i++){
	console.log('这个人今年'+i+'岁了');
}
  • for循环重复某些相同操作。for循环因为有了计数器的存在,我们还可以重复的执行某些操作,比如做一些算术运算;

案例:求1~100之间所有整数的累加和

<body>
    <!-- 
        案例分析:
         1、需要循环100次,我们需要一个计数器i;
         2、我们需要一个存储结果的变量sum,但是初始值一定是03、核心算法:1+2+3+4+...sum=sum+i;
     -->
     <script>
        var sum=0;//求和的变量
        for(var i=0;i<=100;i++){
            sum=sum+i;
        }
        console.log(sum);
     </script>
</body>

案例:for循环案例

 <script>
        // 1、求1-100之间所有数的平均值;
        var sum = 0;
        var average = 0;
        for (var i = 1; i <= 100; i++) {
            sum = sum + i;
        }
        average = sum / 100;
        console.log(average);//50.5

        // 2、求1-100之间所有偶数和奇数的和;
        var event = 0;
        var odd = 0;
        for (var i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                event = event + i;
            } else {
                odd = odd + i;
            }
        }
        console.log(event);//2550
        console.log(odd);//2500

        // 3、求1-100之间所有能被3整除的数字的和;
        var result = 0;
        for (var i = 1; i <= 100; i++) {
            if (i % 3 == 0) {
                result = result + i;
            }
        }
        console.log(result);//1683
    </script>

案例:求学生成绩案例

<body>
    <!-- 要求用户输入班级人数,之后依次输入每个学生的成绩,最后打印出该班级总的成绩以及平均成绩 -->
    <script>
        var num = prompt('请输入班级总人数:');
        var sum = 0;
        var average = 0;
        for (var i = 1; i <= num; i++) {
            var score = prompt('请输入第' + i + '个学生成绩');
            // 因为从prompt取过来的数据是 字符串型的 需要装换为 数字型;
            sum = sum + parseFloat(score);
        }
        average = sum / num;
        alert('班级总的成绩是' + sum);
        alert('班级平均分是' + average);
    </script>
</body>

案例:一行打印5颗星星

<script>
        var str = '';
        for (var i = 1; i <= 5; i++) {
            // console.log('⭐');
            // 我们采用追加字符串的方式,这样可以打印到控制台上;
            str = str + '⭐';
        }
        console.log(str);
    </script>
var num = prompt('请输入星星个数');
        var str = '';
        for (var i = 0; i < num; i++) {
            str = str + '⭐';
        }
        console.log(str);

双重for循环

  • 循环嵌套是指在一个循环语句中再定义一个循环语句的语法结构,例如在for循环语句中,可以再嵌套一个for循环,这样的for循环语句我们称之为双重for循环;
  • 我们可以把里面的循环看作是外层循环的语句;
  • 外层的循环循环一次,里面的循环执行全部;

案例:打印5行5列星星

 <script>
        var str = '';
        for (var i = 1; i <= 5; i++) {
            for (var j = 1; j <= 5; j++) {
                str = str + '⭐';
            }
            // 如果一行打印完毕5个星星,就要另起一行;(加 \n)
            str = str + '\n';
        }
        console.log(str);
    </script>

案例:打印n行n列星星

 <script>
        var row = prompt('请输入行数');
        var column = prompt('请输入列数');
        var str = '';
        for (var i = 1; i <=row; i++) {
            for (var j = 1; j <= column; j++) {
                str = str + '⭐';
            }
            str = str + '\n';
        }
        console.log(str);
    </script>

案例:打印倒三角案例

<script>
        var str = '';
        for (var i = 1; i <= 10; i++) {
            for (var j = i; j <= 10; j++) {
                str = str + '⭐';
            }
            str = str + '\n';
        }
        console.log(str);
    </script>

while循环

  • 语法结构:while(条件表达式){循环体}
  • 执行思路:当条件表达式结果为true,则执行循环体;否则,退出循环;
  • 代码验证:
var num=1;
while(num<=100){
	console.log('你好');
	num++;
}
  • 里面应该也有计数器,初始化变量;
  • 里面应该也有操作表达式,完成计数器的更新,防止死循环;

while循环案例

 <script>
        // 1、打印人的一生,从1岁到100岁;
        // var i=1;
        // while(i<=100){
        //     console.log('这个人今年'+i+'岁了');
        //     i++;
        // }

        // 2、计算1~100之间所有整数的和;
        // var i = 1;
        // var sum = 0;
        // while (i <= 100) {
        //     sum = sum + i;
        //     i++;
        // }
        // console.log(sum);

        // 3、弹出一个提示框,你爱我吗?如果输入我爱你,就提示结束,否则,一直询问;
        var message = prompt('你爱我吗?');
        while (message !== '我爱你') {
            message = prompt('你爱我吗?');
        }  
        alert('我也爱你呀'); 
    </script>

dowhile循环

  • dowhile语句其实是while语句的一个变体。该循环会先执行一次代码块,然后对条件表达式进行判断,如果条件为真,就会重复执行循环体,否则退出循环;
  • 语法结构:
do{
	//循环体
}while(条件表达式)
  • 执行思路:跟while不同的地方在于dowhile先执行一次循环体,再判断条件;如果条件表达式结果为真,则继续执行循环体,否则退出循环;
<script>
        // 代码验证
        var i = 1;
        do {
            console.log('你好');
            i++;
        } while (i <= 100)
</script>
  • dowhile语句至少会执行一次循环体代码;

dowhile案例

 <script>
        // 1、代码验证
        // var i = 1;
        // do {
        //     console.log('你好');
        //     i++;
        // } while (i <= 100)

        // 2、打印人的一生,从1岁到100岁;
        // var i = 1;
        // do {
        //     console.log('这个人今年'+i+'岁了');
        //     i++;
        // } while (i <= 100)

        // 3、计算1~100之间所有整数的和;
        // var i = 1;
        // var sum = 0;
        // do {
        //     sum = sum + i;
        //     i++;
        // } while (i <= 100)
        // console.log(sum);

        // 3、弹出一个提示框,你爱我吗?如果输入我爱你,就提示结束,否则,一直询问;        
        do {
            var message = prompt('你爱我吗?');
        } while (message !== '我爱你')
        alert('我也爱你呀');
    </script>

循环小结

  • JS中循环有forwhiledowhile
  • 三个循环很多情况下都可以互相替代使用;
  • 如果是用来计次数,跟数字相关的,三者使用基本相同,但是我们更喜欢用for
  • whiledowhile可以做更复杂的判断条件,比for灵活一些;
  • whiledowhile执行顺序不一样,while先判断,后执行;dowhile先执行一次,再判断执行;
  • whiledowhile执行次数不一样, dowhile至少会执行一次循环体,而while可能一次也不执行;
  • 实际工作中,我们更常用for循环,它的写法更简洁直观;

continuebreak关键字

continue关键字

  • 用于【立即跳出本次循环,继续下一次循环】(本次循环体中continue之后的代码就会少执行一次);

continue关键字案例

 <script>
        // continue关键字(退出本次,即当前次的循环;继续执行剩余次的循环)
        // for (var i = 1; i <= 5; i++) {
        //     if (i === 3) {
        //         continue; // 只要遇到continue就退出本次循环,直接跳到
        //     }
        //     console.log(i);//1 2 4 5
        // }

        // 案例:求1~100之间,除了能被7整除之外的整数和;
        var sum = 0;
        for (var i = 1; i <= 100; i++) {
            if (i % 7 == 0) {
                continue;
            }
            // sum = sum + i;
            sum += i;
        }
        console.log(sum);
    </script>

break关键字

  • break关键字用于立即跳出整个循环(循环结束);
 // break关键字(退出整个循环)
        for (var i = 1; i <= 5; i++) {
            if (i == 3) {
                break;//退出整个循环
            }
            console.log(i);// 1 2
        }

数组

案例:求数组最大值

<script>
        // 求数组[2,6,1,77,52,25,7]中的最大值;
        /*
        案例分析:
            (1)、声明一个保存最大元素的变量max;
            (2)、默认最大值可以取数组中的第一个元素;
            (3)、遍历这个数组,把里面每个数组元素和max相比较;
            (4)、如果这个数组元素大于max就把这个数组元素存到max里面,否则继续下一轮比较;
            (5)、最后输出这个max;
        */
        var arr = [2, 6, 1, 77, 52, 25, 7];
        var max = arr[0];
        for (var i = 1; i <= arr.length; i++) {
            if (max < arr[i]) {
                max = arr[i];
            }
        }
        console.log(max);
    </script>

数组中新增元素

  • 可以通过修改length长度以及索引号增加数组长度;
    (1)、可以通过修改length长度来实现数组扩容的目的;
  • length属性是可读写的;
    (2)、通过修改数组索引新增数组元素;
  • 可以通过修改数组索引的方式追加数组元素;
 <script>
        // 1、新增数组元素-修改length长度;
        var arr = ['red', 'green', 'blue'];
        console.log(arr.length);
        arr.length = 5;//我们把数组长度修改为了5,里面应该有5个元素;
        console.log(arr);// ['red', 'green', 'blue', empty × 2]
        console.log(arr[3]);//undefined
        console.log(arr[4]);//undefined

        // 2、新增数组元素-通过修改数组索引新增数组元素;追加数组元素;
        // 之前索引号里面没有元素时是追加元素;有元素时是替换元素;
        var arr1 = ['red', 'blue', 'green'];
        arr1[3] = 'pink';
        console.log(arr1);//['red', 'blue', 'green', 'pink']
        arr1='有点意思';
        console.log(arr1);//不能直接给数组名赋值,否则会覆盖掉以前的数据;
    </script>

案例:新建一个数组,里面存放10个整数(1-10)

<script>
        var arr = [];
        for (var i = 0; i < 10; i++) {
            //arr=i; //不要直接给数组名赋值,否则以前的元素都没了;
            arr[i] = i+1;
        }
        console.log(arr);// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
</script>

案例:筛选数组

方法一:

<script>
        // 将数组[2,0,6,1,77,0,52,0,25,7]中大于等于10的元素选出来,放入新数组;
        var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
        var arr1 = [];
        var j = 0;
        for (var i = 0; i <= arr.length; i++) {
            // 新数组应该从0开始,一次递增;
            if (arr[i] >= 10) {
                // arr1[i] = arr[i]; //[empty × 4, 77, empty, 52, empty, 25] 原因:从第四个开始有值,当i=1,2,3时是没有值存进去的;
                arr1[j] = arr[i];
                j++; //[77, 52, 25]
            }
        }
        console.log(arr1);
    </script>

方法二:

 // 筛选数组方法二:
        var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
        var arr1 = [];
        for (var i = 0; i <= arr.length; i++) {
            // 新数组应该从0开始,一次递增;
            if (arr[i] >= 10) {
                // arr1[i] = arr[i]; //[empty × 4, 77, empty, 52, empty, 25] 原因:从第四个开始有值,当i=1,2,3时是没有值存进去的;
                arr1[arr1.length] = arr[i];//刚开始 arr1.length 就是0;数组的length会根据数组长度的变化而变化;
            }
        }
        console.log(arr1);

案例:数组去重

<script>
        // 方法一:
        var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
        var newArr = [];
        // for (var i = 0; i < arr.length; i++) {
        //     if (newArr.indexOf(arr[i]) === -1) {
        //         newArr.push(arr[i]);
        //     }
        // }
        // console.log(newArr);

        // 方法二:
        var mySet=new Set(arr);//利用了Set结构不能接收重复数据的特点;
        for(var val of mySet){
            newArr.push(val);
        }
        console.log(newArr);
    </script>

案例:翻转数组

<script>
        // 要求:将数组['red','green','pink','blue',purper]的内容反过来存放;
        var arr = ['red', 'green', 'pink', 'blue', 'purper'];
        var newArr = [];
        for (var i = arr.length - 1; i >= 0; i--) {
            newArr[newArr.length] = arr[i];
        }
        console.log(newArr);
    </script>

复习:交换两个变量

var num1=10;
var num2=20;
var temp;
temp=num1;
num1=num2;
num2=temp;
console.log(num1,num2);

案例:数组排序(冒泡排序)

  • 冒泡排序是一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大或从大到小);
 <script>
        var arr = [5, 4, 3, 2, 1];
        for (var i = 0; i <= arr.length - 1; i++) {//外层循环管趟数
            for (var j = 0; j <= arr.length - i - 1; j++) {//里面的循环管每一趟的交换次数;
                // 内部交换两个变量的值,前一个和后面一个数组元素相比较;
                if (arr[j] > arr[j + 1]) {
                    var temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        console.log(arr);
    </script>

函数

函数导读

  • 函数:函数就是封装了一段可以被重复执行调用的代码块;目的就是让大量代码重复使用;
  • 函数使用分为两步:【声明函数】和【调用函数】;
function 函数名(){
	//函数体
}
函数名()
  • 函数是做某件事情,函数名一般是动词;(sayHi)
  • 函数不调用自己不执行;
  • 注意:声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码;
  • 函数的封装:就是把一个或多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口;

案例:利用函数求1~100的累加和

<script>
        function getSum() {
            var sum = 0;
            for (var i = 1; i <= 100; i++) {
                sum += i;
            }
            console.log(sum);
        }
        getSum();
    </script>

函数的参数

  • 我们可以利用函数的参数实现函数重复不同的代码;
  • 【形参】和【实参】;
function 函数名(形参1,形参2...){
	
}
函数名(实参1,实参2,...);
  • 在声明函数的小括号里面是【形参】;(形式上的参数)
  • 在函数调用的小括号里面是【实参】;(实际的参数)
  • 形参和实参的执行过程:(形参是接收实参的;形参类似于一个变量;)
  • 函数的参数可以有,也可以没有,个数不限;
    JavaScript教程(一)_第32张图片

案例:利用函数求任意两个数的和以及累加和

<script>
        // 1、利用函数求任意两个数的和
        function getSum(num1, num2) {
            console.log(num1 + num2);
        }
        getSum(1, 3);

        // 2、利用函数求任意两个数之间的和
        function getSums(start, end) {
            var sum = 0;
            for (var i = start; i <= end; i++) {
                sum += i;
            }
            console.log(sum);
        }
        getSums(1, 100);
    </script>
  • 注意点:
    (1)、多个参数之间用逗号隔开;
    (2)、形参可以看作是不用声明的变量;

函数的形参和实参匹配问题

  • 如果实参的个数和形参的个数一致,则正常输出结果;
  • 如果实参的个数多于形参的个数,会取到形参的个数;
  • 如果实参的个数小于形参的个数,多于的形参定义为undefined,最终的结果就是NaN
  • 形参可以看作是不用声明的变量,num2是一个变量但是没有接受值,结果就是undefined
  • 建议:我们尽量让实参的个数和形参相匹配;
function getSum(num1,num2){
	console.log(num1+num2);
}
getSum(1,2);
getSum(1,2,3);
getSum(1);//NaN (任何数字 + undefined = NaN )

JavaScript教程(一)_第33张图片

函数的返回值return

  • 有时候,我们会希望函数将值返回给调用者,此时通过使用return语句就可以实现;
function 函数名(){
	return 需要返回的结果;
}
 函数名();
  • 我们函数只是实现某种功能,最终的结果需要返回给函数的调用者;通过return来实现的;
  • 只要函数遇到return,就把后面的结果返回给函数的调用者;
  • 函数名() = return后面的结果;
function getResult(){
	return 666;
}
getResult()
console.log(getResult());//666

案例:求任意两个数的和

function getSum(num1,num2){
	return num1 + num2;
}
console.log(getSum(1,2));

案例:利用函数求两个数的最大值

<script>
        function getMax(num1, num2) {
            // if (num1 > num2) {
            //     return num1;
            // } else {
            //     return num2;
            // }
            return num1 > num2 ? num1 : num2;
        }
        console.log(getMax(6, 2));
    </script>

案例:利用函数求数组中的最大值

<script>
        // var arr=[5,2,99,101,67,77];
        function getArrMax(arr) {// arr 接收一个数组
            var max = arr[0];
            for (var i = 1; i <= arr.length; i++) {
                if (arr[i] > max) {
                    max = arr[i];
                }
            }
            return max;
        }
        // console.log(getArrMax([5, 2, 99, 101, 67, 77]));//实参是一个数组送过去  
        var re = getArrMax([5, 2, 99, 101, 67, 77]);
        console.log(re);
    </script>

return终止函数并且只能返回一个值

  • return终止函数,return语句之后的代码不被执行;
function getSum(num1,num2){
	return num1+num2;
	alert("我是不会被执行的");//return 后面的的代码不会被执行
}
console.log(getSum(1,2));
  • return只能返回一个值。如果用逗号隔开多个值,以最后一个为准;
function fn(num1,num2){
	return num1,num2;//返回的结果是最后一个值
}
console.log(fn(1,2));
  • 我们求任意两个数的 加减乘除 结果:
function getResult(num1,num2){
	return [num1+num2,num1-num2,num1*num2,num1/num2];
}
console.log(fn(1,2));//返回的是一个数组

函数没有return,返回undefined

  • 我们的函数如果有return,则返回的是return后面的值;如果函数没有return,则返回undefined

breakcontinuereturn的区别

JavaScript教程(一)_第34张图片

arguments 的使用

当我们不确定有多少个参数传递的时候,可以用arguments 来获取,在JS中,arguments 实际上它是当前函数的一个【内置对象】。所有函数都内置了一个arguments对象,arguments对象中【存储了传递的所有实参】;

<script>
        function fn() {
            console.log(arguments); // Arguments(3),arguments是以伪数组的形式来展示的;
            //我们可以按照数组的方式遍历 Arguments;
        }
        fn(1, 2, 3)
        /*
        伪数组并不是真正意义上的数组:
          1、具有数组的 length 属性;
          2、按照索引的方式进行存储的;
          3、没有真正数组的一些方法,如:pop()、push() 等;
        */
</script>

函数的两种声明方式

<script>
        // 1、利用函数关键字自定义函数(命名函数)
        function fn() { }
        fn()

        // 2、函数表达式(匿名函数)
        //注意:函数表达式声明方式跟变量差不多,只不过变量里面存的是值,而函数表达式里面存的是函数;
        // var 变量名 = function(){}
        var fun = function () { } // 注意:此处的 fun 是变量名,不是函数名;
        fun() // 变量名 + ()实现调用;函数表达式也可以进行传递参数;
</script>

arguments 案例:利用函数求任意几个数的最大值

 <script>
        function getMax() {
            var max = arguments[0];
            for (var i = 1; i < arguments.length; i++) {
                if (arguments[i] > max) {
                    max = arguments[i];
                }
            }
            return max;
        }
        console.log(getMax(7, 2, 5, 99, 0, 2346));      
    </script>

案例:利用函数封装方式,翻转任意一个数组

<script>
        function getArrReverse(arr) {
            var newArr = [];
            for (var i = arr.length - 1; i >= 0; i--) {
                newArr[newArr.length] = arr[i];
            }
            return newArr;
        }
        console.log(getArrReverse([1, 2, 3, 4, 5]));     
    </script>

案例:利用函数封装冒泡排序

<script>
        function sort(arr) {
            for (var i = 0; i <= arr.length - 1; i++) {
                for (var j = 0; j <= arr.length - i - 1; j++) {
                    if (arr[j] > arr[j + 1]) {
                        var temp = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = temp;
                    }
                }
            }
            return arr;
        }
        console.log(sort([5, 7, 3, 2, 0, 8, 1]));
    </script>

案例:运用函数封装判断闰年

 <script>
        // 闰年:能被4整除并且不能被100整除;或者能被400整除;
        // function isRunYear(year){
        //     if(year % 4 === 0 && year % 100 !=0 || year % 400 === 0){
        //         return year+'年是闰年';
        //     }else{
        //         return year+'年是平年';
        //     }
        // }
        // console.log(isRunYear(2020));

        function isRunYear(year){
            // 如果是闰年我们返回true;否则返回false;
            var flag = false;
            if(year % 4 === 0 && year % 100 !=0 || year % 400 === 0){
                flag = true;
            }
            return flag;
        }
        console.log(isRunYear(2000));
    </script>

函数可以调用另外一个函数

  • 因为每个函数都是独立的代码块,用于完成特殊任务,因此经常会用到函数相互调用的情况;
function fn1(){
	console.log(11);
	fn2();//在fn1函数里面调用了fn2函数;
}
fn1();
function fn2(){
	console.log(22);
}

一个函数调用另外一个函数案例:用户输入年份,输出当前年份2月份的天数

<script>
        function backDay(){
            var year = prompt('请输入年份');
            if(isRunYear(year)){//调用函数需要加小括号
                alert('当前年份是闰年,2月份有29天');
            }else{
                alert('当前年份是平年,2月份有28天');
            }
        }
        backDay();

        // 判断是否为闰年的函数
        function isRunYear(year){
            // 如果是闰年我们返回true;否则返回false;
            var flag = false;
            if(year % 4 === 0 && year % 100 !=0 || year % 400 === 0){
                flag = true;
            }
            return flag;
        }
    </script>

Javascript作用域

作用域概述:

通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的【可用性的代码范围】就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字的冲突。
Javascript作用域: 就是代码名字(变量)在某个范围内起作用和效果;目的是为了提高程序的可靠性,更重要的是减少命名冲突;js作用域(es6)之前:全局作用域 局部作用域;
全局作用域: 【整个 script 标签】或者是一个【单独的js文件】
局部作用域(函数作用域): 在函数内部就是局部作用域;这个代码的名字只在函数内部起效果和作用;

变量的作用域:

  • 根据作用域的不同,我们把变量分为【全局变量】和【局部变量】

全局变量:

  • 全局变量:在全局作用域下声明的变量(在函数外部定义的变量),在全局下都可以使用;
  • 全局变量在代码的任何位置都可以使用;
  • 在全局作用域下var声明的变量是【全局变量】;
  • 特殊情况下,在函数内不使用var声明的变量也是全局变量(不建议使用);
  • 注意:如果在函数内部,没有声明直接赋值的变量也属于【全局变量】;

局部变量:

  • 在局部作用域下声明的变量,或者在函数内部定义的变量就是局部变量;
  • 局部变量只能在该函数内部使用;
  • 在函数内部var声明的变量是局部变量;
  • 注意: 函数的形参也可以看做是【局部变量】;
从执行效率来看【全局变量】和【局部变量】:
  • 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源;
  • 局部变量当我们程序执行完毕就会销毁,比较节约内存资源;

块级作用域:

  • 用 {} 包裹

作用域链:

内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值,这种结构我们称为作用域链。(就近原则)

  • 只要是代码,就至少有一个作用域;
  • 写在函数内部的局部作用域;
  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;
  • 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称为【作用域链】;

预解析

  • JavaScript代码是由浏览器中的JavaScript解析器(引擎)来执行的。JavaScript解析器在运行JavaScript代码的时候分为两步:【预解析】和【代码执行】。
  • 预解析: js引擎会把js里面所有的 var,还有 function 提升到当前作用域的最前面;
  • 代码执行:按照代码书写的顺序从上往下执行;
  • 预解析分为【变量预解析(变量提升)】和【函数预解析(函数提升)】。
变量提升:
  • 就是把所有的变量声明提升到当前的作用域最前面,不提升赋值操作;
函数提升:
  • 就是把所有的函数声明提升到当前作用域的最前面,不调用函数;
// 1问
console.log(num) // 报错

// 2问
console.log(num) // undefined  坑1
var num=10
// 相当于执行了以下代码
var num ;
console.log(num)
num=10

// 3问
fn() // 11
function fn(){
 	console.log(11) 
}
fn() // 11

// 4问
fun() // 报错 fun is not a function
var fun=function(){ // 函数表达式 调用必须写在函数表达式的下面
	console.log(22) 
}
fun() // 22
//相当于执行了以下代码
var fun ;
fun();
fun=function(){
	console.log(22) 
}
  • 注意:
var a=b=c=9;
// 相当于:var a=9;b=9;c=9 区别于【集体声明】
//所以此处的 b 和 c 直接赋值,没有 var 声明,此处的 b 和 c 当全局变量看;

// 集体声明(用逗号隔开)
var a=9,b=9,c=9

对象

什么是对象?

  • 在Javascript中,对象是一组无序的相关属性和方法的集合,所有的事务都是对象,例如:字符串、数值、数组、函数等;
  • 对象是由【属性】和【方法】组成的:
    【属性】:事物的特征,在对象中用属性来表示(常用名词);
    【方法】:事物的行为,在对象中用方法来表示(常用动词);

为什么需要对象?

  • 保存一个值时,可以使用变量;保存多个值(一组值)时,可以使用数组。JS中的对象表达结构更清晰,更强大。

创建对象的三种方式

1、利用【字面量】创建对象;
  • 【对象字面量】就是花括号 {} ,里面包含了表达这个具体事物(对象)的属性和方法;
  • 调用属性还有一种方法:对象名[‘属性名’]
2、利用 【new Object】 创建对象;
3、利用【构造函数】创建对象;
  • 我们为什么需要使用构造函数?就是因为我们前面两种创建对象的方式一次只能创建一个对象;我们一次创建一个对象,里面很多的属性和方法是大量相同的,我们只能复制;因此,我们可以利用函数的方法,重复这些相同的代码,我们就把这个函数称为构造函数。又因为这个函数不一样,里面封装的不是普通代码,而是【对象】。
  • 构造函数:就是把我们对象里面一些相同的属性和方法抽象出来,封装到函数里面;
  • 构造函数: 是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
//构造函数的语法格式
function 构造函数名(){
	this.属性=this.方法=functon(){}
}
new 构造函数名() //调用构造函数
function Star(uname,age,sex){
	this.name=uname;
	this.age=age;
	this.sex=sex;
	this.sing=function(sang){
		console.log(sang)
	}
}
// 调用函数返回的是一个对象
var ldh = new Star('刘德华',18,'男') 
ldh.sing('冰雨');
console.log(typeof ldh)
console.log(ldh.name)
console.log(ldh['sex'])

注意:
1、构造函数名字首字母要大写;
2、我们构造函数不需要return 就可以返回结果;
3、我们调用构造函数,必须使用new;
4、我们只要 new Sar()调用函数,就创建一个对象;
5、我们的属性和方法前面必须添加this

构造函数和对象的区别?

  • 对象:是特指一个具体的事务,例如:刘德华;
  • 构造函数:抽象了对象的公共部分,封装到了函数里面,它泛指某一大类,例如:明星;它类似于Java语言里的类(class);
  • 我们利用构造函数(new关键字)创建对象的过程,也称为对象的【实例化】;

new关键字执行过程(new在执行时会做四件事)

1、new构造函数可以在内存中创建了一个空的对象;
2、this就指向刚才创建的空对象;
3、执行构造函数里面的代码,给这个空对象添加属性和方法;
4、返回这个新对象(所以构造函数里面不需要return);

遍历对象属性:for...in语句用于对【数组】或者【对象的属性】进行【循环】操作;

//for in 遍历对象
// 语法规则:for (变量 in 对象){}

for(var k in obj){
	console.log(k); // k:变量,输出得到的是:属性名
	console.log(obj[k]); // obj[k] 得到的是:属性值
	//注意:此处的 k 是一个变量,无需用引号包裹;
   // 我们使用 for in 时,里面的变量,我们喜欢写 k 或者 key
  // for in 也可以遍历出对象里面的方法
}

小结:

  • 对象可以让代码结构更清晰;
  • 对象是复杂数据类型 Object
  • 对象的本质:就是一组无序的相关属性和方法的集合;
  • 构造函数泛指某一大类,比如苹果,不管是红色苹果还是绿色苹果,都统称为苹果;
  • 对象实例特指一个事物,比如这个苹果等;
  • for in语句用于对对象的属性进行循环操作;

【变量】【属性】【函数】【方法】的区别

  • 变量:变量和属性的相同点:他们都是用来存储数据的;
  • 变量:单独声明并赋值,使用的时候直接写变量名,单独存在;
  • 属性:在对象里面的不需要声明的,使用的时候必须是 对象.属性;
  • 函数和方法的相同点:都是实现某种功能,做某件事;
  • 函数是单独声明,并且调用的;函数名 + ()调用;单独存在的;
  • 方法在对象里面,调用的时候:对象.方法()调用;

JavaScript内置对象

  • JavaScript中的对象分为3种:自定义对象、内置对象、浏览器对象;
  • 前面两种对象是JS基础内容,属于ECMAScript;第三个浏览器对象属于我们JS独有的;
  • 【内置对象】就是指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法);
  • JavaScript提供了多个内置对象:MathDateArrayString等;
  • https://developer.mozilla.org/zh-CN/
//利用对象封装自己的数学对象,里面有 PI 最大值和最小值  
var myMath={
	PI:3.141592653,
	max:function(){
		var max=arguments[0];
		for(var i=1;i<arguments.length;i++){
			if(arguments[i]>max){
				max=arguments[i]
			}
		}
		return max;
	},
	min:function(){
		var min=arguments[0];
		for(var i=1;i<arguments.length;i++){
			if(arguments[i]<min){
				min=arguments[i]
			}
		}
		return min;
	}
}
// 猜数字游戏案例
function getRandom(min,max){
	return Math.floor(Math.random() * (max-min + 1)) + min;
}
var random =getRandom(1,10);
while(true){ //死循环
	var num = prompt('你来猜?输入1~10之间的一个数字');
}
if(num>random){
	alert('你猜大了')
}else if(num<random){
	alert('你猜小了')
}else{
	alert('猜对了!')
	break; // 退出整个循环,结束程序
}

日期对象(Date()

  • 日期对象是一个构造函数,必须使用new来调用创建我们的日期对象;
  • 使用Date(),如果没有参数,返回当前系统的当前时间;
  • 参数常用的写法:数字型:2019,10,01或者是字符串型:2019-10-1 8:8:8
//格式化日期年月日星期(星期天返回的是0)
var arr=['星期天','星期一','星期二','星期三','星期四','星期五','星期六']
var date=new Date();
var day=date.getDay();
console.log(arr[day]) 
//封装一个函数返回当前的时分秒,格式:08:08:08
function getTimer(){
	var time=new Date();
	var h=time.getHours();
	h = h<10?'0'+h:h
	var m=time.getMinutes()
	m = m<10?'0'+m:m
	var s=time.getSeconds()
	s = s<10?'0'+s:s
	return h+':'+m+':'+s
}
console.log(getTimer()) 

倒计时案例:
JavaScript教程(一)_第35张图片

数组

JavaScript教程(一)_第36张图片
JavaScript教程(一)_第37张图片

字符串

基本包装类型

  • 对象才有属性和方法;复杂数据类型才有属性和方法;简单数据类型为什么会有length属性呢?
  • 基本包装类型:为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String、Number 和 Boolean(三种基本包装类型);基本包装类型就是把【简单数据类型】包装成为【复杂数据类型】,这样基本数据类型就有了【属性】和【方法】;
    (1)、把简单数据类型,包装成复杂数据类型;
    (2)、把临时变量的值给str;
    (3)、销毁这个临时变量;
var str = 'andy';
console.log(str.length);
var temp = new Sring('andy');
str = temp;
temp = null;

字符串的不可变

  • 字符串的不可变:指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址改变了,内存中新开辟了一个内存空间;所以不要大量的拼接字符串;
    JavaScript教程(一)_第38张图片
  • 字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串;
// 案例:查找字符串“abcoefoxyozzopp”中所有o出现的位置以及次数;
/*
核心算法:先查找第一个o出现的位置,然后,只要 indexOf 返回的结果不是 -1,就继续往后查找;因为 indexOf 只能查找到第一个,所以后面的查找一定是当前索引加1,从而继续查找;
*/ 
var str = 'abcoefoxyozzopp'
var index = str.indexOf('o')
var num = 0;
while(index !== -1){
	console.log(index)
	num++
	index = str.indexOf('0',index+1);
}
console.log('o出现的次数是' + num)
//案例:遍历字符串
// charAt(index) 根据位置返回字符
var str= 'andy'
console.log(str.charAt(3))

//遍历所有字符串
for(var i=0;i<str.length;i++){
	console.log(str.charAt(i))
}
// 有一个对象,判断该对象里有没有该属性 对象['属性名']
var o={
	age:18
}
if(o['age']){
	console.log('里面有该属性')
}else{
	console.log('里面没有该属性')
}
// 案例:统计字符串 'abcoefoxyozzopp' 中出现次数最多的字符 
/*
核心算法:利用 charAt() 遍历这个字符串;把每个字符都存储给对象,如果对象没有该属性,就为1,如果存在了就 +1;遍历对象,得到最大值和该字符;
*/
var str = 'abcoefoxyozzopp';
var o ={}
for(var i=0;i<str.length;i++){
	var charts=str.charAt(i) // charts 是字符串的每一个字符
	if(o[charts]){ //o[charts]得到的是属性值
		o[charts]++
    }else{
		o[charts]=1
	}
}
console.log(o)
// 遍历对象,求出出现最多的次数
var max = 0;
var ch = '';//统计出现次数最多的字符
for(var k in o){ //遍历对象用 for in 
	// k 得到的是属性名
	// o[k] 得到的是属性值
	if(o[k]>max){
		max=o[k];
		ch=k
	}
}
console.log(max)
console.log(ch)
  • 替换字符:str.replace('被替换的字符','替换为的字符'),只会替换第一个字符;
//案例:有一个字符 'abcoefoxyozzopp' ,要求把里面所有的 o 替换为 *;(该方法可用于实现过滤敏感词等功能)
var str = 'abcoefoxyozzopp';
while(str.indexOf('o') !== -1){
	str = str.replace('o','*')
}
console.log(str)

JavaScript简单数据类型和复杂数据类型

数据类型内存分配

  • 【简单数据类型】又叫做【基本数据类型】或【值类型】;【复杂类型】又叫做【引用类型】;
    (1)、值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型;(string 、number 、boolean 、 undefined 、null(null 返回的是一个空的对象 Object))
    注意:如果有个变量我们以后打算存储为对象,暂时没想好放啥,这个时候就给 null;
    (2)、引用类型:复杂数据类型,在存储时变量中存储的仅仅是【地址】(引用),因此叫做引用数据类型;通过 new 关键字创建对象(系统对象、自定义对象),比如 Object 、Array 、 Date 等;

堆和栈

  • 堆栈空间分配区别?
    (1)、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;简单数据类型存放到栈里面,里面直接开辟一个空间,存放的是值
    (2)、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收;复杂数据类型存放在堆里面;(复杂数据类型:首先在栈里面存放用【用十六进制表示】的地址,然后这个地址指向堆里面的数据)
    注意:JavaScript中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言;
    JavaScript教程(一)_第39张图片
    JavaScript教程(一)_第40张图片

简单类型传参(简单数据类型传参传值,复杂数据类型传参传地址)

  • 函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部的变量;
 function fn(a) {
            a++
            console.log(a); // 11
        }
        var x = 10
        fn(x)
        console.log(x);// 10

复杂类型传参

  • 函数的形参也可以看作是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name){
	this.name=name
}

function f1(x){//x=p
	 console.log(x.name)//2、这里输出什么?刘德华
	 x.name='张学友'
	 console.log(x.name)//3、这里输出什么?张学友
}

var p=new Person('刘德华')
 console.log(p.name)//1、这里输出什么?刘德华
 f1(p)
 console.log(p.name)//4、这里输出什么?张学友

Web APIs和JS基础

JavaScript教程(一)_第41张图片

  • API:是为我们程序员提供的一个接口,帮助我们实现某种功能,我们会使用就可以了,不必纠结内部如何实现;
  • Web API:是浏览器提供的一套操作【浏览器功能】和【页面元素】的API(BOM和DOM)。主要是针对于浏览器提供的接口,主要针对于浏览器做交互效果;
  • Web API一般都有输入和输出(函数的传参和返回值),Web API很多都是方法(函数)。

Dom

  • 什么是Dom?文档对象模型(Document Object Model,简称Dom),是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口
  • W3C已经定义了一系列DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。
  • Dom树:
    JavaScript教程(一)_第42张图片
  • 文档:一个页面就是一个文档,DOM中使用document表示。
  • 元素:页面中的所有标签都是元素,DOM中使用element表示。
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示。
  • DOM把以上内容都看做是对象。
  • DOM在我们实际开发中主要用来操作元素的。
  • 获取页面中的元素可以使用以下几种方法:(返回的是一个元素对象)
    (1)、根据ID获取;
    (2)、根据标签名获取;(返回的是获取过来元素对象的集合,以伪数组的形式存储的)(还可以获取某个元素(父元素)内部所有指定标签名的子元素,注意:父元素必须是【单个对象】(必须指明是哪一个元素对象),获取的时候不包括元素自己)
    var ol=document.getElementsByTagName('ol') console.log(ol[0].document.getElementsByTagName('li') )简单做法:给父元素添加ID,通过ID获取父元素,然后获取父元素里面的子元素;
    (3)、通过HTML5新增的方法获取;Document.getElementsByClassName()Document.querySelector('选择器')(根据指定选择器返回第一个元素对象)、Document.querySelectorAll('选择器')(根据指定选择器返回所有元素对象集合)
    (4)、特殊元素获取;
  • console.dir()打印我们返回的元素对象,更好的查看里面的属性和方法;
  • 获取body元素:document.body
  • 获取html元素:document.documentElement

事件

  • JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为;简单理解:触发 — 响应机制;
  • 事件三要素:事件是由三部分组成:事件源、事件类型、事件处理程序,被称为事件三要素
    (1)、事件源:事件被触发的对象;
    (2)、事件类型:如何触发,什么事件。比如:鼠标点击、鼠标经过、键盘按下;
    (3)、事件处理程序:通过一个函数赋值的方式完成;
<button id='btn'>按钮</button>

var btn=document.getElementById('btn');
btn.onclick=function(){
	alert('弹窗')
}

JavaScript教程(一)_第43张图片

操作元素

  • JavaScript的DOM操作可以改变网页内容、结构和样式,我们可以利用DOM操作元素来改变元素里面的内容、属性等。注意以下都是属性;

改变元素内容

  • element.innerText从起始位置到终止位置的内容,但它取出html标签,同时空格和换行也会去掉;(不识别html标签)非标准 去除空格和换行
<button>点击改变时间</button>
<div>写死的时间</div>
<p>123</p>

<script>
        // 1、获取元素
        var btn = document.querySelector('button');
        var div = document.querySelector('div')
        // 注册事件
        btn.onclick = function () {
            // div.innerText = '2022-1-2'
            div.innerText = getDate()
        }

        function getDate() {
            var date = new Date()
            var year = date.getFullYear();
            var month = date.getMonth();
            var dates = date.getDate();
            var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
            var day = date.getDay();
            return '今天是:' + year + '年' + month + '月' + dates + '日' + arr[day]
        }
         // 我们元素可以不用添加事件
        var p = document.querySelector('p')
        p.innerText = getDate()
</script>
  • element.innerHTML起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行;(识别html标签)W3C标准 保留空格和换行
var p = document.querySelector('p')
p.innerHTML = '今天是:2022-1-2' //实现给‘今天是’加粗
  • 这两个属性是可读写的,可以获取元素里面的内容。
<p>
	我是文字
	<span>123</span>
</p>

var p=document.querySelector('p')
console.log(p.innerText)//我是文字 123
console.log(p.innerHTML)//我是文字 123(空格和换行依然保留)

修改元素属性

常用元素的属性操作

  • innerTextinnerHTML改变元素内容;
  • srchref
  • idalttitle
//案例:分时问候案例
<img src="./images/shangwu.jpg" alt="">
<div>上午好</div>

<script>
        // 获取元素
        var img = document.querySelector('img')
        var div = document.querySelector('div')
        // 得到当前的小时数
        var date = new Date();
        var h = date.getHours();
        // 判断小时数改变图片和文字信息
        if (h < 12) {
            img.src = './images/shangwu.jpg'
            div.innerHTML = '上午好'
        } else if (h < 18) {
            img.src = './images/xiawuhao.jpg'
            div.innerHTML = '下午好'
        } else {
            img.src = './images/wanshanghao.jpg'
            div.innerHTML = '晚上好'
        }
</script>

表单元素的属性操作

  • 利用 DOM 可以操作如下表单元素的属性:type value checked selected disabled
  //1、获取元素
  var btn= document.querySelector('button')
  var input= document.querySelector('input')
  //2、注册事件  处理程序
  btn.onclick=function(){
	//btn.disabled=true //禁用按钮
	this.disabled=true //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>
    <style>
        .box {
            position: relative;
            width: 400px;
            border-bottom: 1px solid #ccc;
            margin: 100px auto;
        }

        .box input {
            width: 370px;
            height: 30px;
            border: 0;
            outline: none;
        }

        .box img {
            position: absolute;
            top: 2px;
            right: 2px;
            width: 24px;
        }
    </style>
</head>

<body>
    <div class="box">
        <label for="">
            <img src="./images/green_close_eye.png" alt="" id="eye">
        </label>
        <input type="password" name="" id="pwd">
    </div>
    <script>
        var eye = document.getElementById('eye')
        var pwd = document.getElementById('pwd')

        //方法1: 利用flag变量记录点击
         var flag = 0
         eye.onclick = function () {
             // 点击一次过后,flag一定要变化
             if (flag == 0) {
                 pwd.type = 'text'
                 eye.src='./images/green_open_eye.png'
                 flag = 1;//赋值操作
             } else {
                 pwd.type = 'password'
                 eye.src='./images/green_close_eye.png'
                 flag = 0;
             }
         }

        //方法2: 计数器思想记录点击
        var count = 0;
        eye.onclick = function () {
            count++
            if (count % 2 == 0) {
                eye.src = "./images/green_close_eye.png"
                pwd.type = "password"
            } else {
                eye.src = "./images/green_open_eye.png"
                pwd.type = "text"
            }
        }
    </script>
</body>

</html>

样式属性操作

  • 我们可以通过JS修改元素的大小、颜色、位置等样式;
  • element.style行内样式操作;
  • element.className类名样式操作;
  • 注意:JS里面的样式采取驼峰命名法,比如:fontSize backgroundColor;JS修改style样式操作,产生的是行内样式,CSS权重比较高;
循环精灵图背景
//案例:循环精灵图背景;可以利用for循环设置一组元素的精灵图背景。
<!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;
        }

        li {
            list-style-type: none;
        }

        .box {
            width: 250px;
            margin: 100px auto;
        }

        .box li {
            float: left;
            width: 24px;
            height: 24px;
            background-color: pink;
            margin: 15px;
            background: url(./images/icons.png) no-repeat;
        }
    </style>
</head>

<body>
    <div class="box">
        <ul>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
        </ul>
    </div>

    <script>
        // 1、获取所有元素,所有的li
        var lis = document.querySelectorAll('li')
        // 2、让索引号 乘以 44 就是每个 li 的背景y坐标,index就是我们的y坐标;
        for (var i = 0; i < lis.length; i++) {
            var index = i * 24 //我这张精灵图是24
            lis[i].style.backgroundPosition = '0-' + index + 'px'//精灵图的y坐标是负的;x坐标永远是0
            //lis[i].style.backgroundPosition = '0 0' //全部展示第一张图片
            //lis[i].style.backgroundPosition = '0 -24px' //全部展示第二张图片
        }
    </script>
</body>

</html>
案例:当鼠标点击文本框时,里面的默认文字隐藏;当鼠标离开文本框时,里面的文字显示;
//案例:当鼠标点击文本框时,里面的默认文字隐藏;当鼠标离开文本框时,里面的文字显示;
//`onfocus` `onblur`
<!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>
        input {
            color: #999;
        }
    </style>
</head>

<body>
    <input type="text" value="手机">
    <script>
        var text = document.querySelector('input')
        text.onfocus = function () {
            console.log('得到了焦点');
            if (this.value === '手机') {
                this.value = ''
            }
            this.style.color = '#333'//获得焦点时把文本框里的文字的颜色变深
        }
        text.onblur = function () {
            console.log('失去了焦点');
            if (this.value === '') {
                this.value = '手机'
            }
            this.style.color = '#999'//失去焦点时把文本框里的文字的颜色变浅
        }
    </script>
</body>

</html>

样式属性操作:我们可以通过JS修改元素的颜色、大小、位置等样式

  • element.style 行内样式操作;
  • element.className 类名样式操作;
<!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>使用className修改样式属性</title>
    <style>
        div{
            width: 50px;
            height: 50px;
            background-color: green;
        }
        .change{
            width: 100px;
            height: 100px;
            background-color: aqua;
            margin-top: 100px;
        }
    </style>
</head>
<body>
    <div class='fist'>文本</div>
    <script>
        var test=document.querySelector('div')
        test.onclick=function(){
        //我们可以通过 修改元素的 className 更改元素的样式,适合于样式较多或者功能复杂的情况       
        this.className='change'//点击时给div加上change的类名
         //如果想要保留原先的类名,我们可以这么做 --->  多类名选择器
        this.className='fist change'
        }
    </script>
</body>
</html>
  • 注意:className 会直接更改元素的类名,会覆盖原先的类名;
  • 如果想要保留原先的类名,我们可以这么做 —> 多类名选择器
案例:密码框验证信息
<!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>
        div {
            width: 600px;
            margin: 100px auto;
        }

        .message {
            display: inline-block;
            font-size: 12px;
            color: #999;
            background: url(./images/reg.jpg) no-repeat left center;
            padding-left: 20px;
        }

        .wrong {
            color: red;
            background-image: url(./images/wrong.jpg);//注意:此处不用写no-repeat left center
        }

        .right {
            color: green;
            background-image: url(./images/right.jpg);//注意:此处不用写no-repeat left center
        }
    </style>
</head>

<body>
    <div class="register">
        <input type="password" class="ipt">
        <p class="message">请输入6~16位密码</p>
    </div>
    <script>
        var ipt = document.querySelector('.ipt')
        var messege = document.querySelector('.message')
        ipt.onblur = function () {
            if (this.value.length < 6 || this.value.length > 16) {
                messege.className = 'message wrong';
                messege.innerHTML = '你输入的位数不对,要求6~16位'
            } else {
                messege.className = 'message right';
                messege.innerHTML = '你输入的正确'
            }
        }
    </script>
</body>

</html>

操作元素小结:

JavaScript教程(一)_第44张图片

排他思想

  • 如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法;
    (1)、第一步:所有元素全部清除样式;
    (2)、第二步:给当前元素设置样式;
<!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>
</head>

<body>
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    <script>
        // 首先先排除其他人,然后才设置自己的样式,这种排除其他人的思想我们称为排他思想
        var btns = document.querySelectorAll('button')
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function () {
                // 1、我们先把所有按钮的背景颜色去掉
                for (var i = 0; i < btns.length; i++) {
                    btns[i].style.backgroundColor = ''
                }
                // 2、然后才让当前的元素背景颜色为pink
                this.style.backgroundColor = 'pink'
            }
        }
    </script>
</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;
        }

        body {
            background: url(./images/01.jpeg) no-repeat center top;
        }

        .baidu {
            overflow: hidden;
            margin: 100px auto;
            background-color: #fff;
            width: 410px;
            padding-top: 3px;
        }

        .baidu li {
            /* list-style: none; */
            float: left;
            margin: 0 1px;
            cursor: pointer;
        }

        .baidu img {
            width: 100px;
        }
    </style>
</head>

<body>
    <ul class="baidu">
        <li><img src="./images/01.jpeg" alt=""></li>
        <li><img src="./images/02.jpeg" alt=""></li>
        <li><img src="./images/03.jpeg" alt=""></li>
        <li><img src="./images/04.jpeg" alt=""></li>
    </ul>
    <script>
        // 1、获取元素(类名是 baidu 下的 img)
        var imgs = document.querySelector('.baidu').querySelectorAll('img')
        // 2、循环注册事件
        for (var i = 0; i < imgs.length; i++) {
            imgs[i].onclick = function () {
                // this.src 就是我们点击的图片的路径
                // 把这个路径 this.src 给 body 就可以了
                 //document.body.style.backgroundImage获取body的背景图片
            document.body.style.backgroundImage = 'url(' + this.src + ')'
            }
        }
    </script>
</body>

</html>

表格隔行变色效果案例

//onmouseover鼠标经过  onmouseout鼠标离开
<!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>
        table{
            width: 800px;
            margin: 100px auto;
            text-align: center;
            border-collapse: collapse;//设置表格的边框是否被合并为一个单一的边框
            font-size: 14px;
        }
        thead tr{
            height: 30px;
            background-color: skyblue;
        }
        tbody tr{
            height: 30px;
        }
        tbody td{
            border-bottom: 1px solid #d7d7d7;
            color: blue;
        }
        .bg{
            background-color: pink;
        }
    </style>
</head>
<body>
    <table>
        <thead>
            <tr>
                <th>代码</th>
                <th>名称</th>
                <th>最新公布净值</th>
                <th>累计净值</th>
                <th>前单位净值</th>
                <th>净值增长率</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>003526</td>
                <td>农行金穗3个月定期开放债券</td>
                <td>1.075</td>
                <td>1.079</td>
                <td>1.074</td>
                <td>+0.047%</td>
            </tr>
            <tr>
                <td>003527</td>
                <td>农行金穗4个月定期开放债券</td>
                <td>1.075</td>
                <td>1.079</td>
                <td>1.074</td>
                <td>+0.047%</td>
            </tr>
        </tbody>
    </table>
    <script>
        // 1、获取元素 获取 tbody 里面所有的 tr
        var trs=document.querySelector('tbody').querySelectorAll('tr')
        // 2、利用循环绑定注册事件
        for(var i=0;i<trs.length;i++){
            // 3、鼠标经过事件 onmouseover
            trs[i].onmouseover=function(){
                this.className='bg';
            }
            // 4、鼠标离开事件 onmouseout
            trs[i].onmouseout=function(){
                this.className='';
            }
        }
    </script>
</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>
        .wrap {
            width: 300px;
            margin: 100px auto;
        }

        table {
            width: 100%;
            margin: 100px auto;
            text-align: center;
            border-collapse: collapse;
            font-size: 14px;
        }

        thead tr {
            height: 30px;
            background-color: skyblue;
        }

        tbody tr {
            height: 30px;
        }

        tbody td {
            border-bottom: 1px solid #d7d7d7;
        }
    </style>
</head>

<body>
    <div class="wrap">
        <table>
            <thead>
                <tr>
                    <th>
                        <input type="checkbox" id="j_cbAll">
                    </th>
                    <th>商品</th>
                    <th>价钱</th>
                </tr>
            </thead>
            <tbody id="j_tb">
                <tr>
                    <td>
                        <input type="checkbox">
                    </td>
                    <td>iphone8</td>
                    <td>8000</td>
                </tr>
                <tr>
                    <td>
                        <input type="checkbox">
                    </td>
                    <td>iphone9</td>
                    <td>9000</td>
                </tr>
                <tr>
                    <td>
                        <input type="checkbox">
                    </td>
                    <td>iphone10</td>
                    <td>10</td>
                </tr>
            </tbody>
        </table>
    </div>
    <script>
        // 第一步:全选和取消全选的做法:让下面所有复选框的checked属性(选中状态)跟随 全选按钮即可
        // 1、获取元素
        var j_cbAll = document.getElementById('j_cbAll'); // 全选按钮
        var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');//下面所有的复选框
        // 2、注册事件
        j_cbAll.onclick = function () {
            // this.checked 它可以得到当前复选框的选中状态,如果是 true 就选中,如果是 false ,就是未选中;
            console.log(this.checked);
            for (var i = 0; i < j_tbs.length; i++) {
                j_tbs[i].checked = this.checked;//将全选按钮的选中或未选中状态赋值给所有的 checkbox 
            }
        }
        //第二步:下面复选框需要全部选中,上面全选才能选中做法:给下面所有复选框绑定点击事件,每次点击,都要循环遍历
        for (var i = 0; i < j_tbs.length; i++) {
            j_tbs[i].onclick = function () {
                // flag 控制全选按钮是否选中
                var flag = true
                // 每次点击下面的复选框都要循环检查这四个小按钮是否全被选中
                for (var i = 0; i < j_tbs.length; i++) {
                    if (!j_tbs[i].checked) {
                        flag = false;
                        break;//退出for循环,这样可以提高执行效率;因为只要有一个没有选中,剩下的就循环判断了;
                    }
                }
                j_cbAll.checked = flag
            }
        }
    </script>
</body>

</html>

自定义属性的操作

获取自定义属性值

  • element.属性 获取属性值;
<div id='demo'></div>

var div=document.querySelector('div')
// 获取元素的属性
// 方法1:element.属性
console.log(div.id); // demo
  • element.getAttribute('属性') attribute 本意“属性”;
<div id='demo'></div>

var div=document.querySelector('div')
// 获取元素的属性
// 方法2:element.getAttribute('属性')
console.log(div.getAttribute('id')); // demo
  • element.属性 获取属性值 和 element.getAttribute('属性') 获取属性值 的区别?
    (1)、element.属性 获取内置属性值(元素本身自带的属性)如:id class等;
    (2)、element.getAttribute('属性') 主要获得自定义的属性(标准)我们程序员自定义的属性;

设置属性值

  • element.属性 = '值' 设置内置属性值;
<div id='demo' class='nav'></div>

var div = document.querySelector('div')
div.className= 'sss'
  • element.setAttribute('属性','值') ;主要针对于自定义属性;
<div id='demo' index='1' class='nav'></div>

var div = document.querySelector('div')
div.setAttribute('index','2')
 // class比较特殊,这里面写的就是class,不是className
div.setAttribute('class','sss')

移除属性

  • element.removeAttribute('属性')
<div id='demo' index='1' class='nav'></div>

var div = document.querySelector('div')
div.removeAttribute('index')

tab栏切换案例

<!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>tab栏切换案例</title>
    <style>
        .tab {
            width: 1200px;
            height: 100px;
        }

        .tab_list {
            width: 100%;
            float: left;
        }

        .tab_con {
            width: 100%;
            float: left;
            padding: 20px 60px;
        }
        .tab_list ul{
            width: 95%;
            height: 39px;
            background: rgb(223, 221, 221);
        }

        .tab_list li {
            float: left;
            height: 39px;
            line-height: 39px;
            padding: 0 20px;
            text-align: center;
            cursor: pointer;
            list-style: none;
        }

        .tab_list .current {
            background-color: #c81623;
            color: #fff;
        }

        .item_info {
            padding: 20px 0 0 20px;
        }

        .item {
            display: none;
        }
    </style>
</head>

<body>
    <div class="tab">
        <div class="tab_list">
            <ul>
                <li class="current">商品介绍</li>
                <li>规格与包装</li>
                <li>售后保障</li>
                <li>商品评价</li>
                <li>手机社区</li>
            </ul>
        </div>
        <div class="tab_con">
            <div class="item" style="display: block;">
                商品介绍模块内容
            </div>
            <div class="item">
                规格与包装模块内容
            </div>
            <div class="item">
                售后保障模块内容
            </div>
            <div class="item">
                商品评价模块内容
            </div>
            <div class="item">
                手机社区模块内容
            </div>
        </div>
    </div>
    <script>
        // 先获取父组件,再获取父组件下的所有的li
        var tab_list = document.querySelector('.tab_list');
        var lis = tab_list.querySelectorAll('li');
        var items = document.querySelectorAll('.item')
        // for循环绑定点击事件
        for (var i = 0; i < lis.length; i++) {
            // 开始给5个小li 设置索引号
            lis[i].setAttribute('index', i) // element.setAttribute('属性','值')

            // 1、上面的模块选项卡:点击某一个,当前这个底色会是红色,其余不变(排他思想) 修改类名的方式
            // 干掉所有人,其余的li清除class这个类
            lis[i].onclick = function () {
                for (var i = 0; i < lis.length; i++) {
                    lis[i].className = '';
                }
                // 留下我自己
                this.className = 'current'
                /*
                2、下面的显示内容模块:下面的模块显示内容和上面的选项卡一一对应,相匹配;
                 给上面的tab_list里面的所有小li添加自定义属性,属性值从0开始编号;
                */
                var index = this.getAttribute('index')//element.getAttribute('属性')
                console.log(index);
                // 干掉所有人,让其余的item 这些div隐藏
                for (var i = 0; i < lis.length; i++) {
                    items[i].style.display = 'none'
                }
                // 留下我自己,让对应的item显示出来
                items[index].style.display = 'block'
            }
        }
    </script>
</body>

</html>

H5自定义属性

  • 自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中;
  • 自定义属性获取是通过element.getAttribute('属性') 获取;但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性;
<div getTime='20'></div>

// getTime 是自定义属性,只能通过 getAttribute 获取
var div = document.querySelect('div')
console.log(div.getTime) // undefined
console.log(div.getAttribute('getTime'))

H5给我们新增了自定义属性

设置H5自定义属性

  • H5规定自定义属性以 data- 开头作为属性名并且赋值;
<div data-index='1'></div>

// 或者使用JS设置 element.setAttribute('data-index',2)
div.setAttribute('data-time',20)

获取H5自定义属性

  • 兼容性获取 element.getAttribute('data-index')
  • H5新增 element.dataset.index 或者 element.dataset['index'] ie11才开始支持;(只能获取以data- 开头的)
<div getTime="20" data-index="2" data-list-name="andy"></div>

<script>
  	var div=document.querySelector('div')
    // H5新增的获取自定义属性的方法
    // dataset 是一个【集合】,里面存放了所有以data开头的自定义属性
    console.log(div.dataset);// DOMStringMap {index: '2'}
    console.log(div.dataset.index);// 2
    console.log(div.dataset['index']);// 2 
    // 如果自定义属性里面有多个 - 连接的单词,我们获取的时候采用【驼峰命名法】
    console.log(div.dataset.listName); //andy
</script>

DOM中的节点操作

  • 获取元素通常使用两种方式:
    (1)、利用DOM提供的方法获取元素:如:document.getElementById() 等;这种方法逻辑性不强、繁琐;
    (2)、利用节点层级关系获取元素:利用父子兄节点关系获取元素;这种方法逻辑性强,但是兼容性稍差;
    ** 这两种方法都可以获取元素节点,我们后面都会用到,但是节点操作更简单。

节点概述

  • 网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node 来表示;
  • HTML DOM 树中的所有节点均可以通过JavaScript 进行访问,所有HTML 元素(节点)均可被修改,也可以创建和删除;
  • 一般的,节点至少拥有nodeType (节点类型)、nodeName (节点名称)、nodeValue (节点值)这三个基本属性;
  • 元素节点nodeType 为1;
  • 属性节点nodeType 为2;
  • 文本节点nodeType 为3;(文本节点包含文字、空格、换行等)
  • 我们在实际开发中,节点操作主要操作的是元素节点;
<div class="box"></div>

var box=document.querySelector('.box')
console.dir(box) 

JavaScript教程(一)_第45张图片

节点操作之父节点

节点层级

  • 利用DOM 树可以把节点划分为不同的层级关系,常见的是【父子兄层级关系】;
父级节点: node.parentNode
  • 得到的是离元素最近的父级节点;如果指定的节点没有父节点就返回null
<div class="box">
	<span class="erweima"></span>
</div>

//获取父节点
var erweima=document.querySelector('.erweima')
//获取 erweima 节点的父节点;得到的是离元素最近的父级节点
erweima.parentNode 

节点操作之子节点

子节点: parentNode.childNodes(标准)(获取到的是所有的子节点,包含 元素节点、文本节点等)

  • parentNode.childNodes 返回包含指定节点的子节点的集合,该集合为即时更新的集合;
  • 注意:返回值里面包含了所有的子节点,包括元素节点、文本节点等;如果只想要获得里面的元素节点,则需要专门处理。所以我们一般不提倡使用 childNodes
<ul>
	<li></li>
	<li></li>
	<li></li>
</ul>

//DOM提供的方法(API)获取
var ul=document.querySelector('ul')
var lis=ul.querySelectorAll('li')

//子节点(获取到的是所有的子节点,包含 元素节点、文本节点等)
console.log(ul.childNodes)
  • 专门处理:只想要获得里面的元素节点
var ul=document.querySelector('ul')
for(var i=0;i<ul.childNodes.length;i++){
	if(ul.childNodes[i].nodeType == 1){
		//ul.childNodes[i]是元素节点
		console.log(ul.childNodes[i])
	}
}
  • parentNode.children (非标准):是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回(这个是我们重点掌握的);虽然parentNode.children 是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用。
//children 获取所有的子元素节点(也是我们实际开发常用的)
var ul=document.querySelector('ul')
console.log(ul.children )

节点操作之第一个子元素和最后一个子元素

<ol>
	<li></li>
	<li></li>
	<li></li>
</ol>

var ol=document.querySelector('ol')
//1、firstChild 第一个子节点,不管是文本节点还是元素节点;找不到就返回 null
console.log(ol.firstChild)
console.log(ol.lastChild)

//2、firstElementChild 返回第一个子元素节点
console.log(ol.firstElementChild)
console.log(ol.lastElementChild)
  • parentNode.firstElementChildparentNode.lastElementChild 注意:这两个方法有兼容性问题,IE9 以上才支持;
  • 实际开发中,firstChildlastChild 包含其他节点,操作不方便;而firstElementChild lastElementChild 又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
    (1)、如果想要第一个子元素节点,可以使用parentNode.children[0]
//实际开发的写法,既没有兼容性问题又返回第一个子元素
console.log(ol.children[0])
console.log(ol.children[3])//第四个子元素

//得到最后一个子元素
console.log(ol.children[ol.children.length-1])

新浪下拉菜单案例

<ul class="nav">
        <li>
            <a href="#">微博</a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
    </ul>

    <script>
        // 1、获取元素
        var nav = document.querySelector('.nav');
        var lis = nav.children; //得到四个小li
        // 2、循环遍历事件
        for (var i = 0; i < lis.length; i++) {
            lis[i].onmouseover = function () {
                this.children[1].style.display = 'block'
            }
            lis[i].onmouseout = function () {
                this.children[1].style.display = 'none'
            }
        }
    </script>

兄弟节点 node.nextSiblingnode.previousSiblingnode.nextElementSiblingnode.previousElementSibling

  • node.nextSibling 返回当前元素的下一个兄弟节点(包括【元素节点】 和 【文本节点】等等),找不到就返回null;同样,也是包含所有的节点;
<div>我是div</div>
<span>我是span<span>

var div=document.querySelector('div')
console.log(div.nextSibling) //得到div的兄弟节点,包括元素节点 和 文本节点 #text
  • node.previousSibling 返回当前元素的上一个兄弟节点(包括【元素节点】 和 【文本节点】等等),找不到就返回null;同样,也是包含所有的节点;
  • node.nextElementSibling 返回当前元素下一个兄弟元素节点,找不到就返回null;
  • node.previousElementSibling 返回当前元素上一个兄弟元素节点,找不到就返回null;
  • node.nextElementSiblingnode.previousElementSibling 这两个方法有兼容性问题,IE9以上才支持;
如何解决兼容性问题?自己封装一个兼容性的函数。
function getNextElementSibling(element){
	var el=element;
	while(el=el.nextSibling){
		if(el.nodeType === 1){
			return el;
		}
	}
	return null
}

节点操作之创建和添加节点

创建节点:document.createElement('tagName')

  • document.createElement() 方法创建由tagName 指定的HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称之为【动态创建元素节点】;
<ul></ul>

//创建元素节点(只是创建了节点,未添加到页面上)
var li=document.createElement('li');

添加节点:node.appendChild(child)node.insertBefore(child,指定元素)

  • node.appendChild(child) 方法将一个节点添加到指定父节点的子节点列表【末尾】。类似于css 里面的after 伪元素;(node 是父级;child 是子级)
<ul></ul>

//创建元素节点(只是创建了节点,未添加到页面上)
var li=document.createElement('li');
var ul=document.querySelector('ul')
//将节点添加到页面上
ul.appendChild(li)
  • node.insertBefore(child,指定元素) 方法将一个节点添加到父节点的指定子节点的【前面】。类似于css 里面的before 伪元素;
<ul></ul>

//创建元素节点(只是创建了节点,未添加到页面上)
var lili=document.createElement('li');
var ul=document.querySelector('ul')
//将节点添加到ul的第一个子节点的前面上
ul.insertBefore(lili,ul.children[0])
  • 总结:我们想要页面添加一个新的元素:1、创建元素;2、添加元素;
案例:简单版本发布留言
<!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>
</head>

<body>
    <textarea name="" id="" cols="30" rows="10"></textarea>
    <button>发布</button>
    <ul></ul>

    <script>
        // 1、获取元素
        var btn = document.querySelector('button');
        var text = document.querySelector('textarea');
        var ul = document.querySelector('ul');
        // 2、注册事件
        btn.onclick = function () {
            if (text.value == '') {
                alert('你没有输入内容')
                return false
            } else {
                // (1)、创建元素
                var li = document.createElement('li');
                // 先有li才能赋值
                li.innerHTML = text.value
                // (2)、添加元素
                // ul.appendChild(li) //添加到最后
                // 添加到最前面
                ul.insertBefore(li,ul.children[0])
            }
        }
    </script>
</body>

</html>

节点操作 - 删除节点 node.removeChild(child)

  • node.removeChild(child)方法从DOM 中删除一个子节点,返回删除的节点;
<button>删除</button>
<ul>
	<li>熊大</li>
	<li>熊二</li>
	<li>光头强</li>
<ul>
//1、获取元素
var ul=document.querySelector('ul');
//2、删除元素
//ul.removeChild(ul.children[0]) //删除“熊大”
//3、点击按钮,依次删除里面的孩子
var btn=document.querySelector('button');
btn.onclick=function(){
	if(ul.children.length == 0){
		this.disabled= 'true' // 元素删完让按钮置灰
	}else{
  		ul.removeChild(ul.children[0])
	}
}
案例:删除留言案例
<!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>
        li {
            width: 300px;
            padding: 5px;
            background-color: pink;
            color: red;
            font-size: 14px;
            margin: 15px 0;
        }

        li a {
            float: right;
        }
    </style>
</head>

<body>
    <textarea name="" id="" cols="30" rows="10"></textarea>
    <button>发布</button>
    <ul></ul>

    <script>
        // 1、获取元素
        var btn = document.querySelector('button');
        var text = document.querySelector('textarea');
        var ul = document.querySelector('ul');
        // 2、注册事件
        btn.onclick = function () {
            if (text.value == '') {
                alert('你没有输入内容')
                return false
            } else {
                // (1)、创建元素
                var li = document.createElement('li');
                // 先有li才能赋值
                // 小技巧:阻止连接跳转需要添加 javascript:void(0); 或 javascript:;
                li.innerHTML = text.value + "删除"

                // (2)、添加元素
                // ul.appendChild(li) //添加到最后
                // 添加到最前面
                ul.insertBefore(li, ul.children[0])

                // (3)、删除元素 删除的是当前链接的li,它的父亲 this.parentNode 
                var as = document.querySelectorAll('a')
                for (var i = 0; i < as.length; i++) {
                    as[i].onclick = function () {
                        ul.removeChild(this.parentNode);
                    }
                }
            }
        }
    </script>
</body>

</html>
  • 小技巧:阻止连接跳转需要添加javascript:void(0); javascript:; 如:删除

节点操作 - 复制节点(克隆节点) node.cloneNode()

  • node.cloneNode()方法返回调用该方法的节点的一个副本。也称为【克隆节点】或【拷贝节点】;
<ul>
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul>

var ul=document.querySelector('ul')
//1、克隆节点,第一个li
var lili= ul.children[0].cloneNode()

//2、将克隆的第一个节点放到页面中
ul.appendChild(lili)
  • 注意
    (1)、如果括号参数【空】或者为【false】,则是【浅拷贝】,即只克隆复制节点本身,不克隆里面的子节点。(只复制标签,不复制里面的内容。)node.cloneNode()
    (2)、 想要深拷贝,括号里面填true 即可(既复制标签,也复制里面的内容);node.cloneNode(true)
案例:动态生成表格
<!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>
        table {
            width: 500px;
            margin: 100px auto;
            border-collapse: collapse;
            text-align: center;
        }

        td,
        th {
            border: 1px solid #333;
        }

        thead tr {
            height: 40px;
            background-color: #ccc;
        }
    </style>
</head>

<body>
    <table cellspacing="'0">
        <thead>
            <tr>
                <th>姓名</th>
                <th>科目</th>
                <th>成绩</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>

    <script>
        // 1、先准备好学生的数据
        var datas = [
            { name: '张三', subject: 'javaSript', score: 100 },
            { name: '李四', subject: 'javaSript', score: 100 },
            { name: '王五', subject: 'javaSript', score: 100 },
        ]
        // 2、往 tbody 里面创建行,有几个人(通过数组的长度)我们就创建几行;
        var tbody = document.querySelector('tbody')
        for (var i = 0; i < datas.length; i++) { //外面的for循环管行 tr
            // 创建 tr 行
            var tr = document.createElement('tr')
            tbody.append(tr) //将创建的 tr 放到 tbody 里
            // 行里面创建单元格 td (跟数据有关系的三个单元格),单元格的数量取决于每个对象里面的属性个数 for循环遍历对象
            for (var k in datas[i]) { //里面的for循环管列 td
                //创建单元格
                var td = document.createElement('td')
                // 把对象里面的属性值 datas[i][k]  给 td
                console.log(datas[i][k]); //对象里面的属性值 
                td.innerHTML = datas[i][k];
                tr.append(td) //将创建好的 td 放到 tr 里               
            }
            // 3、创建有删除2个字的单元格
            var td = document.createElement('td');
            td.innerHTML = '删除';
            tr.appendChild(td)
        }
        // 4、删除操作
        var as = document.querySelectorAll('a')
        for (var i = 0; i < as.length; i++) {
            as[i].onclick = function () {
                // 点击a,删除当前a所在的行(链接的爸爸的爸爸)
                tbody.removeChild(this.parentNode.parentNode)
            }
        }

        // 复习:for in 遍历对象
        // for(var k in obj){
        //     k 得到的是属性名
        //     obj[k] 得到的是属性值
        // }
    </script>
</body>

</html>

节点操作 - document.write 创建元素

三种动态创建元素的区别:

  • document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘;(页面上之前的元素被清除,重新创建了一个新的页面,新页面上只展示document.write创建的元素)
<button>点击</button>
    <p>abdjk</p>
    <script>
        // document.write 会导致页面重绘(页面上之前的元素被清除,重新创建了一个新的页面,新页面上只展示document.write创建的元素);(如果页面文档流加载完毕,再调用这句话会导致页面重绘)
        var btn=document.querySelector('button')
        btn.onclick=function(){
            document.write('
123
'
) } </script>
//当整个页面都加载完了,再调用里面的函数
window.onload=function(){}
  • element.innerHTMLdocument.createElement 效率对比:
    (1)、element.innerHTML 是将内容写入某个DOM 节点,不会导致页面全部重绘;创建多个元素效率更高(不是拼接字符串,而是采取数组的形式拼接),结构稍微复杂;
    (2)、document.createElement 创建多个元素效率稍微低一点点,但是结构更清晰;
    (3)、总结:不同浏览器下,element.innerHTML 效率要比 document.createElement 高;

Dom 重点核心总结

  • 文档对象模型(Document Object Model,简称 DOM),是W3C组织推荐的处理可扩展标记语言(HTML 或 XML)的标准【编程接口】;
  • W3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式;
  • 对于 javaSript ,为了能够使 javaSript 操作 HTML ,javaSript 就有了一套自己的 DOM 编程接口;
  • 对于 HTML ,dom 使得 html 形成一棵 dom树,包含文档、元素、节点;
    JavaScript教程(一)_第46张图片
  • 我们获取过来的DOM元素是一个对象(Object),所以称为【文档对象模型】;
  • 关于DOM操作,我们主要针对于【元素的操作】。主要有:创建、增、删、改、查、属性操作、事件操作;
  • 创建:document.writeinnerHtmlcreateElement
  • 增:appendChildinsertBefore
  • 删:removeChild
  • 改:主要修改dom的元素属性,dom元素的内容、属性、表单的值等
    (1)、修改元素属性:src href title 等;
    (2)、修改普通元素内容:innerHTML innerText
    (3)、修改表单元素:value type disabled 等;
    (4)、修改元素样式:style className
  • 查:主要获取查询dom的元素:
    (1)、DOM提供的API方法:getElementById 等;
    (2)、H5提供的新方法:querySelector querySelectorAll
    (3)、利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling nextElementSibling)提倡使用;
  • 属性操作:主要针对于自定义属性
    (1)、setAttribute :设置dom的属性值;
    (2)、getAttribute :得到dom的属性值;
    (3)、removeAttribute :移除属性;
  • 事件操作:给元素注册事件,采取 事件源.事件类型=事件处理程序
    JavaScript教程(一)_第47张图片

事件高级

注册事件两种方式

  • 给元素添加事件,称为【注册事件】或者【绑定事件】;
  • 注册事件有两种方式:【传统方式】和【方法监听注册方式】;
    (1)、传统方式:利用 on 开头的事件 onclick ;特点:注册事件的【唯一性】,即同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数;
<button onclick='alert("hi~")'></button>
btn.onclick=function(){}

(2)、方法监听注册方式:W3C标准推荐方式;addEventListener() 它是一个方法;IE9之前的IE不支持此方法,可使用attachEvent() 代替;特点:同一个元素同一个事件可以注册多个监听器(事件处理函数);按注册顺序依次执行;

addEventListener()

  • 事件监听方式
  • eventTarget.addEventListener(type,lister[,useCapture]) 方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数;
    (1)、type :事件类型字符串,如:click mouseover 注意这里不要带on
    (2)、listener 事件处理函数,事件发生时,会调用该监听函数;
    (3)、useCapture 可选参数,是一个布尔值,默认是false
//注意:事件监听注册事件 addEventListener 里面的事件类型是字符串,要加引号,而且不带 on
//同一个元素,同一个事件可以添加多个侦听器(事件处理程序)
btn.addEventListener('click',function(){})

attachEvent 注册事件(IE9以前的版本支持)

  • eventTarget.attachEvent(eventNameWithon,callback)
  • eventTarget.attachEvent(eventNameWithon,callback)方法将指定的监听器注册到eventTarget (目标对象)上,当该对象触发指定的事件时,指定的回调函数就会被执行;
  • 该方法接收两个参数:
    (1)、eventNameWithon :事件类型字符串,比如:onclick onmouseover 这里要带 on ;
    (2)、callback:事件处理函数,当目标触发事件时回调函数被调用;
btn.attachEvent('onclick',function(){})

注册事件兼容性解决方案(封装兼容性函数)

  • 兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器;
<!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>
</head>

<body>
    <script>
        function addEventListener(element, eventName, fn) {
            // 判断当前浏览器是否支持 addEventListener 方法
            if (element.addEventListener) {
                element.addEventListener(eventName, fn);//第三个参数 默认是false
            } else if (element.attachEvent) {
                element.attachEvent('on' + eventName, fn)
            } else {
                // 相当于 element.onclick = fn
                element['on' + eventName] = fn
            }
        }
    </script>
</body>

</html>

删除事件(解绑事件)

删除事件的方式:

(1)、传统注册方式

eventTarget.onclick = null
<body>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <script>
        var divs = document.querySelectorAll('div')
        divs[0].onclick = function () {
            alert(11)
            //传统方法删除事件
            divs[0].onclick = null
        }
    </script>
</body>

(2)、方法监听注册方式

  • 方法1:
eventTarget.removeEventListener(type,listener[,useCapture]);
<body>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <script>
        var divs = document.querySelectorAll('div')
        // removeEventListener 删除元素
        divs[1].addEventListener('click', fn) //里面的 fn 不需要加小括号调用
        function fn() {
            alert(22);
            divs[1].removeEventListener('click', fn)
        }
    </script>
</body>
  • 方法2:(谷歌浏览器不兼容)
eventTarget.detachEvent(eventNameWithOn,callback);
<div>1</div>
<div>2</div>
<div>3</div>	

var divs = document.querySelectorAll('div')
divs[2].attachEvent('onclick', fn1);
      function fn1() {
           alert(33)
           divs[2].detachEvent('onclick', fn1)
       }
删除事件兼容性解决方案
function removeEventListener(element,eventName,fn){
	//判断当前浏览器是否支持 removeEventListener 方法
	if(element.removeEventListener){
		element.removeEventListener(eventName,fn);//第三个参数,默认是false
	}else if(element.detachEvent){
		element.detachEvent('on'+eventName,fn);
	}else{
		element['on'+eventName]=null;
	}
}

DOM事件流

  • 事件流描述的是从页面中接收事件的顺序;
  • 事件发生时会在元素节点之间按照待定的顺序传播,这个传播过程DOM事件流
    JavaScript教程(一)_第48张图片
    JavaScript教程(一)_第49张图片
  • 注意:
    (1)、JS代码中只能执行捕获或者冒泡其中的一个阶段;
    (2)、onclickattachEvent 只能得到冒泡阶段;
    (3)、addEventListener(type,listener[,useCapture]) 第三个参数如果是 true ,表示在事件捕获阶段调用事件处理程序;如果是false (不写默认是false),表示在事件冒泡阶段调用事件处理程序;
    (4)、实际开发中我们很少使用事件捕获,更关注事件冒泡;
    (5)、有些事件是没有冒泡的,比如:onblur onfocus onmouseenter onmouseleave
<!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>DOM事件流</title>
    <style>
        .father {
            width: 200px;
            height: 200px;
            background-color: aqua;
        }

        .son {
            width: 100px;
            height: 100px;
            background-color: blueviolet;
            margin: 0 auto;
        }
    </style>
</head>

<body>
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        /*
            DOM事件流 三个阶段:
            1、JS代码中只能执行捕获或者冒泡其中的一个阶段;
            2、onclick 和 attachEvent(ie)只能得到冒泡阶段;
            3、捕获阶段 如果 addEventListener 第三个参数是 true 那么则处于捕获阶段;document->html->body->father->son
        */
        // var son = document.querySelector('.son')
        // son.addEventListener('click', function () {
        //     alert('son')
        // }, true)

        // var father = document.querySelector('.father')
        // father.addEventListener('click', function () {
        //     alert('father')
        // }, true)

        // 4、冒泡阶段 如果 addEventListener 第三个参数是 false 或者省略, 那么则处于冒泡阶段;son->father->body->html->document
        var son = document.querySelector('.son')
        son.addEventListener('click', function () {
            alert('son')
        }, false)

        var father = document.querySelector('.father')
        father.addEventListener('click', function () {
            alert('father')
        }, false)
        document.addEventListener('click', function () {
            alert('document')
        })
    </script>
</body>

</html>

事件对象

eventTarget.onclick=function(event){} 
eventTarget.addEventListener('click',function(event){})
  • 这个event 就是事件对象,我们还喜欢写成 e 或者 evt
  • 这个event是个形参,系统帮我们设定为事件对象,不需要传递实参过去;
  • 当我们注册事件时,event对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数);
  • 官方解释:event 对象代表事件的状态,比如键盘按钮的状态、鼠标的位置、鼠标按钮的状态;
  • 简单解释:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法;比如:谁绑定了这个事件;鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置;键盘触发事件的话,会得到键盘的相关信息,如按了哪个键;
  • 在IE6~8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取查找;解决:
    e=e || window.event
<!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>
</head>

<body>
    <div>123</div>
    <script>
        var div = document.querySelector('div')
        div.onclick = function (event) {
            console.log(event);
        }
        div.addEventListener('click', function (event) {
            console.log(event);
        })
        /*
            1、event 就是一个事件对象,写到我们侦听函数的 小括号里面,当形参来看;
            2、事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数;
            3、事件对象是我们事件的一系列相关数据的集合,跟事件相关的;
            比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标;如果是键盘事件,里面就包含了键盘事件的信息,比如:判断用户按下了哪个键;
            4、这个事件对象我们可以自己命名,比如:event、evt、e;
            5、事件对象也有兼容性问题,ie678通过 window.event 获取;兼容性写法:e=e || window.event;
        */        
    </script>
</body>

</html>

事件对象的常见属性和方法

1、targetthis 区别

JavaScript教程(一)_第50张图片

  • (1)、e.target 返回的是触发事件的对象(元素);
<body>
    <div>123</div>
    <ul>
        <li>abc</li>
        <li>abc</li>
        <li>abc</li>
    </ul>
    <script>
        var div=document.querySelector('div')
        div.addEventListener('click',function(e){
            console.log(e.target); //
123
console.log(this); //
123
}) </script> </body>

注意this 返回的是绑定事件的对象(元素);

<body>
    <div>123</div>
    <ul>
        <li>abc</li>
        <li>abc</li>
        <li>abc</li>
    </ul>
    <script>
        var div = document.querySelector('div')
        div.addEventListener('click', function (e) {
            console.log(e.target); //
123
console.log(this); //
123
}) var ul = document.querySelector('ul') ul.addEventListener('click', function (e) { //我们给ul绑定了事件,那么 this 就指向 ul console.log(this);//
      // 注意:此处没有写第三个参数,所以默认是false(冒泡),li 没有绑定点击事件,点击的是 li ,li没找到事件就往上找,这是冒泡; console.log(e.currentTarget);// 了解:跟 this 有个非常相似的属性 currentTarget (IE678不兼容) console.log(e.target);//
    • }) /* 区别:e.target 点击了哪个元素,就返回哪个元素;this 哪个元素绑定了这个点击事件,那么就返回谁; */ // 考虑兼容性问题的写法 div.onclick = function (e) { e = e || window.event; var target = e.target || e.srcElement; console.log(target); } </script> </body>
2、e.type
<body>
    <div>123</div>
    <a href="http://www.baidu.com">百度</a>
    <form action="http://www.baidu.com">
        <input type="submit" value="提交" name="sub">
    </form>
    <script>
        // 常见事件对象的属性和方法
        // 返回事件类型
        var div = document.querySelector('div')
        div.addEventListener('click', fn);
        div.addEventListener('mouseover', fn)
        div.addEventListener('mouseout', fn)
        function fn(e) {
            console.log(e.type);
        }
    </script>
</body>
3、事件对象阻止默认行为
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
    <input type="submit" value="提交" name="sub">
</form>

// 阻止默认行为(事件):让链接不跳转,或者让提交按钮不提交;
var a=document.querySelector('a');
a.addEventListener('click',function(e){
   e.preventDefault();//DOM推荐的标准写法(低版本IE浏览器不支持)
})
// 传统的注册方式
a.click = function (e) {
    // 普通浏览器 e.preventDefault();---> 方法
    e.preventDefault()
    // 低版本浏览器 ie678 用 returnValue ---> 属性
    e.returnValue;
   /*
 我们可以利用 return false ,也能阻止默认行为,而且没有兼容性问题;
 特点:return后面的代码不执行了,而且只限于传统的注册方式;
	*/ 
   return false
}
4、阻止事件冒泡
  • 事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点;事件冒泡本身的特性,会带来的坏处,也会带来好处,需要我们灵活掌握;
  • 阻止事件冒泡:标准写法:利用事件对象里面的stopPropagation() 方法;
<body>
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        var son = document.querySelector('.son')
        son.addEventListener('click', function (e) {
            alert('son')
            e.stopPropagation(); //stop停止  propagation 传播 ;有兼容性问题
            e.cancelBubble=true;// 低版本IE浏览器
        }, false)

        var father = document.querySelector('.father')
        father.addEventListener('click', function () {
            alert('father')
        }, false)
        document.addEventListener('click', function () {
            alert('document')
        })

        if(e && e.stopPropagation){
            e.stopPropagation();
        }else{
            window.event.cancelBubble=true;
        }
    </script>
</body>
5、事件委托(代理、委派)
  • ul里面有多个li,点击每个li都会弹出对话框,以前需要给每个li注册事件,是非常辛苦的,而且访问DOM的次数越多,这就会延长整个页面的交互就绪时间;
  • 事件委托:也称为事件代理,在jQuery里面称为事件委派
  • 事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。以上案例:给ul注册点击事件,然后利用事件对象的target 来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器;
  • 事件委托的作用:我们只操作了一次DOM ,提高了程序的性能;
<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <script>
        var ul = document.querySelector('ul')
        ul.addEventListener('click', function fn(e) {
            // alert('被点击了')
            // e.target 可以得到我们点击的对象
            e.target.style.backgroundColor = 'pink'
        })
    </script>
</body>
6、常用的鼠标事件
  • event 对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象MouseEvent和键盘事件对象KeyboardEvent
    JavaScript教程(一)_第51张图片
  • 禁止鼠标右键菜单:contextmenu 主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单;
document.addEventListener('contextmenu',function(e){
	e.preventDefault();
})
  • 禁止鼠标选中:selectstart 开始选中;
document.addEventListener('selectstart',function(e){
	e.preventDefault();
})
<body>
    我是一段不愿意分享的文字
    <script>
        // contextmenu 可以禁用右键菜单
        document.addEventListener('contextmenu', function (e) {
            e.preventDefault();
        })

        // 禁止选中文字 selectstart
        document.addEventListener('selectstart', function (e) {
            e.preventDefault();
        })
    </script>
</body>
  • 获得鼠标在页面中的坐标:鼠标事件对象MouseEvent
    JavaScript教程(一)_第52张图片
<script>
        // 鼠标事件对象 MouseEvent
        document.addEventListener('click', function (e) {
            // 1、client 鼠标在可视区的x和y坐标
            console.log(e.clientX);
            console.log(e.clientY);

            // 2、page 鼠标在页面文档的x和y坐标
            console.log(e.pageX);
            console.log(e.pageY);

            // 3、screen 鼠标在电脑屏幕的x和y坐标
            console.log(e.screenX);
            console.log(e.screenY);
        })
    </script>
  • 案例:跟随鼠标的天使
<!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>
        img {
            position: absolute;
        }
    </style>
</head>

<body>
    <img src="./images/angel.gif" alt="">
    <script>
        /*
            1、鼠标不断的移动,使用鼠标移动事件:mousemove;
            2、在页面中移动,给 document 注册事件;
            3、图片要移动距离,而且不占位置,我们使用绝对定位即可;
            4、核心原理:每次鼠标移动,我们都会获得最新的鼠标坐标,把这个 x 和 y 坐标作为图片的 top 和 left 值就可以移动图片;
        */
        var pic = document.querySelector('img')
        document.addEventListener('mousemove', function (e) {
            // mousemove 只要我们鼠标移动1px,就会触发这个事件;
            var x = e.pageX;
            var y = e.pageY;
            console.log('x坐标是' + x, 'y坐标是' + y);
            // 注意:千万不要忘记给 left 和 top 添加 px 单位;
            // 减50和40是减去图片的长和宽的一半,从而使鼠标箭头的位置处于图片的中心;
            pic.style.left = x - 50 + 'px';
            pic.style.top = y - 40 + 'px';
        })
    </script>
</body>

</html>
7、常用的键盘事件

JavaScript教程(一)_第53张图片

  • 三个事件的执行顺序:keydown --> keypress --> keyup
  • 利用keyCode 判断用户按下哪个键;
  • 键盘事件对象中的keyCode属性可以得到相应键的ASCII值码;
    JavaScript教程(一)_第54张图片
<body>
    <script>
        // 键盘事件对象中的 keyCode 属性可以得到相应键的 ASCII 码值;
        // 1、我们的 keyup 和 keydown 事件不区分字母大小写;例如:a 和 A 得到的都是65;
        // 2、我们的 keypress 事件,区分字母大小写;例如:a 得到的都是 97 和 A 得到的都是 65;
        document.addEventListener('keyup', function (e) {
            console.log(e);
            console.log('up:' + e.keyCode);
            if (e.keyCode === 65) {
                alert('按下了a键')
            } else {
                alert('没有按下a键')
            }
        })

        document.addEventListener('keypress', function (e) {
            console.log(e);
            console.log('press:' + e.keyCode);
        })
    </script>
</body>
  • 案例:模拟京东按键输入内容
<body>
    <input type="text">
    <script>
        /*
            1、核心思路:检测用户是否按下了s键,如果按下s键,就把光标定位到搜索框里面;
            2、使用键盘事件对象里面的keyCode判断用户按下的是否是s键;
            3、搜索框获得焦点:使用js里面的 focus() 方法;
        */
        var search = document.querySelector('input')
        document.addEventListener('keyup', function (e) {//此处用keydowm会把s填入输入框
            console.log(e.keyCode);
            if (e.keyCode === 83) {
                search.focus();
            }
        })
    </script>
</body>
  • 案例:模拟京东快递单号查询
<!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>
        body,
        html {
            margin: 0;
            padding: 0;
        }

        .search {
            position: relative;
            width: 178px;
            margin: 100px;
        }

        .con {
            display: none;
            position: absolute;
            top: -40px;
            width: 171px;
            border: 1px solid rgba(0, 0, 0, .2);
            box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
            padding: 5px 0;
            font-size: 18px;
            line-height: 20px;
            color: #333;
        }

        .con::before {  /* 倒三角形 */
            content: '';
            width: 0;
            height: 0;
            position: absolute;
            top: 28px;
            left: 18px;
            border: 8px solid #000;
            border-style: solid dashed dashed;
            border-color: #fff transparent transparent;
        }
    </style>
</head>

<body>
    <!-- 
        案例分析:
         (1)、快递单号输入内容时,上面的大号字体盒子(con)显示(这里面的字号更大);
         (2)、表单检测用户输入:给表单添加键盘事件;
         (3)、同时把快递快递单号里面的值(value)获取过来赋值给con盒子(innerText)作为内容;
         注意:keydown 和 keypress 在文本框里的特点:他们两个事件触发的时候,文字还没有落入文本框中;keyup 事件触发的时候,文字已经落入文本框里面了;
     -->
    <div class="search">
        <div class="con">123</div>
        <input type="text" placeholder="请输入您的快递单号" class="jd">
    </div>
    <script>
        var con = document.querySelector('.con');
        var jd_input = document.querySelector('.jd');
        jd_input.addEventListener('keyup', function () {
            if (this.value === '') {
                con.style.display = 'none';
            } else {
                con.style.display = 'block';
                con.innerText = this.value;
            }
        })
       //当我们失去焦点,就隐藏这个con盒子
        jd_input.addEventListener('blur', function () {
            con.style.display = 'none'
        })
        //当我们获得焦点,就显示这个con盒子
        jd_input.addEventListener('focus', function () {
            if (this.value !== '') {
                con.style.display = 'block'
            }
        })        
    </script>
</body>

</html>

你可能感兴趣的:(javascript)