JavaScript基础

JavaScript

概况

起源

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

简史

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

ECMAScript是一个标准,而这个标准需要由各个厂商去实现。
• 不同的浏览器厂商对该标准会有不同的实现。

image-20211104220703897

实现

• 我们已经知道ECMAScript是JavaScript标准,所以一般情况下这两个词我们认为是一个意思。
• 但是实际上JavaScript的含义却要更大一些。
• 一个完整的JavaScript实现应该由以下三个部分构成:

image-20211104220808363

特点

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

解释型语言

  • JavaScript是一门解释型语言,所谓解释型语言不需要被编译为机器码再执行,而是直接执行。
  • 由于少了编译这一步骤,所以解释型语言开发起来尤为轻松,但是解释型语言运行较慢也是它的劣势。
  • 不过解释型语言中使用了JIT技术,使得运行速度得以改善。

类似于 C 和 Java 的语法结构

  • JavaScript的语法结构与C和Java很像,向for、if、while等语句和Java的基本上是一模一样的。
  • 所以有过C和Java基础的同学学习起来会轻松很多。
  • 不过JavaScript和与Java的关系也仅仅是看起来像而已。

动态语言

  • JavaScript是一门动态语言,所谓的动态语言可以暂时理解为在语言中的一切内容都是不确定的。比如一个变量,这一时刻是个整型,下一时刻可能会变成字符串了。当然这个问题我们以后再谈。
  • 不过在补充一句动态语言相比静态语言性能上要差一些,不过由于JavaScript中应用的JIT技术,所以JS可能是运行速度最快的动态语言了。

基于原型的面向对象

  • JavaScript是一门面向对象的语言。
  • Java也是一门面向对象的语言,但是与Java不同JavaScript是基于原型的面向对象。

编写位置

  • 我们目前学习的JS全都是客户端的JS,也就是说全都是需要在浏览器中运行的,所以我们我们的JS代码全都需要在网页中编写。
  • 我们的JS代码需要编写到script标签中。
  • 我们一般将script标签写到head中。(和style标签有点像)
  • 属性:
    • type:默认值text/javascript可以不写,不写也是这个值。
    • src:当需要引入一个外部的js文件时,使用该属性指向文件的地址。

例如:

<script type="text/javascript" src="">
	console.log("Hello World");
</script>

注意:

  • JavaScript是严格区分大小写的,也就是abc和Abc会被解析器认为是两个不同的东西。
  • 所以在编写上边的HelloWorld时,一定要注意区分大小写。

注释

  • 注释中的内容不会被解析器解析执行,但是会在源码中显示,我们一般会使用注释对程序中的内容进行解释。
  • JS中的注释和Java的的一致,分为两种:
    • 单行注释//注释内容
    • 多行注释/*注释内容*/

标识符

标识符定义

  • 所谓标识符,就是指变量、函数、属性的名字,或函数的参数

  • 标识符可以是按照下列格式规则组合起来的一或多个字符:

    • 第一个字符必须是一个字母、下划线( _ )或一个美元符号( $ )
    • 其他字符可以是字母、下划线、美元符号或数字。
  • 按照惯例,ECMAScript 标识符采用驼峰命名法

  • 但是要注意的是JavaScript中的标识符不能是关键字和保留字

关键字和保留字符

关键字

image-20211104222638606

保留字符

image-20211104222659357

其他不建议使用的标识符

image-20211104222725661

变量

  • 变量的作用是给某一个值或对象标注名称。
  • 比如我们的程序中有一个值123,这个值我们是需要反复使用的,这个时候我们最好将123这个值赋值给一个变量,然后通过变量去使用123这个值
  • 变量的声明:
    • 使用var关键字声明一个变量。
      • var a;
    • 变量的赋值:
      • 例:a=123;
    • 声明和赋值同时进行: var a = 123;

数据类型

六种数据类型

  • 数据类型决定了一个数据的特征,比如:123和”123”,直观上看这两个数据都是123,但实际上前者是一个数字,而后者是一个字符串。
  • 对于不同的数据类型我们在进行操作时会有很大的不同。
  • JavaScript中一共有6种基本数据类型:
    • 字符串型(String)
    • 数值型(Number)
    • 布尔型(Boolean)
    • null型(Null)
    • undefined型(Undefined)
    • 这5种之外的类型都称为Object,其中Object为引用数据类型。

String

  • String用于表示一个字符序列,即字符串。

  • 字符串需要使用 ’或“ 括起来。

  • 转义字符:

    image-20211104234422186

  • 将其他数值转换为字符串有三种方式:toString()String()拼串

  • String字符串格式

    • 在JS中字符串需要使用引号引起来
      
    • 使用双引号或单引号都可以,但是不要混着用
      
    • 引号不能嵌套,双引号不能放双引号,单引号不能放单引号
      

Number

  • Number 类型用来表示整数和浮点数,最常用的功能就是用来表示10进制的整数和浮点数。
  • Number表示的数字大小是有限的,范围是:
    • ± 1.7976931348623157e+308
    • 如果超过了这个范围,则会返回± Infinity。
  • NaN,即非数值(Not a Number)是一个特殊的数值(属于一种特殊的Number类型),JS中当对数值进行计算时没有结果返回,则返回NaN,例如typeof "abc"*"efg"--->NaN 。使用typeof检查一个NaN也会返回number,typeof NaN -->number

Boolean(布尔型)

  • 布尔型也被称为逻辑值类型或者真假值类型。

  • 布尔型只能够取真(true)和假(false)两种数值。除此以外,其他的值都不被支持。

  • 其他的数据类型也可以通过Boolean()函数转换为布尔类型。

  • 转换规则:

    image-20211104235551594

Undefined

  • Undefined 类型只有一个值,即特殊的 undefined 。

  • 在使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined。例如:

    var b ;
    console.log(typeof b); //undefined
    
  • 需要注意的是typeof对没有初始化和没有声明的变量都会返回undefined。

Null

  • Null 类型的值只有一个,这个特殊的值是null 。

  • 从语义上看null表示的是一个空的对象。所以使用typeof检查null会返回一个Object。

    var a = null;
    console.log(typeof a); //Object
    
  • undefined值实际上是由null值衍生出来的,所以如果比较undefined和null是否相等,会返回true;

typeof运算符

  • 使用typeof操作符可以用来检查一个变量的数据类型。
  • 使用方式:typeof 数据,例如 typeof 123。
  • 返回结果:
    • typeof 数值 返回 number
    • typeof 字符串 返回 string
    • typeof 布尔型 返回 boolean
    • typeof undefined 返回 undefined
    • typeof null 返回 object
/*
* 在JS中所有的数值都是Number类型,
* 	包括整数和浮点数(小数)
* 
* JS中可以表示的数字的最大值
* 	Number.MAX_VALUE
* 		1.7976931348623157e+308
* 
* 	Number.MIN_VALUE 大于0的最小值
* 		5e-324
* 
*  如果使用Number表示的数字超过了最大值,则会返回一个
* 		Infinity 表示正无穷
* 		-Infinity 表示负无穷
* 		使用typeof检查Infinity也会返回number
*  NaN 是一个特殊的数字,表示Not A Number
* 		使用typeof检查一个NaN也会返回number
*/

/*
可以使用一个运算符 typeof来检查一个变量的类型
语法:typeof 变量	
检查字符串时,会返回string
检查数值时,会返回number
* */


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


/*
* 如果使用JS进行浮点运算,可能得到一个不精确的结果
* 	所以千万不要使用JS进行对精确度要求比较高的运算	
*/

强制类型转换

强制类型转化成String

定义:指将一个数据类型强制转换为其他的数据类型,类型转换主要指,将其他的数据类型,转换为StringNumberBoolean

方式一:调用被转换数据类型的toString()方法

var a = 12;
a.toString();
console.log(a);  //a的值不变,还是Number类型的12

 //该方法不会影响到原变量,它会将转换的结果返回
a = a.toString();
console.log(a); //此时的a为String类型的12

//但是注意:null和undefined这两个值没有toString()方法,如果调用他们的方法,会报错
a = null;
a = a.toString(); //报错

 a = undefined;
 console.log(a);  //报错

方式二: 调用String()函数,并将被转换的数据作为参数传递给函数

  • 对于Number和Boolean实际上就是调用的toString()方法
  • 对于null和undefined,就不会调用toString()方法,它会将 null 直接转换为 "null",将 undefined 直接转换为 "undefined"
var a = 123;
a = 123;
//调用String()函数,来将a转换为字符串
a = String(a);
console.log(typeof a);//string

a = null;
console.log(typeof a);//Object
a = String(a);
console.log(typeof a);//string

a = undefined;
console.log(typeof a);//undefined
a = String(a);
console.log(typeof a);//string

方式三(隐式的类型转换):

为任意的数据类型 +""
例子:

var a = true;  
a = a + ""; 

强制类型转换成Number

转换方式一:

使用Number()函数

  • 字符串 --> 数字
    • 1.如果是纯数字的字符串,则直接将其转换为数字
    • 2.如果字符串中有非数字的内容,则转换为NaN
    • 3.如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
  • 布尔 --> 数字
    • true 转成 1
    • false 转成 0
  • null --> 数字 0
  • undefined --> 数字 NaN

转换方式二:

这种方式专门用来对付字符串

  • parseInt() 把一个字符串转换为一个整数
  • parseFloat() 把一个字符串转换为一个浮点数

如果对非String使用parseInt()或parseFloat(),它会先将其转换为String然后在操作 parseInt()

a = true;
a = parseInt(a);
console.log(typeof a)  //Number
console.log(a)   //"true"字符串  ---》 Number  结果:NaN

可以将一个字符串中的有效的整数位提取出来,并转换为Number
例子:

var a = "123.456px";  
a = parseInt(a); //123  

方式三(隐式的类型转换):

使用一元的+来进行隐式的类型转换
例子:

var a = "123";  
a = +a;  

转换为布尔值

方式一(强制类型转换):

使用Boolean()函数
例子:

var s = "false";  
s = Boolean(s); //true 

转换的情况

  • 字符串 > 布尔
    除了空串其余全是true

    a = "";  //空串
    a = Boolean(a);
    console.log(a) //false
    
    a = "    "; //这不是空串,这是包含空格的字符串
    a = Boolean(a);
    console.log(a) //true
    
  • 数值 > 布尔
    除了0和NaN其余的全是true

    var a = 123; //true
    a = -123; //true
    a = 0; //false
    a = Infinity; //true
    a = NaN; //false
    
    //调用Boolean()函数来将a转换为布尔值
    a = Boolean(a);
    
  • null、undefined > 布尔
    都是false

    a = null; //false
    a = Boolean(a);
    a = undefined; //false
    a = Boolean(a);
    
  • 对象 > 布尔
    都是true

方式二(隐式类型转换):
为任意的数据类型做两次非运算,即可将其转换为布尔值
例子:

var a = "hello";  
a = !!a; //true 

练习

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">


        var a = "123";

        //调用Number()函数来将a转换为Number类型
        a = Number(a);
        console.log(typeof a)  //number

        a = false;
        a = Number(a); 
        console.log(a) //0

        a = null;
        a = Number(a); 
        console.log(a)  //0

        a = undefined;
        a = Number(a);
        console.log(a) //NaN

        a = "123567a567px";
        //调用parseInt()函数将a转换为Number
        /*
         * parseInt()可以将一个字符串中的有效的整数内容去出来,
         * 	然后转换为Number
         */
        a = parseInt(a);

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

        /*
         * 如果对非String使用parseInt()或parseFloat()
         * 	它会先将其转换为String然后在操作
         */
        a = true;
        a = parseInt(a);
        console.log(typeof a)  //Number
        console.log(a)   //"true"字符串  ---》 Number  结果:NaN

        // 浮点数-- - 》parseInt(浮点数) -- - 》保留整数( 没有四舍五入)
        a = 198.83;
        a = parseInt(a);

        console.log(typeof a);
        console.log(a);  //198
    </script>
</head>

<body>
</body>

</html>

其他进制的数字

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

    //十六进制
    a = 0x10;
    console.log(a) //16
    
  • 如果需要表示8进制的数字,则需要以0开头

    a = 070;
    a = parseInt(a);
    console.log(a); //八进制:56     十进制:70
    
    //向"070"这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析
     a = "070";
    console.log(a)  //IE8 输出56  Chrome输出70
    
  • 如果要要表示2进制的数字,则需要以0b开头,但是不是所有的浏览器都支持

    //二进制数字
    a = 0b10;
    console.log(a) //2
    
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			
			var a = 123;
			
			/*
			 * 在js中,如果需要表示16进制的数字,则需要以0x开头
			 * 			如果需要表示8进制的数字,则需要以0开头
			 * 			如果要要表示2进制的数字,则需要以0b开头
			 * 				但是不是所有的浏览器都支持
			 * 	
			 */
			
			//十六进制
			a = 0x10;
			a = 0xff;
			a = 0xCafe;
			
			//八进制数字
			a = 070;
			
			//二进制数字
			//a = 0b10;
			
			//向"070"这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析
			a = "070";
			
			//可以在parseInt()中传递一个第二个参数,来指定数字的进制
			a = parseInt(a,10);
			
			console.log(typeof a);
			console.log(a);
			
		</script>
	</head>
	<body>
	</body>
</html>

运算符

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

typeof运算符

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

var a = 123;

var result = typeof a; //从java知识方面来理解:String result = “Number”

console.log(typeof result); //string
console.log(result); //Number

算数运算符

+ 对两个值进行加法运算并返回结果

- 对两个值进行减法运算并返回结果

* 对两个值进行乘法运算并返回结果
* / 对两个值进行除法运算并返回结果
* % 对两个值进行取余运算并返回结果

对非Number类型的值进行运算时,都会先转换为Number然后在做运算。

特殊1:任何值和NaN做运算都得NaN

特殊2:任何的值和字符串做加法运算,都会先转换为字符串,然后再和字符串做拼串的操作

练习:

result = a + 1;

result = 456 + 789;

result = true + 1; //2

result = true + false; //1

result = 2 + null; //2

result = 2 + NaN; //NaN

result = 123 + "1"; //1231

result = true + "hello"; //truehello

//任何值和字符串相加都会转换为字符串,并做拼串操作
/*
* 我们可以利用这一特点,来将一个任意的数据类型转换为String
* 	我们只需要为任意的数据类型 + 一个 "" 即可将其转换为String
* 	这是一种隐式的类型转换,由浏览器自动完成,实际上它也是调用String()函数
*/
var c = 123;

c = c + "";  //转成字符串  123

result = 1 + 2 + "3"; //运算从左到右,33

result = "1" + 2 + 3; //123

result = 100 - 5;

result = 100 - true;

result = 100 - "1"; //字符串p拼接只针对加法运算,99

result = 2 * 2;

result = 2 * "8";

result = 2 * undefined; //undefined 转Number类型-->NaN,即2*NaN---》NaN

result = 2 * null; //null转Number类型---》0,即2*0--》0

一元运算符

正负号

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

  • 正号+
    • 正号+不会对数字产生任何影响
    • 对于非Number类型的值,它会将先转换为Number,然后在运算,可以对一个其他的数据类型使用+,来将其转换为number,它的原理和Number()函数一样
  • 负号
    • 负号可以对数字进行负号的取反
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        /*
         * 一元运算符,只需要一个操作数
         * 	+ 正号
         * 		- 正号不会对数字产生任何影响
         * 	- 负号
         * 		- 负号可以对数字进行负号的取反
         * 
         * 	- 对于非Number类型的值,
         * 		它会将先转换为Number,然后在运算
         * 		可以对一个其他的数据类型使用+,来将其转换为number
         * 		它的原理和Number()函数一样
         */

        var a = 123;
        a = -a;
        console.log(a); //-123

        a = +a;
        console.log(a); //-123

        a = true;
        a = +a;
        console.log("a = " + a); //1
        console.log(typeof a); //Number

        a = "18";
        a = +a;
        console.log("a = " + a); //18
        console.log(typeof a); //Number

        var result = 1 + +"2" + 3; //6
        console.log("result = " + result);
    </script>
</head>

<body>
</body>

</html>

自增

自增可以使变量在原值的基础上自增1
自增使用 ++
自增可以使用 前++(++a)后++(a++)
无论是++a 还是 a++都会立即使原变量自增1(这句话我个人不是很赞同,我的理解:++a,先自增后运算;a++:先运算后自增)
不同的是++a和a++的值是不同的,
++a的值是变量的新值(自增后的值)
a++的值是变量的原值(自增前的值)

自减

自减可以使变量在原值的基础上自减1
自减使用
自减可以使用 前(a)后(a)
无论是a 还是 a都会立即使原变量自减1(这句话我个人不是很赞同,我的理解:--a,先自减后运算;a++:先运算后自减)
不同的是a和a的值是不同的,
a的值是变量的新值(自减后的值)
a的值是变量的原值(自减前的值)

var num = 10;
console.log(--num); //9

var a = 1;

//使a自增1
//a++;
//++a;

console.log(a++);  //1
console.log("++a = " + ++a); //3

var c = 10;
//第一次c++,是在10的基础上自增
console.log(c++); //10
//第二次c++,是在11的基础上自增
c++;
console.log(c);   //12

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

逻辑运算符

!

非运算符可以应用于任意值,无论值是什么类型,这个运算符都会返回一个布尔值。

非运算可以对一个布尔值进行取反,true变false false边true

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

如果对非布尔值进行运算,则会将其转换为布尔值,然后再取反,所以我们可以利用该特点,来将一个其他的数据类型转换为布尔值

可以为一个任意数据类型取两次反,来将其转换为布尔值,原理和Boolean()函数一样

var flag = flase;
flag = !flag;
console.log(flag);//true

var a = "abc";
a = !!a;
console.log(a);//true
console.log(typeof a) //boolean

&&

&&可以对符号两侧的值进行与运算
只有两端的值都为true时,才会返回true。只要有一个false就会返回false。
"与"是一个短路的与,如果第一个值是false,则不再检查第二个值

对布尔值做运算时,如果两个值都为true则返回true,否则返回false

对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值
规则:
1.如果第一个值为false,则返回第一个值
2.如果第一个值为true,则返回第二个值

||

||可以对符号两侧的值进行或运算
只有两端都是false时,才会返回false。只要有一个true,就会返回true。
或是一个短路的或,如果第一个值是true,则不再检查第二个值

对布尔值进行运算时,如果两个值都为false则返回false,否则返回true。

对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值
规则:
1.如果第一个值为true,则返回第一个值
2.如果第一个值为false,则返回第二个值

练习:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>

    <script type="text/javascript">
        /*
         * && || 非布尔值的情况
         * 	- 对于非布尔值进行与或运算时,
         * 		会先将其转换为布尔值,然后再运算,并且返回原值
         * 	- 与运算:
         * 		- 如果第一个值为true,则必然返回第二个值
         * 		- 如果第一个值为false,则直接返回第一个值
         * 
         * 	- 或运算
         * 		- 如果第一个值为true,则直接返回第一个值
         * 		- 如果第一个值为false,则返回第二个值
         * 
         */

        //true && true
        //与运算:如果两个值都为true,则返回后边的
        var result = 5 && 6;


        //与运算:如果两个值中有false,则返回靠前的false
        //false && true
        result = 0 && 2;   //0
        result = 2 && 0;    //0
        //false && false
        result = NaN && 0;  //NaN   NaN转Boolean--->false
        result = 0 && NaN;  //0


        //true || true
        //如果第一个值为true,则直接返回第一个值
        result = 2 || 1;
        result = 2 || NaN;
        result = 2 || 0;

        //如果第一个值为false,则直接返回第二个值
        result = NaN || 1;
        result = NaN || 0;

        result = "" || "hello";

        result = -1 || "你好";


        console.log("result = " + result);
    </script>

</head>

<body>
</body>

</html>

赋值运算符

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

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 

关系运算符

关系运算符用来比较两个值之间的大小关系的

=
<
<=
关系运算符的规则和数学中一致,用来比较两个值之间的关系,
如果关系成立则返回true,关系不成立则返回false。
如果比较的两个值,其中有个值是是非数值(String、boolean、undefined),会将其转换为Number然后再比较
如果比较的两个值都是字符串,此时会比较字符串的Unicode编码,而不会转换为Number。

注意:

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

两边都是字符串,比较的是Unicode码,比较字符编码时是一位一位进行比较

​ 例如: "abc" 和 “def" 比较,首先是”a"和“d"比较

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        /*
         * 通过关系运算符可以比较两个值之间的大小关系,
         * 	如果关系成立它会返回true,如果关系不成立则返回false
         * 
         * > 大于号
         * 	- 判断符号左侧的值是否大于右侧的值
         * 	- 如果关系成立,返回true,如果关系不成立则返回false
         * 
         * >= 大于等于
         * 	- 判断符号左侧的值是否大于或等于右侧的值
         * 
         * < 小于号
         * <= 小于等于
         * 
         * 非数值的情况
         * 	- 对于非数值进行比较时,会将其转换为数字然后在比较
         * 	- 如果符号两侧的值都是字符串时,不会将其转换为数字进行比较
         * 		而会分别比较字符串中字符的Unicode编码
         */

        var result = 5 > 10; //false
        result = 5 > 4; //true

 
        //console.log(1 > true); //Boolean类型的 true转number:1 	false
        //console.log(1 >= true); //true
        //console.log(1 > "0"); //String类型的"0"转Number:0			true
        //console.log(10 > null); //null类型转Number:0				true
        //任何值和NaN做任何比较都是false
        //console.log(10 <= "hello"); //String类型的"hello"转Number:NaN		false
        //console.log(true > false); //true

        //console.log("1" < "5"); //true
        //console.log("11" < "5"); //两边都是字符串,比较的是Unicode码,比较字符编码时是一位一位进行比较,经过查Unicode表,1的Unicode码小于5的Unicode码,返回true

        //比较两个字符串时,比较的是字符串的字符编码
        //console.log("a" < "b");//true
        //比较字符编码时是一位一位进行比较
        //如果两位一样,则比较下一位,所以借用它来对英文进行排序
        //console.log("abc" < "bcd");//true
        //比较中文时没有意义,只是单纯地比较大小
        //console.log("戒" > "我"); //true

        //如果比较的两个字符串型的数字,可能会得到不可预期的结果
        //注意:在比较两个字符串型的数字时,一定一定一定要转型
        console.log("11123123123123123123" < +"5"); //true
    </script>
</head>

<body>
</body>

</html>

编码

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        /*
         * 在字符串中使用转义字符输入Unicode编码
         * 	格式:\u四位编码
         */
        console.log("\u2620");
    </script>
</head>

<body>
    <!--在网页中使用Unicode编码
			格式:&#编码; 这里的编码需要的是10进制
		-->
    <h1 style="font-size: 200px;">&#9760;</h1>
    <h1 style="font-size: 200px;">&#9856;</h1>

</body>

</html>

相等运算符

、!=、=、!==

相等,判断左右两个值是否相等,如果相等返回true,如果不等返回false
相等会自动对两个值进行类型转换,如果对不同的类型进行比较,会将其转换为相同的类型然后再比较(一般都会转换为Number类型再比较,如果俩边的类型一样就不需要转换为Number类型,直接判断即可),转换后相等它也会返回true,但是,【null、undefined、NaN】做相等运算符(指 ==)操作时,并没有自动转型;但是如果做关系运算符(指 >= <= > <)操作时,null,undefined会被Number()强制转换成数字类型

console.log(null == 0); //相等运算符操作,false
console.log(null >= 0 ) //关系运算符操作,null自动转型为number类型,null-->0,结果为true

!=
不等,判断左右两个值是否不等,如果不等则返回true,如果相等则返回false
不等也会做自动的类型转换。

===
全等,判断左右两个值是否全等,它和相等类似,只不过它不会进行自动的类型转换,
如果两个值的类型不同,则直接返回false,如果二者类型相同,再比较二者的值

console.log("55" == 55) //true
console.log("55" === 55) //false

!==
不全等,和不等类似,但是它不会进行自动的类型转换,如果两个值的类型不同,它会直接返回true

特殊的值:
null和undefined
由于undefined衍生自null,所以null == undefined 会返回true,这个也比较特殊

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

但是 null === undefined 会返回false。

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

NaN
NaN不与任何值相等,包括它自身

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

判断一个值是否是NaN
使用isNaN()函数

var b = NaN;
console.log(isNaN(b)); //true

练习

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        /*
         * 相等运算符用来比较两个值是否相等,
         * 	如果相等会返回true,否则返回false
         * 
         * 使用 == 来做相等运算
         * 	- 当使用==来比较两个值时,如果值的类型不同,
         * 		则会自动进行类型转换,将其转换为相同的类型
         * 		然后在比较
         * 不相等
         * 	 不相等用来判断两个值是否不相等,如果不相等返回true,否则返回false
         * 	- 使用 != 来做不相等运算
         * 	- 不相等也会对变量进行自动的类型转换,如果转换后相等它也会返回false
         * 
         * 		
         *  ===
         * 		全等
         * 		- 用来判断两个值是否全等,它和相等类似,不同的是它不会做自动的类型转换
         * 			如果两个值的类型不同,直接返回false
         * 	!==
         * 		不全等
         * 		- 用来判断两个值是否不全等,和不等类似,不同的是它不会做自动的类型转换
         * 			如果两个值的类型不同,直接返回true
         */

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

        var a = 10;

        //console.log(a == 4); //false

        console.log("1" == 1); //字符串自动转化为Number类型 "1"--->1        结果为 true

        console.log(true == "1"); //boolean类型转Number类型:true-->1       字符串转Number:"1"-->1   结果为true

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

        /*
         * undefined 衍生自 null
         * 	所以这两个值做相等判断时,会返回true
         */
        console.log(undefined == null);

        /*
         * 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(10 != 10); //false
        console.log("abcd" != "abcd"); //当俩边的类型都相同时就不再转Number类型了,结果为false
        //console.log("1" != 1);//false

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

        console.log(1 !== "1"); //true
    </script>
</head>

<body>
</body>

</html>

条件运算符

条件运算符也叫三元运算符

语法:

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

  • 执行的流程:

    • 条件运算符在执行时,首先对条件表达式进行求值,

    • 如果该值为true,则执行语句1,并返回执行结果

    • 如果该值为false,则执行语句2,并返回执行结果

    • 如果条件的表达式的求值结果是一个非布尔值,会将其转换为布尔值然后在运算

      "hello"?alert("语句1"):alert("语句2"); //"hello"-->true,接着执行语句1
      

优先级:
和数学中一样,JS中的运算符也是具有优先级的,
比如 先乘除 后加减 先与 后或
具体的优先级可以参考优先级的表格,在表格中越靠上的优先级越高,

image-20211107001901171
优先级越高的越优先计算,优先级相同的,从左往右计算。
优先级不需要记忆,如果越到拿不准的,使用()来改变优先级

逗号

  • 使用逗号可以在一条语句中执行多次操作。
  • 比如:var num1=1, num2=2, num3=3;
  • 使用逗号运算符分隔的语句会从左到右顺序依次执行。

代码块

  • 代码块是在大括号 {} 中所写的语句,以此将多条语句的集合视为一条语句来使用。
    例如:
{
var a = 123;
a++;
alert(a);
}
  • 我们一般使用代码块将需要一起执行的语句进行分组,需要注意的是,代码块结尾不需要加分号。
  • JS中的代码块,只具有分组的的作用,没有其他的用途,代码块中的内容,在外部是完全可见的
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        /*
         * 我们的程序是由一条一条语句构成的
         * 	语句是按照自上向下的顺序一条一条执行的
         * 	在JS中可以使用{}来为语句进行分组,
         * 		同一个{}中的语句我们称为是一组语句,
         * 		它们要么都执行,要么都不执行,
         * 		一个{}中的语句我们也称为叫一个代码块
         * 		在代码块的后边就不用再编写;了
         * 
         * 	JS中的代码块,只具有分组的的作用,没有其他的用途,代码块中的内容,在外部是完全可见的
         */
        {
            var a = 10;
            alert("hello");
            console.log("你好");
            document.write("语句");
        }
        console.log("a = " + a);
    </script>
</head>

<body>
</body>

</html>

流程控制语句

程序都是自上向下的顺序执行的,
通过流程控制语句可以改变程序执行的顺序,或者反复的执行某一段的程序。

语句的分类:

1.条件判断语句

2.条件分支语句

3.循环语句

条件判断语句

使用条件判断语句可以在执行某个语句之前进行判断,如果条件成立才会执行语句,条件不成立则语句不执行。

语法一

if(条件表达式){  
 	语句...  
 }  
    //if语句在执行时,会先对条件表达式进行求值判断,
   // 如果条件表达式的值为true,则执行if后的语句,
   // 如果条件表达式的值为false,则不会执行if后的语句。
    //if语句只能控制紧随其后的那个语句,
     //   如果希望if语句可以控制多条语句,
    //可以将这些语句统一放到代码块中 
    //if语句后的代码块不是必须的,但是在开发中尽量写上代码块,即使if后只有一条语句 

语法二:

if...else...语句

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

如果该值为true,则执行if后的语句;

如果该值为false,则执行else后的语句

if(条件表达式){  
	语句...  
}else{  
	语句...  
} 

语法三:

if...else if...else

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

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

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

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

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

if(条件表达式){  
	语句...  
}else if(条件表达式){  
	语句...  
}else if(条件表达式){  
	语句...  
}else if(条件表达式){  
	语句...  
}else{  
	语句...  
}	

prompt函数的使用

/*
* prompt()可以弹出一个提示框,该提示框中会带有一个文本框,
* 	用户可以在文本框中输入一段内容,该函数需要一个字符串作为参数,
* 	该字符串将会作为提示框的提示文字
* 
* 用户输入的内容将会作为函数的返回值返回,可以定义一个变量来接收该内容
*/
//score就是小明的期末成绩
 var score = prompt("请输入小明的期末成绩(0-100):");

image-20211107110955848

条件分支语句

switch语句

执行流程:
switch…case…语句在执行时,会依次将case后的表达式的值switch后的条件表达式的值进行全等比较

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

    • 当前case后的所有的代码都会执行,我们可以在case的后边跟着一个break关键字,这样可以确保只会执行当前case后的语句,而不会执行其他的case
  • 如果比较结果为false,则继续向下比较。

  • 如果所有的case判断结果都为false,则从default处开始执行代码。

switch(条件表达式){  
	case 表达式:  
		语句...  
		break;  
	case 表达式:  
		语句...  
		break;  
	case 表达式:  
		语句...  
		break;  
	default:  
		语句...  
		break;  
}  

循环语句

通过循环语句可以反复执行某些语句多次

while循环
  • 和if一样while中的条件表达式将会被转换为布尔类型,只要该值为真,则代码块将会一直重复执行。
  • 代码块每执行一次,条件表达式将会重新计算。

语法:

while(条件表达式){  
    语句...  
}  

执行流程:
while语句在执行时,会先对条件表达式进行求值判断,
如果判断结果为false,则终止循环
如果判断结果为true,则执行循环体
循环体执行完毕,继续对条件表达式进行求值判断,依此类推

do…while循环

语法:

do{  
语句...  
}while(条件表达式)  

执行流程
do…while在执行时,会先执行do后的循环体,然后在对条件表达式进行判断,
如果判断判断结果为false,则终止循环。
如果判断结果为true,则继续执行循环体,依此类推

while和do...while区别

while:先判断后执行
do…while: 先执行后判断
do…while可以确保循环体至少执行一次。

死循环:

//该循环不会停止,除非浏览器关闭,死循环在开发中慎用
//可以使用break,来终止循环
while(true){
...
break;
}
for循环

语法:

for(①初始化表达式 ; ②条件表达式 ; ④更新表达式/迭代条件){  
    ③(循环体)语句...  
}  

执行流程:
首先执行①初始化表达式,初始化一个变量,(注意:①初始化表达式只执行一次
然后对②条件表达式进行求值判断,如果为false则终止循环
如果判断结果为true,则执行③循环体
循环体执行完毕,执行④更新表达式,对变量进行更新。
更新表达式执行完毕重复②--》 ③--》④

死循环

while(true){  

}  

for(;;){  

}

break和continue

  • break 和 continue 语句用于在循环中精确地控制代码的执行。

  • 使用break语句会使程序立刻退出最近的循环,强制执行循环后边的语句。

  • break和continue语句只在循环和switch语句中使用,主要最外层有循环或者switch就可以

    var j = 2;
    if(j == 2){
        break;  //此处的break语句不会执行
    }
    
    for(var i=0 ; i<5 ; i++){
    	console.log(i);
    				
    	if(i == 2){
    		break;   //此处的break语句会执行,因为外层有for循环
    	}
    				
    }
    
  • 使用continue语句会使程序跳过当次循环,继续执行下一次循环,并不会结束整个循环。

    for(var i=0 ; i<5 ; i++){
    	if(i==2){
    		continue;   //当i = 2时,只会跳过本次循环,下次循环从i=3开始
    	}
    	console.log(i);
    }
    

label

• 使用 label 语句可以在代码中添加标签,以便将来使用。
• 语法:
– label: statement

• 例子:

start: for (var i=0; i < count; i++) {
alert(i);
}

outer:
for(var i=0 ; i<5 ; i++){
	console.log("@外层循环"+i)
	for(var j=0 ; j<5; j++){
		break outer;   //结束外层循环
		console.log("内层循环:"+j);
	}
}

• 这个例子中定义的 start 标签可以在将来由 break 或 continue 语句
引用。加标签的语句一般都要与 for 语句等循环语句配合使用

对象(Object)

JS数据类型

JS中数据类型分为基本数据类型和引用数据类型

  • 基本数据类型

    • String 字符串
    • Number
    • boolean
    • null
    • undefined
  • 引用数据类型

    • 对象(以后我们看到的值,只要不是上边的5种,全都是对象)

对象概念

  • 对象是一种复合数据类型,在对象中可以保存多个不同数据类型的属性,它将很多值聚合到一起,可以通过名字访问这些值。使用typeof检查一个对象时,会返回object
  • 对象也可以看做是属性的无序集合,每个属性都是一个名/值对。
  • 对象除了可以创建自有属性,还可以通过从一个名为原型的对象那里继承属性

对象的分类:

  1. 内建对象

    由ES标准中定义的对象,在任何的ES的实现中都可以使用;比如:Math String Number Boolean Function Object....

  2. 宿主对象

    由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象,比如 BOM DOM

  3. 自定义对象:由开发人员自己创建的对象

创建的对象

方式一:

/*
* 使用new关键字调用的函数,是构造函数constructor
* 构造函数是专门用来创建对象的函数
* 使用typeof检查一个对象时,会返回object
*/
var obj = new Object();  

方式二:

使用对象字面量来创建一个对象
var obj = {}; 



/*
* 使用对象字面量,可以在创建对象时,直接指定对象中的属性
* 语法:{属性名:属性值,属性名:属性值....}
* 	对象字面量的属性名可以加引号也可以不加,建议不加,
* 	如果要使用一些特殊的名字,则必须加引号
* 属性名和属性值是一组一组的名值对结构,
* 	名和值之间使用:连接,多个名值对之间使用,隔开
* 	如果一个属性之后没有其他的属性了,就不要写,
*/

var obj2 = {
	name:"猪八戒",
	age:13,
	gender:"男",
	test:{name:"沙僧"}
};

向对象中的属性增删改

为对象创建属性

语法:

//语法一:
对象.属性名 = 属性值;
//语法二:
对象[“属性名”] = 属性值; //这种方式能够使用特殊的属性名

对象的属性名没有任何要求,不需要遵守标识符的规范,但是在开发中,尽量按照标识符的要求去写。
属性值也可以任意的数据类型。

如果对象的属性名是一个特殊的属性名,不能采用.的方式来操作,需要使用另一种方式:

语法:对象["属性名"] = 属性值
obj."123" = 789; //控制台有可能报错,不建议用这种方式命名属性名

obj["123"] = 789;//特殊的属性名,需要用  对象["属性名"] = 属性值

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

使用[]这种形式去操作属性,更加的灵活,在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性

读取对象中的属性

语法:

//语法一
对象.属性名
//语法二
对象[“属性名”] //"属性名"可以是字符串常量,也可以是字符串变量

如果读取一个对象中没有的属性,它不会报错,而是返回一个undefined
console.log(obj.hello); //,因为obj没有hello属性,,结果为undefined

删除对象的属性

语法:

  • delete 对象.属性名

  • delete 对象["属性名"]

var obj = new Object();  //定义对象
obj.name = "zhangfei";  //创建属性

delete obj.name;  //删除属性

console.log(obj.name);  //obj对象的属性name已删除,结果为undefined

练习:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			
			var obj = new Object();

			/*
			 * 向对象中添加属性
			 * 属性名:
			 * 	- 对象的属性名不强制要求遵守标识符的规范
			 * 		什么乱七八糟的名字都可以使用
			 * 	- 但是我们使用是还是尽量按照标识符的规范去做
			 * 
			 */
			obj.name = "孙悟空";
			
			//obj.var = "hello";
			
			/*
			 * 如果要使用特殊的属性名,不能采用.的方式来操作
			 * 	需要使用另一种方式:
			 * 		语法:对象["属性名"] = 属性值
			 * 	读取时也需要采用这种方式
			 * 
			 * 使用[]这种形式去操作属性,更加的灵活,
			 * 	在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性
			 * 
			 */
			obj["123"] = 789;
			obj["nihao"] = "你好";
			var n = "nihao";
			//console.log(obj["123"]);
			
			/*
			 * 属性值
			 * 	JS对象的属性值,可以是任意的数据类型
			 * 		甚至也可以是一个对象
			 */
			
			obj.test = true;
			obj.test = null;
			obj.test = undefined;
			
			//创建一个对象
			var obj2 = new Object();
			obj2.name = "猪八戒";
			
			//将obj2设置为obj的属性
			obj.test = obj2;
			
			//console.log(obj.test.name);
			
			/*
			 * in 运算符
			 * 	- 通过该运算符可以检查一个对象中是否含有指定的属性
			 * 		如果有则返回true,没有则返回false
			 *  - 语法:
			 * 		"属性名" in 对象
			 */
			//console.log(obj.test2);
			
			//检查obj中是否含有test2属性
			//console.log("test2" in obj);
			//console.log("test" in obj);
			console.log("name" in obj);
			
		</script>
	</head>
	<body>
	</body>
</html>

从以上的练习学到的知识:
in 运算符:循环遍历对象自身的和继承的可枚举属性(不含Symbol属性).

- 通过该运算符可以检查一个对象中是否含有指定的属性
	如果有则返回true,没有则返回false
- 语法:
	"属性名" in 对象

js对象属性的特性

  • JS对象的属性值,可以是任意的数据类型,甚至也可以是一个对象
var obj = new Object();
var obj2 = new Object();
obj2.name = "猪八戒";
obj.test = obj2;   //obj的test属性是一个对象
console.log(obj.test.name);  //猪八戒

基本数据类型和引用数据类型的内存结构

基本数据类型的数据,变量是直接保存的它的值。
变量与变量之间是互相独立的,修改一个变量不会影响其他的变量。

image-20211108220540854

引用数据类型的数据,变量是保存对象的引用(内存地址)。
如果多个变量指向的是同一个对象,此时修改一个变量的属性,会影响其他的变量。

image-20211108220853464

image-20211108222001428

比较两个变量时,对于基本数据类型,比较的就是值,
对于引用数据类型比较的是地址,地址相同才相同,如果两个对象是一摸一样的,但是地址不同,它也会返回false

image-20211108221030654

image-20211108221501654

枚举对象中的属性

语法:

for(var 变量 in 对象){
    
}

练习

var obj = {
	name: "孙悟空",
	age: 18,
	gender: "男",
	address: "花果山"
};
for (var n in obj) {
	console.log("属性名:" + n); //name age  gender  address
	console.log("属性值:" + obj[n]); //"孙悟空" "18" "男" "花果山"
}

函数(Function)

函数也是一个对象,也具有普通对象的功能(能有属性)
函数中可以封装一些代码,在需要的时候可以去调用函数来执行这些代码
使用typeof检查一个函数时会返回function

创建函数的三种方式:①构造函数、②函数声明、③函数表达式

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

构造函数

创建一个函数对象,用typeof检查:

var fun = new Function();
console.log(typeof fun);   //Function

//我们在实际开发中很少使用构造函数来创建一个函数对象
//创建一个函数对象
//可以将要封装的代码以字符串的形式传递给构造函数
var fun = new Function("console.log('Hello 这是我的第一个函数');");

//封装到函数中的代码不会立即执行
//函数中的代码会在函数调用的时候执行
//调用函数 语法:函数对象()
//当调用函数时,函数中封装的代码会按照顺序执行
fun();

函数声明

 function 函数名([形参1,形参2...形参N]){  
语句...  
}; 
    
//函数调用
    函数名();

函数表达式

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

调用函数
语法:函数对象([实参1,实参2…实参N]);
fun() sum() alert() Number() parseInt()
当我们调用函数时,函数中封装的代码会按照编写的顺序执行

立即执行函数

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

/*(function(){
	alert("我是一个匿名函数~~~");
})();*/
(function(a,b){  
    console.log("a = "+a);  
    console.log("b = "+b);  
})(123,456); 

其他

遍历对象

for(var v in obj){  
    document.write("property:name ="+v+"value="+obj[v]+"<br/>" );  
}  

形参和实参
形参:形式参数
定义函数时,可以在()中定义一个或多个形参,形参之间使用,隔开
定义形参就相当于在函数内声明了对应的变量但是并不赋值,形参会在调用时才赋值。

function sum(a,b){
	console.log("a = "+a);
	console.log("b = "+b);
	console.log(a+b);
}
/*
* 在调用函数时,可以在()中指定实参(实际参数)
* 	实参将会赋值给函数中对应的形参
*/
sum(1,2);

实参:实际参数(实参可以是任意类型)
调用函数时,可以在()传递实参,传递的实参会赋值给对应的形参,
调用函数时JS解析器不会检查实参的类型和个数,可以传递任意数据类型的值。
如果实参的数量大于形参,多余实参将不会赋值

function sum(a , b ){		
    var d = a + b ;			
    return d;		
	}

sum(1,2,3); //多余实参将不会赋值,即3无法赋值

如果实参的数量小于形参,则没有对应实参的形参将会赋值undefined

function sum(a , b ){		
	console.log(a);	 //1
    console.log(b);	 //undefined
	}

sum(1); 

返回值,就是函数执行的结果。
使用return 来设置函数的返回值。
语法:return 值;
该值就会成为函数的返回值,可以通过一个变量来接收返回值
return后边的代码都不会执行,一旦执行到return语句时,函数将会立刻退出。

function sum(a , b , c){
    //alert(a + b +c);			
    var d = a + b + c;			
    return d;		
    console.log(11); //前面有return 语句,该语句不会执行			
	}

return后可以跟任意类型的值,可以是基本数据类型,也可以是一个对象。
如果return后不跟值,或者是不写return则函数默认返回undefined。

function sum(a , b , c){
    return ;	//return后不跟值,或者是不写return则函数默认返回undefined。
    console.log(11); //前面有return 语句,该语句不会执行			
	}


//不写return则函数默认返回undefined。
function sum(a , b , c){
    console.log(11); //前面有return 语句,该语句不会执行			
	}


//调用函数
//变量result的值就是函数的执行结果
//函数返回什么result的值就是什么
var result = sum(4,7,8);

break、continue和return
break
退出当前循环
continue
跳过当次循环
return
退出函数

练习,注:返回值可以是任意的数据类型

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			
			function fun(){
				alert("函数要执行了~~~~");
				
				for(var i=0 ; i<5 ; i++){
					
					
					if(i == 2){
						//使用break可以退出当前的循环
						//break;
						
						//continue用于跳过当次循环
						//continue;
						
						//使用return可以结束整个函数
						//return;
					}
					
					console.log(i);
				}
				
				alert("函数执行完了~~~~");
			}
			
			//fun();
			
			/*
			 * 返回值可以是任意的数据类型
			 * 	也可以是一个对象,也可以是一个函数
			 */
			function fun2(){
				
				//返回一个对象
				return {name:"沙和尚"};
			}
			
			var a = fun2();
			
			//console.log("a = "+a);
			
			function fun3(){
				//在函数内部再声明一个函数
				function fun4(){
					alert("我是fun4");
				}
				
				//将fun4函数对象作为返回值返回
				return fun4;
			}
			
			a = fun3();
			//console.log(a);
			//a();
			fun3()();
			
            
            
            //函数对象()
			/*
			 * 立即执行函数
			 * 	函数定义完,立即被调用,这种函数叫做立即执行函数
			 * 	立即执行函数往往只会执行一次
			 */
			/*(function(){
				alert("我是一个匿名函数~~~");
			})();*/
			
			(function(a,b){
				console.log("a = "+a);
				console.log("b = "+b);
			})(123,456);
			
		</script>
	</head>
	<body>
	</body>
</html>

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

var obj = new Object();
obj.name = "zhangsan"
obj.sayName = function(){   //对象的属性值也可以是个函数
    console.log(obj.name);
};

function fun(){
	console.log(obj.name);
};

obj.sayName(); //调用方法

fun();  //调用函数

var obj2 = {	
	name:"猪八戒",
	age:18,
	sayName:function(){  //定义方法
		console.log(obj2.name);
	}
};
obj2.sayName();


注:

函数和方法的区别:
没有区别,只是叫法不同;函数在对象里叫方法;不在对象中叫函数
函数也可以称为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法,调用这个函数就说调用对象的方法(method)	

eval()函数

/*
* eval()
* 	- 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回
* 	- 如果使用eval()执行的字符串中含有{},它会将{}当成是代码块
* 		如果不希望将其当成代码块解析,则需要在字符串前后各加一个()
* 
* 	- eval()这个函数的功能很强大,可以直接执行一个字符串中的js代码,
* 		但是在开发中尽量不要使用,首先它的执行性能比较差,然后它还具有安全隐患
*/
<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>
	<script type="text/javascript">
		var str = '{"name":"孙悟空","age":18,"gender":"男"}';
		/*
		 * eval()
		 * 	- 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回
		 * 	- 如果使用eval()执行的字符串中含有{},它会将{}当成是代码块
		 * 		如果不希望将其当成代码块解析,则需要在字符串前后各加一个()
		 * 
		 * 	- eval()这个函数的功能很强大,可以直接执行一个字符串中的js代码,
		 * 		但是在开发中尽量不要使用,首先它的执行性能比较差,然后它还具有安全隐患
		 */
		var str2 = "alert('hello');";
		eval(str2);
		var obj = eval("(" + str + ")");
		console.log(obj);
	</script>
</head>

<body>
</body>

</html>

作用域

作用域简单来说就是一个变量的作用范围。
在JS中作用域分成两种:

1.全局作用域

直接在script标签中编写的代码都运行在全局作用域中
全局作用域在打开页面时创建,在页面关闭时销毁。
全局作用域中有一个全局对象window,window对象由浏览器提供,可以在页面中直接使用,它代表的是整个的浏览器的窗口
在全局作用域中创建的变量都会作为window对象的属性保存
在全局作用域中创建的函数都会作为window对象的方法保存
在全局作用域中创建的变量和函数可以在页面的任意位置访问。
在函数作用域中也可以访问到全局作用域的变量。
尽量不要在全局中创建变量

变量的声明提前和函数的声明提前

  • 变量的声明提前

    • 使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值), 但是如果声明变量时

      不使用var关键字,则变量不会被声明提前

console.log("a = "+a); //undefined			
var a = 123;   //相当于在最前面声明a变量  var a;


console.log("b = "+b); //报错:b is not defined	
b = 123;   

image-20211109211420032

函数的声明提前

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

fun();   //正常输出:我是一个fun函数
//函数声明,会被提前创建
function fun(){
	console.log("我是一个fun函数");
}

fun2();  //报错:fun2 is not a function
//函数表达式,不会被提前创建
var fun2 = function(){
};

image-20211109212036928

2.函数作用域

函数作用域是函数执行时创建的作用域,每次调用函数都会创建一个新的函数作用域。
函数作用域在函数执行时创建,在函数执行结束时销毁
在函数作用域中创建的变量,不能在全局中访问。
当在函数作用域中使用一个变量时,它会先在自身作用域中寻找,

如果有就直接使用

如果没有则向上一级作用域中寻找,直到找到全局作用域,
如果全局作用域中依然没有找到,则会报错ReferenceError

/*
* 在函数作用域也有声明提前的特性,
* 	使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
 * 	函数声明也会在函数中所有的代码执行之前声明
 */
function fun3() {
	fun4();
	console.log(a);  //undefined
	var a = 35;     //在函数作用域最前面声明 var = a;
    
	function fun4() {   //在函数fun3最前面声明函数fun4
		alert("I'm fun4");
	}
}

image-20211109215327834

image-20211109215512224

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

在函数中,不使用var声明的变量都会成为全局变量

/*
* 在函数中,不使用var声明的变量都会成为全局变量
*/
function fun5() {
//d没有使用var关键字,则会设置为全局变量
	d = 100;
}
fun5();
//在全局输出d
console.log("d = " + d);

定义形参就相当于在函数作用域中声明了变量

/*
* 定义形参就相当于在函数作用域中声明了变量
 */
function fun6(e) {
	//形参e,相当于在fun6中定义了一个局部变量
	//var e;
	alert(e);  
}
fun6();  //调用fun6时,没有传参数,相当于只声明了e,没有赋值,所以当执行alert(e)时,输出undefined

this(上下文对象)

我们每次调用函数时,解析器(浏览器引擎) 都会将一个上下文对象作为隐含的参数传递进函数。
使用this来引用上下文对象,根据函数的调用形式不同,this的值也不同。

this指向当前对象

this的不同的情况:
1.以函数的形式调用时,this是window

function fun() {
			console.log(this.name); //全局name
		}

		//创建一个对象
		var obj = {
			name: "所悟空",
			sayName: fun
		}
		var name = "全局name";

		//以函数形式调用,this是window
		fun();

2.以方法的形式调用时,this就是调用方法的对象

function fun() {
			console.log(this.name); //所悟空
		}

		//创建一个对象
		var obj = {
			name: "所悟空",
			sayName: fun
		}
		var name = "全局name";

		//以方法的形式调用,this是调用方法的对象
		obj.sayName();

3.以构造函数的形式调用时,this就是新创建的对象

构造函数

构造函数是专门用来创建对象的函数
一个构造函数我们也可以称为一个类
通过一个构造函数创建的对象,我们称该对象是这个构造函数的实例
通过同一个构造函数创建的对象,我们称为一类对象
构造函数就是一个普通的函数,只是他的调用方式不同,
如果直接调用,它就是一个普通函数
如果使用new来调用,则它就是一个构造函数

例子:

function Person(name , age , gender){  
    this.name = name;  
    this.age = age;  
    this.gender = gender;  
    this.sayName = function(){  
        alert(this.name);  
    };  
}  
 var per = new Person("孙悟空",18,"男");   //使用new来调用,则Person就是一个构造函数

构造函数的执行流程:
1.创建一个新的对象
2.将新的对象作为函数的上下文对象(this)
3.执行函数中的代码
4.将新建的对象返回

instanceof 用来检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数
如果该对象是构造函数的实例,则返回true,否则返回false
Object是所有对象的祖先,所以任何对象和Object做instanceof都会返回true

Dog(){
    
}
var dog = new Dog();
console.log(dog instanceof Object); //true

原型(prototype)

  • 创建一个函数以后,解析器都会默认在函数中添加一个prototype参数
    prototype属性指向的是一个对象,这个对象我们称为原型对象。

    function MyClass(){
    		//prototype属性默认在MyClass函数中,prototype默认指向一个原型对象
    }
    

image-20211110004129748

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

    var mc = new MyClass();  //有一个隐含属性__prototype__
    var mc2 = new MyClass();
    var mc3 = new MyClass();
    

image-20211110005026184

  • 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
  • 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
  • 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了

image-20211110211820787

原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。

我们可以将对象中共有的属性和方法统一添加到原型对象中,
这样我们只需要添加一次,就可以使所有的对象都可以使用。
当我们去访问对象的一个属性或调用对象的一个方法时,它会先自身中寻找,
如果在自身中找到了,则直接使用。
如果没有找到,则去原型对象中寻找,如果找到了则使用,
如果没有找到,则去原型的原型中寻找,依此类推。直到找到Object的原型为止,Object的原型的原型为null,
如果依然没有找到则返回undefined
使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true

hasOwnProperty()
这个方法可以用来检查对象自身中是否含有某个属性
语法:对象.hasOwnProperty(“属性名”)

/*
* 原型对象也是对象,所以它也有原型,
* 	当我们使用一个对象的属性或方法时,会在自身中寻找,
* 		自身中如果有,则直接使用,
* 		如果没有则去原型对象中寻找,如果原型对象中有,则使用,
* 		如果没有则去原型的原型中寻找,直到找到Object对象的原型,
* 		Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
*/

toString方法

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

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

function Person(name , age , gender){
	this.name = name;
	this.age = age;
	this.gender = gender;
}
var per = new Person("孙悟空",18,"男");
console.log(per.toString()) //[object Object]
console.log(per)  //相当于 console.log(per。toString())

Person.prototype.toString = function(){
    return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
};

console.log(per.toString()) //Person[name=孙悟空,age=18,gender=男]

垃圾回收(GC)

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

image-20211110224202604

数组(Array)

数组也是一个对象,是一个用来存储数据的对象和Object类似,但是它的存储效率比普通对象要高
数组中保存的内容我们称为元素
普通对象使用字符串作为属性名,数组使用索引(index)来操作元素
索引指由0开始的整数

image-20211110225117282

数组的操作:

创建数组俩种方式

var arr = new Array();  
var arr1 = new Array(1,2,3,4);  
//或者使用字面量来创建数组
var arr = [];  
var arr1 = [1,2,3,4];  

向数组中添加元素
语法;
数组对象[索引] = 值;

arr[0] = 123;  
arr[1] = "hello";  

创建数组时直接添加元素
语法:

 var arr = [元素1,元素2....元素N]; 

//例如
 var arr = [123,"hello",true,null];  

获取和修改数组的长度
使用length属性来操作数组的长度
获取长度:
数组.length
对于非连续的数组,length获取到的是数组的最大索引+1
对于连续的数组,length获取到的就是数组中元素的个数

//连续
var arr = new Array();
arr[0] = 0;
arr[1] = 1
console.log(arr.length); //2


//非连续
var arr1 = new Array();
arr1[0] = 0;
arr1[10] = 10;
console.log(arr1.length)  // 11

修改数组的长度
数组.length = 新长度
如果修改后的length大于原长度,则多出的部分会空出来

var arr = new Array();
arr[0] = 1;
arr[1] = 3;
arr[2] = 2;
arr.length = 6;
console.log(arr); 

image-20211110233649971

如果修改后的length小于原长度,则原数组中多出的元素会被删除

var arr = new Array();
arr[0] = 1;
arr[1] = 3;
arr[2] = 2;
arr.length = 2;
console.log(arr); 

image-20211110233736897

向数组的最后添加元素
由于length会获取到数组的最大的索引+1,数组[数组.length] = 值;

var arr = new Array();
arr[arr.length] = 70;
arr[arr.length] = 80;
arr[arr.length] = 90;

console.log(arr); //70,80,90

数组遍历

//创建一个数组
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];

//遍历方式一:
for(var i=0 ; i<arr.length ; i++){
	console.log(arr[i]);
}

//遍历方式二:
arr.forEach(function(value , index , array){
	console.log(value);
});

/*
* forEach()方法需要一个函数作为参数
* 	- 像这种函数,由我们创建但是不由我们调用的,我们称为回调函数
* 	- 数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素
* 		以实参的形式传递进来,我们可以来定义形参,来读取这些内容
* 	- 浏览器会在回调函数中传递三个参数:
* 		第一个参数,就是当前正在遍历的元素
* 		第二个参数,就是当前正在遍历的元素的索引
* 		第三个参数,就是正在遍历的数组
* 		
*/

数组的方法

image-20211111233241524

slice(sart,[end])

可以从一个数组中截取指定的元素
该方法不会影响原数组,而是将截取到的内容封装为一个新的数组并返回
参数:
1.截取开始位置的索引(包括开始位置) (左闭右开)
2.截取结束位置的索引(不包括结束位置)
第二个参数可以省略不写,如果不写则一直截取到最后
参数可以传递一个负值,如果是负值,则从后往前数

splice()

/*
* splice()
* 	- 可以用于删除数组中的指定元素
* 	- 使用splice()会影响到原数组,会将指定元素从原数组中删除并将被删除的元素作为返回值返回
* 	- 参数:
* 		第一个,表示开始位置的索引
* 		第二个,表示删除的数量
* 		第三个及以后。。
* 			可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
*/

arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
var result = arr.splice(3,0,"牛魔王","铁扇公主","红孩儿");  //从索引3开始,删除0个元素,添加"牛魔王","铁扇公主","红孩儿"3个元素
console.log(result);   //"孙悟空","猪八戒","沙和尚","唐僧","牛魔王","铁扇公主","红孩儿","白骨精"

join([splitor])

可以将一个数组转换为一个字符串

该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回

参数:
需要一个字符串作为参数,这个字符串将会作为连接符来连接数组中的元素
如果不指定连接符则默认使用逗号

arr = ["孙悟空","猪八戒","沙和尚","唐僧"];	
result = arr.join("@-@");

sort()

可以对一个数组中的内容进行排序,默认是按照Unicode编码进行排序,所以对数字进排序时,可能会得到错误的结果
调用以后,会直接修改原数组
我们可以自己来指定排序的规则,我们可以在sort()添加一个回调函数,来指定排序规则,

​ -回调函数中需要定义两个形参,浏览器将会分别使用数组中的元素作为实参去调用回调函数,使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边

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

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

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

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

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

arr = [5,4,2,1,3,6,8,7];
arr.sort(function(a,b){
	//升序排列
	//return a - b;
    
    //降序排列
	return b - a;
});

concat()

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

var arr = ["孙悟空","猪八戒","沙和尚"];
var arr2 = ["白骨精","玉兔精","蜘蛛精"];
var arr3 = ["二郎神","太上老君","玉皇大帝"];
var result = arr.concat(arr2,arr3,"牛魔王","铁扇公主");

reverse()

该方法用来反转数组(前边的去后边,后边的去前边),该方法会直接修改原数组

arr = ["b","d","e","a","c"];
arr.reverse();

函数对象的方法

call()和apply()

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

  • 当函数调用call()和apply()时都会调用函数自身的执行

    function fun(a,b) {
    	console.log("a = "+a);
    	console.log("b = "+b);
    }
    
    fun.call();//执行call()方法的同时,也执行fun()函数
    
  • 在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this

    function fun(a,b) {
    	console.log(this); // 这个对象为obj
    }
    var obj = {
    	name: "obj",
    	sayName:function(){
    	alert(this.name);
    }
    fun.call(obj);
    //fun.apply(obj);
    
  • call()方法可以将实参在对象之后依次传递

    fun.call(obj,2,3); //obj 是对象,2和3是实参
    
  • apply()方法需要将实参封装到一个数组中统一传递

     fun.apply(obj,[2,3]);
    

arguments方法

/*
* 在调用函数时,浏览器每次都会传递进两个隐含的参数:
* 	1.函数的上下文对象 this
* 	2.封装实参的对象 arguments
* 		- arguments是一个类数组对象(arguments不是数组类型,只能说argument用法很像数组),它也可以通过索引来操作数据,也可以获取长度
* 		- 在调用函数时,我们所传递的实参都会在arguments中保存
* 		- arguments.length可以用来获取实参的长度
* 		- 我们即使不定义形参,也可以通过arguments来使用实参,只不过比较麻烦
* 			arguments[0] 表示第一个实参
* 			arguments[1] 表示第二个实参 。。。
*		- 它里边有一个属性叫做callee,
* 			这个属性对应一个函数对象,就是当前正在指向函数的对象
*/

function fun(){
	console.log(arguments instanceof Array);  //false,arguments不是数组
	console.log(Array.isArray(arguments));    //false
	//console.log(arguments[1]);
	//console.log(arguments.length);
	console.log(arguments.length);
	console.log(arguments.callee);
	console.log(arguments.callee == fun);     //true
}

fun("hello",true);

包装类

在JS中为我们提供了三个包装类:
String() Boolean() Number()
通过这三个包装类可以创建基本数据类型的对象
例子:

var num = new Number(2);
var str = new String("hello");  
var bool = new Boolean(true); 

但是在实际应用中千万不要这么干。

当我们去操作一个基本数据类型的属性和方法时,
解析器会临时将其转换为对应的包装类,然后再去操作属性和方法,
操作完成以后再将这个临时对象进行销毁。

var s = 123;
//s变量首先会转成Number类型的对象,Number类型的对象添加一个hello属性,值为"你好";
//当执行完这整条语句时,Number对象会被销毁
s.hello = "你好"; 	
console.log(s.hello);  //s变量重新转Number类型对象,但是没有hello属性了,undefined
console.log(typeof s); //string

Date

日期的对象,在JS中通过Date对象来表示一个时间
创建对象
创建一个当前的时间对象

var d = new Date();  
console.log(d);  //Sat Nov 13 2021 11:25:38 GMT+0800 (中国标准时间)

创建一个指定的时间对象,需要在构造函数中传递一个表示时间的字符串作为参数

日期的格式 月份/日/年 时:分:秒

var d2 = new Date("2/18/2011 11:10:30");
console.log(d2);  //Fri Feb 18 2011 11:10:30 GMT+0800 (中国标准时间)

方法:

image-20211113113943587

getDate():获取当前日期对象是几日

var d2 = new Date("2/18/2011 11:10:30");
console.log(d2);  //Fri Feb 18 2011 11:10:30 GMT+0800 (中国标准时间)

/*
* getDate()
* 	- 获取当前日期对象是几日
*/
var date = d2.getDate();
console.log(date);   //18

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

  • 会返回一个0-6的值
    • 0 表示周日
    • 1表示周一
var d2 = new Date("2/18/2011 11:10:30");
var day = d2.getDay();
console.log(day);   //5

getMonth():获取当前时间对象的月份

会返回一个0-11的值

  • 0 表示1月
  • 1 表示2月
  • 11 表示12月
var d2 = new Date("2/18/2011 11:10:30");
var month = d2.getMonth();
console.log(month);  //1

getFullYear() :获取当前日期对象的年份

var year = d2.getFullYear();
console.log(year); //2011

getTime():获取当前日期对象的时间戳

  • 时间戳,指的是从格林威治标准时间的1970年1月1日,0时0分0秒, 到当前日期所花费的毫秒数(1秒 = 1000毫秒)
  • 计算机底层在保存时间时使用都是时间戳
var d3 = new Date("1/1/1970 0:0:0");
time = d3.getTime();
console.log(time);  //-28800000

Date.now():获取当前的时间戳

var start = Date.now();
console.log(start);   //1636775545722

Math

Math属于一个工具类(类似Java的静态类),它不需要我们创建对象,它里边封装了属性运算相关的常量和方法
我们可以直接使用它来进行数学运算相关的操作

注释:Math 对象并不像 Date 和 String 那样是对象的类,因此没有构造函数 Math(),像 Math.sin() 这样的函数只是函数,不是某个对象的方法。您无需创建它,通过把 Math 作为对象使用就可以调用其所有属性和方法。

image-20211113122321562

image-20211113122523358

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			
			//Math.PI 表示的圆周率
			console.log(Math.PI);
			
			/*
			 * abs()可以用来计算一个数的绝对值
			 */
			console.log(Math.abs(-1));
			
			/*
			 * Math.ceil()
			 * 	- 可以对一个数进行向上取整,(小数位有值就自动进1),返回值 >= 该参数的最大整数
			 * Math.floor()
			 * 	- 可以对一个数进行向下取整,(小数部分会被舍掉),返回值 <= 该参数的最大整数
			 * Math.round()
			 * 	- 可以对一个数进行四舍五入取整
			 */
			console.log(Math.ceil(1.1));   //2
			console.log(Math.floor(1.99));  //1
			console.log(Math.round(1.4));  //1
			console.log(Math.ceil(-1.5)); //-1
			console.log(Math.floor(-1.5)); //-2
			
			/*
			 * Math.random()
			 * 	- 可以用来生成一个0-1之间的随机数
			 *  - 生成一个[0-10)的随机数,左闭右开
			 * 	- 生成一个0-x之间的随机数
			 * 		Math.round(Math.random()*x)
			 * 
			 * 	- 生成一个1-10
			 * 	- 生成一个x-y之间的随机数:Math.round(Math.random()*(y-x)+x)
			 */
			
			//生成1-6之间的随机数
			console.log(Math.round(Math.random()*5+1));
			
			/*
			 * max() 可以获取多个数中的最大值
			 * min() 可以获取多个数中的最小值
			 */


			var max = Math.max(10,45,30,100);
			console.log(max); //100
			var min = Math.min(10,45,30,100);
			console.log(min); //10
			
			/*
			 * Math.pow(x,y)
			 * 	返回x的y次幂
			 */
			
			console.log(Math.pow(2,3)); //8
			
			/*
			 * Math.sqrt()
			 *  用于对一个数进行开方运算
			 */
			console.log(Math.sqrt(4));  //2
			
		</script>
	</head>
	<body>
	</body>
</html>

字符串的相关的方法

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			//创建一个字符串
			var str = "Hello Atguigu";
			
			/*
			 * 在底层字符串是以字符数组的形式保存的
			 * ["H","e","l"]
			 */
			
			/*
			 * length属性
			 * 	- 可以用来获取字符串的长度
			 */
			//console.log(str.length);
			//console.log(str[5]);
			
			/*
			 * charAt()
			 * 	- 可以返回字符串中指定位置的字符
			 * 	- 根据索引获取指定的字符	
			 */
			str = "中Hello Atguigu";
			
			var result = str.charAt(6);
			
			/*
			 * charCodeAt()
			 * 	- 获取指定位置字符的字符编码(Unicode编码)
			 */
			
			result = str.charCodeAt(0);
			
			/*
			 * String.formCharCode()
			 * 	- 可以根据字符编码去获取字符
			 */
			result = String.fromCharCode(0x2692);
			
			/*
			 * concat()
			 * 	- 可以用来连接两个或多个字符串
			 * 	- 作用和+一样
			 */
			result = str.concat("你好","再见");
			
			/*
			 * indexof()
			 * 	- 该方法可以检索一个字符串中是否含有指定内容
			 * 	- 如果字符串中含有该内容,则会返回其第一次出现的索引
			 * 		如果没有找到指定的内容,则返回-1
			 * 	- 可以指定一个第二个参数,指定开始查找的位置
			 * 
			 * lastIndexOf();
			 * 	- 该方法的用法和indexOf()一样,
			 * 		不同的是indexOf是从前往后找,
			 * 		而lastIndexOf是从后往前找
			 * 	- 也可以指定开始查找的位置
			 */
			
			str = "hello hatguigu";
			
			result = str.indexOf("h",1);
			
			result = str.lastIndexOf("h",5);
			
			/*
			 * slice()
			 * 	- 可以从字符串中截取指定的内容
			 * 	- 不会影响原字符串,而是将截取到内容返回
			 * 	- 参数:
			 * 		第一个,开始位置的索引(包括开始位置)
			 * 		第二个,结束位置的索引(不包括结束位置)
			 * 			- 如果省略第二个参数,则会截取到后边所有的
			 * 		- 也可以传递一个负数作为参数,负数的话将会从后边计算
			 */
			str = "abcdefghijk";
			
			result = str.slice(1,4);
			result = str.slice(1,-1);
			
			/*
			 * substring()
			 * 	- 可以用来截取一个字符串,可以slice()类似
			 * 	- 参数:
			 * 		- 第一个:开始截取位置的索引(包括开始位置)
			 * 		- 第二个:结束位置的索引(不包括结束位置)
			 * 		- 不同的是这个方法不能接受负值作为参数,
			 * 			如果传递了一个负值,则默认使用0
			 * 		- 而且他还自动调整参数的位置,如果第二个参数小于第一个,则自动交换
			 */
			
			result = str.substring(0,1);
			
			/*
			 * substr()
			 * 	- 用来截取字符串
			 * 	- 参数:
			 * 		1.截取开始位置的索引
			 * 		2.截取的长度
			 */
			
			str = "abcdefg";
			
			result = str.substr(3,2);
			
			/*
			 * split()
			 * 	- 可以将一个字符串拆分为一个数组
			 * 	- 参数:
			 * 		-需要一个字符串作为参数,将会根据该字符串去拆分数组
			 */
			str = "abcbcdefghij";
			
			result = str.split("d");
			
			/*
			 * 如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
			 */
			result = str.split("");
			
			//console.log(Array.isArray(result));
			//console.log(result[0]);
			console.log(result);
			
			
			str = "abcdefg";
			
			/*
			 * toUpperCase()
			 * 	- 将一个字符串转换为大写并返回
			 */
			result = str.toUpperCase();
			
			str = "ABCDEFG";
			
			/*
			 * toLowerCase()
			 * 	-将一个字符串转换为小写并返回
			 */
			result = str.toLowerCase();
			
			//console.log(result);
			
			
		</script>
	</head>
	<body>
	</body>
</html>

正则表达式

正则用来定义一些字符串的规则,程序可以根据这些规则来判断一个字符串是否符合规则,也可以将一个字符串中符合规则的内容提取出来。

创建正则表达式方式一:

语法:

var 变量 = new RegExp("正则表达式","匹配模式");  //匹配模式可以不写

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

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

在构造函数中可以传递一个匹配模式作为第二个参数,

​ - i 忽略大小写 (ignore)

​ -g 全局匹配模式(global)

练习:

var reg = new RegExp("ab","i");
console.log(reg.test("abc"));  //true
console.log(typeof reg);  //object

创建正则表达式二:

var 变量 =/正则表达式/
var 变量 =/正则表达式/匹配模式    例如:var reg = /a/i     //判断某个字符串是否含有a且忽略大小写

练习:

var reg = /ab/i
console.log(reg.test("abc"));  //true
console.log(typeof reg);  //object

正则语法

| 或
[] 或
【^ 】 除了

reg = /[^ab]/;  //字符串中是否包含除了a和b的其他字符串
console.log(reg.text("abc"));  //true

[a-z] 小写字母 (也可以[e-i])
[A-Z] 大写字母
[A-z] 任意字母,但是还包括了其他ASCII在此之中的
[0-9] 任意数字

支持正则表达式的 String 对象的方法

image-20211113222443155

split()

var str = "1a2b3c4d5e6f7";
/*
* split()
* 	- 可以将一个字符串拆分为一个数组
* 	- 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
* 	- 这个方法即使不指定全局匹配,也会全都插分
*/

/*
* 根据任意字母来将字符串拆分
*/
var result = str.split(/[A-z]/);
console.log(result);

image-20211113222608478

search()

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

console.log(result);  //6

match()

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

result = str.match(/[a-z]/ig);
console.log(result);

image-20211113223308359

replace()

/*
* replace()
* 	- 可以将字符串中指定内容替换为新的内容
*  - 参数:
* 		1.被替换的内容,可以接受一个正则表达式作为参数
* 		2.新的内容
*  - 默认只会替换第一个
*/
str = "1a2a3a4a5e6f7A8B9C";
result = str.replace(/[a-z]/gi , "");
console.log(result);  //123456789

量词

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

元符号

/*
* . 任意一个符号
* \w
* 	- 任意字母、数字、_  [A-z0-9_]
* \W
* 	- 除了字母、数字、_  [^A-z0-9_]
* \d
* 	- 任意的数字 [0-9]
* \D
* 	- 除了数字 [^0-9]
* \s
* 	- 空格
* \S
* 	- 除了空格
* \b
* 	- 单词边界
* \B
* 	- 除了单词边界
*/

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

注:检查一个字符串中是否含有 . ,在正则表达式中使用\作为转义字符,如\.

var reg1 = /./;  //任意字符
var reg2 = /\./;   //转义后,单纯代表 .

//(相当于reg2)转义后,单纯代表 .    
//理解:直接用字符串做正则表达式,遇到特殊字符需要转义, \\-->\,所以\\.--->\.  相当于var = reg2 = /\./
var reg3 = new RegExp("\\.");  

console.log(reg1.test("agb"))  //true
console.log(reg2.test("agb"))  //false

console.log(reg2.test("agb.")) //true
console.log(reg3.test("agb.")) //true

DOM

dom介绍

  • DOM,全称Document Object Model文档对象模型。
    • JS中通过DOM来对HTML文档进行操作。只要理解了DOM就可以随心所欲的操作WEB页面。
  • 文档(Document)
    • 文档表示的就是整个的HTML网页文档
  • 对象(Object)
    • 对象表示将网页中的每一个部分都转换为了一个对象。
  • 模型(Model)
    • 使用模型来表示对象之间的关系,这样方便我们获取对象。

image-20211114001008237

image-20211113233421873

节点

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

  • 比如:html标签、属性、文本、注释、整个文档等都是一个节点。

  • 虽然都是节点,但是实际上他们的具体类型是不同的。

  • 比如:标签我们称为元素节点、属性称为属性节点、文本称为文本节点、文档称为文档节点。

  • 节点的类型不同,属性和方法也都不尽相同。

  • 节点:Node——构成HTML文档最基本的单元
    常用节点分为四类

    • 文档节点:整个HTML文档
    • 元素节点:HTML文档中的HTML标签
    • 属性节点:元素的属性
    • 文本节点:HTML标签中的文本内容

image-20211114001325755

节点的属性

image-20211114001422560

文档节点(document)

  • 文档节点document,代表的是整个HTML文档,网页中的所有节点都是它的子节点
  • document对象作为window对象的属性存在的,可以直接使用
  • 通过该对象我们可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。

元素节点(Element)

  • HTML中的各种标签都是元素节点,这也是我们最常用的一个节点。
  • 浏览器会将页面中所有的标签都转换为一个元素节点,我们可以通过document的方法来获取元素节点。
    比如:
    – document.getElementById()
    – 根据id属性值获取一个元素节点对象。

属性节点(Attr)

  • 属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。

  • 可以通过元素节点来获取指定的属性节点。
    • 例如:
    – 元素节点.getAttributeNode("属性名");

    注意:我们一般不使用属性节点。

文本节点(Text)

  • 文本节点表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点。
  • 它包括可以字面解释的纯文本内容。
  • 文本节点一般是作为元素节点的子节点存在的
  • 获取文本节点时,一般先要获取元素节点。再通过元素节点获取文本节点。
    例如:
    – 元素节点.firstChild;
    – 获取元素节点的第一个子节点,一般为文本节点

事件

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

绑定事件的方式:

1.可以在标签的事件属性中设置相应的JS代码
例子:

<button onclick="js代码。。。">按钮</button>  

2.可以通过为对象的指定事件属性设置回调函数的形式来处理事件
例子:

<button id="btn">按钮</button>  
<script>  
    var btn = document.getElementById("btn");  
    btn.onclick = function(){  
  
   };  

获取元素节点

通过document对象调用

  1. getElementById()
    – 通过id属性获取一个元素节点对象
  2. getElementsByTagName()
    – 通过标签名获取一组元素节点对象
  3. getElementsByName()
    – 通过name属性获取一组元素节点对象

获取元素节点的子节点

通过具体的元素节点调用

  1. getElementsByTagName()
    – 方法,返回当前节点的指定标签名后代节点

  2. childNodes
    – 属性,表示当前节点的所有子节点(包括空白的文本节点)

  3. children
    – 属性,表示当前节点的所有子节点(不包括空白的文本节点)

  4. firstElementChild

– 属性,表示当前节点的第一个子节点(不包括空白文本节点)

  1. firstChild
    – 属性,表示当前节点的第一个子节点(包括空白文本节点)

  2. lastChild
    – 属性,表示当前节点的最后一个子节点

获取父节点和兄弟节点

通过具体的节点调用

  1. parentNode
    – 属性,表示当前节点的父节点
  2. previousSibling
    – 属性,表示当前节点的前一个兄弟节点
  3. nextSibling
    – 属性,表示当前节点的后一个兄弟节点

元素节点的属性

获取: 元素对象.属性名
例:element.value,element.id,element.className
设置: 元素对象.属性名=新的值
例:element.value = “hello”,element.id = “id01”,element.className = “newClass”

其他属性

  • nodeValue
    – 文本节点可以通过nodeValue属性获取和设置文本节点的内容
  • innerHTML
    – 元素节点通过该属性获取和设置标签内部的html代码

使用CSS选择器进行查询

  • querySelector()
  • querySelectorAll()
  • 这两个方法都是用document对象来调用,两个方法使用相同,都是传递一个选择器字符串作为参数,方法会自动根据选择器字符串去网页中查找元素。
  • 不同的地方是querySelector()只会返回找到的第一个元素,而querySelectorAll()会返回所有符合条件的元素。

节点的修改

这里的修改我们主要指对元素节点的操作。

  • 创建节点
    – document.createElement(标签名)
  • 删除节点
    – 父节点.removeChild(子节点)
  • 替换节点
    – 父节点.replaceChild(新节点 , 旧节点)
  • 插入节点
    – 父节点.appendChild(子节点)
    – 父节点.insertBefore(新节点 , 旧节点)

文档的加载

浏览器在加载一个页面时,是按照自上向下的顺序加载的,加载一行执行一行。
如果将js代码编写到页面的上边,当代码执行时,页面中的DOM对象还没有加载,此时将会无法正常获取到DOM对象,导致DOM操作失败。
解决方式一
可以将js代码编写到body的下边

<body>  
		<button id="btn">按钮</button>  
  
		<script>  
			var btn = document.getElementById("btn");  
			btn.onclick = function(){  
		  
			};  
	</script>  
</body>  


解决方式二:
将js代码编写到window.onload = function(){}中
window.onload 对应的回调函数会在整个页面加载完毕以后才执行,所以可以确保代码执行时,DOM对象已经加载完毕了

<script>  
    window.onload = function(){  
        var btn = document.getElementById("btn");  
        btn.onclick = function(){  
        };  
    };  
</script>	    

DOM查询

元素.childNodes

获取当前元素的所有子节点,会获取到空白的文本子节点

childNodes属性会获取包括文本节点在呢的所有节点,根据DOM标签标签间空白也会当成文本节点
注意:在IE8及以下的浏览器中,不会将空白文本当成子节点

元素.children
获取当前元素的所有子元素(不包括空白的文本子节点)

元素.firstChild
获取当前元素的第一个子节点,会获取到空白的文本子节点

元素.lastChild
获取当前元素的最后一个子节点

元素.parentNode
获取当前元素的父元素

元素.previousSibling
获取当前元素的前一个兄弟节点(包括空白的子节点)

previousElementSibling

获取前一个兄弟元素(不包括空白的子节点),IE8及以下不支持

元素.nextSibling
获取当前元素的后一个兄弟节点

firstElementChild

获取当前元素的第一个子元素
firstElementChild不支持IE8及以下的浏览器,如果需要兼容他们尽量不要使用

innerHTML和innerText
这两个属性并没有在DOM标准定义,但是大部分浏览器都支持这两个属性
两个属性作用类似,都可以获取到标签内部的内容,
不同是innerHTML会获取到html标签,而innerText会自动去除标签
如果使用这两个属性来设置标签内部的内容时,没有任何区别的

读取标签内部的文本内容

文本节点.nodeValue

<h1>h1中的文本内容</h1>
元素.firstChild.nodeValue
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Untitled Document</title>
	<link rel="stylesheet" type="text/css" href="style/css.css" />
	<script type="text/javascript">

		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的按钮绑定一个单击响应函数
			var btn02 = document.getElementById("btn02");
			btn02.onclick = function () {
				//查找所有li节点
				//getElementsByTagName()可以根据标签名来获取一组元素节点对象
				//这个方法会给我们返回一个类数组对象,所有查询到的元素都会封装到对象中
				//即使查询到的元素只有一个,也会封装到数组中返回
				var lis = document.getElementsByTagName("li");

				//打印lis
				//alert(lis.length);

				//变量lis
				for (var i = 0; i < lis.length; i++) {
					alert(lis[i].innerHTML);
				}
			};


			//为id为btn03的按钮绑定一个单击响应函数
			var btn03 = document.getElementById("btn03");
			btn03.onclick = function () {
				//查找name=gender的所有节点
				var inputs = document.getElementsByName("gender");

				//alert(inputs.length);

				for (var i = 0; i < inputs.length; i++) {
					/*
					 * innerHTML用于获取元素内部的HTML代码的
					 * 	对于自结束标签,这个属性没有意义
					 */
					//alert(inputs[i].innerHTML);
					/*
					 * 如果需要读取元素节点属性,
					 * 	直接使用 元素.属性名
					 * 		例子:元素.id 元素.name 元素.value
					 * 		注意:class属性不能采用这种方式,因为class关键字在JavaScript 中属于保留字
					 * 			读取class属性时需要使用 元素.className
					 */
					alert(inputs[i].className);
				}
			};


		};


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

<head>
	<meta charset="UTF-8">
	<title></title>
	<style type="text/css">
		* {
			margin: 0;
			padding: 0;
		}

		#outer {
			width: 500px;
			margin: 50px auto;
			padding: 10px;
			background-color: greenyellow;
			/*设置文本居中*/
			text-align: center;
		}
	</style>

	<script type="text/javascript">

		window.onload = function () {

			/*
			 * 点击按钮切换图片
			 */

			//获取两个按钮
			var prev = document.getElementById("prev");
			var next = document.getElementById("next");

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

			//获取img标签
			var img = document.getElementsByTagName("img")[0];

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

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

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


			//分别为两个按钮绑定单击响应函数
			prev.onclick = function () {

				/*
				 * 切换到上一张,索引自减
				 */
				index--;

				//判断index是否小于0
				if (index < 0) {
					index = imgArr.length - 1;
				}

				img.src = imgArr[index];

				//当点击按钮以后,重新设置信息
				info.innerHTML = "一共 " + imgArr.length + " 张图片,当前第 " + (index + 1) + " 张";
			};

			next.onclick = function () {

				/*
				 * 切换到下一张是index自增
				 */
				index++;

				if (index > imgArr.length - 1) {
					index = 0;
				}

				//切换图片就是修改img的src属性
				//要修改一个元素的属性 元素.属性 = 属性值
				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>

document对象的其他的属性和方法

document.all
获取页面中的所有元素,相当于document.getElementsByTagName("*");

document.documentElement
获取页面中html根元素

document.body
获取页面中的body元素

document.getElementsByClassName()
根据元素的class属性值查询一组元素节点对象
这个方法不支持IE8及以下的浏览器

document.querySelector()
根据CSS选择器去页面中查询一个元素
如果匹配到的元素有多个,则它会返回查询到的第一个元素

var div = document.querySelector(".box1 div");

document.querySelectorAll()
根据CSS选择器去页面中查询一组元素
会将匹配到所有元素封装到一个数组中返回,即使只匹配到一个

DOM修改

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

document.createTextNode(“textContent”)
可以根据文本内容创建一个文本节点对象

父节点.appendChild(子节点)
向父节点中添加指定的子节点

父节点.insertBefore(新节点,旧节点)
将一个新的节点插入到旧节点的前边

父节点.replaceChild(新节点,旧节点)
使用一个新的节点去替换旧节点

父节点.removeChild(子节点)
删除指定的子节点

推荐方式:子节点.parentNode.removeChild(子节点)

以上方法,实际就是改变了相应元素(标签)的innerHTML的值。

myClick("btn07",function(){  
    //向city中添加广州  
    var city = document.getElementById("city");  
  
    /*  
	* 使用innerHTML也可以完成DOM的增删改的相关操作  
	* 一般我们会两种方式结合使用  
	*/  
    //city.innerHTML += "<li>广州</li>";  
  
    //创建一个li  
    var li = document.createElement("li");  
    //向li中设置文本  
    li.innerHTML = "广州";  
    //将li添加到city中  
    city.appendChild(li);  
  
});  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>添加删除记录练习</title>
	<link rel="stylesheet" type="text/css" href="ex_2_style/css.css" />
	<script type="text/javascript">

		window.onload = function () {

			/*
			 * 点击超链接以后,删除一个员工的信息
			 */

			//获取所有额超链接
			var allA = document.getElementsByTagName("a");

			//为每个超链接都绑定一个单击响应函数
			for (var i = 0; i < allA.length; i++) {
				/*
				 * for循环会在页面加载完成之后立即执行,
				 * 	而响应函数会在超链接被点击时才执行
				 * 当响应函数执行时,for循环早已执行完毕
				 */

				alert("for循环正在执行" + i);

				allA[i].onclick = function () {

					alert("响应函数正在执行" + i);  //3

					//alert(allA[i]);   //此时的i=3,allA[3] = undefined

					return false;
				};

			}

		};


	</script>
</head>

<body>

	<table id="employeeTable">
		<tr>
			<th>Name</th>
			<th>Email</th>
			<th>Salary</th>
			<th>&nbsp;</th>
		</tr>
		<tr>
			<td>Tom</td>
			<td>tom@tom.com</td>
			<td>5000</td>
			<td><a href="javascript:;">Delete</a></td>
		</tr>
		<tr>
			<td>Jerry</td>
			<td>jerry@sohu.com</td>
			<td>8000</td>
			<td><a href="deleteEmp?id=002">Delete</a></td>
		</tr>
		<tr>
			<td>Bob</td>
			<td>bob@tom.com</td>
			<td>10000</td>
			<td><a href="deleteEmp?id=003">Delete</a></td>
		</tr>
	</table>

	<div id="formDiv">

		<h4>添加新员工</h4>

		<table>
			<tr>
				<td class="word">name: </td>
				<td class="inp">
					<input type="text" name="empName" id="empName" />
				</td>
			</tr>
			<tr>
				<td class="word">email: </td>
				<td class="inp">
					<input type="text" name="email" id="email" />
				</td>
			</tr>
			<tr>
				<td class="word">salary: </td>
				<td class="inp">
					<input type="text" name="salary" id="salary" />
				</td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button id="addEmpButton" value="abc">
						Submit
					</button>
				</td>
			</tr>
		</table>

	</div>

</body>

</html>

DOM对CSS的操作

读取和修改内联样式

使用style属性来操作元素的内联样式
读取内联样式:
语法:元素.style.样式名
例子:
元素.style.width
元素.style.height
注意:如果样式名中带有-,则需要用驼峰命名法将样式名中的-去掉,然后除了首字母小写,其余单词首字母改大写
比如:background-color > backgroundColor
border-width > borderWidth
修改内联样式:
语法:元素.style.样式名 = 样式值
通过style修改和读取的样式都是内联样式,由于内联样式的优先级比较高,所以我们通过JS来修改的样式,往往会立即生效,但是如果样式中设置了!important,则内联样式将不会生效。

注:通过style属性设置和读取的都是内联样式,无法读取样式表中的样式

<style type="text/css">
	#box1{
		width: 100px;
		height: 100px;
		background-color: red !important;
	}
    
    
</style>
<script> 
    box1.style.backgroundColor = "yellow";   //不生效
</script>

读取元素的当前样式

正常浏览器
使用getComputedStyle()
这个方法是window对象的方法,可以返回一个对象,这个对象中保存着当前元素生效样式
参数:
1.要获取样式的元素
2.可以传递一个伪元素,一般传null
例子:
获取元素的宽度
getComputedStyle(box1,null).width

如果获取的样式没有设置,则会获取到真实的值,而不是默认值

比如:没有设置width,它不会获取到auto,而是一个长度

通过该方法读取到样式都是只读的不能修改,如果要修改必须通过style属性

IE8
使用currentStyle
语法:
元素.currentStyle.样式名
例子:
box1.currentStyle.backgroundColor

通过这个属性读取到的样式是只读的不能修改,如果要修改必须通过style属性

function getStyle(obj , name){
    //找变量沿着作用域找,找不到就报错,找属性是沿着原型链找,找不到返回undefined
	if(window.getComputedStyle){
	//正常浏览器的方式,具有getComputedStyle()方法
		return getComputedStyle(obj , null)[name];
	}else{
	//IE8的方式,没有getComputedStyle()方法
		return obj.currentStyle[name];
	}
				
	//return window.getComputedStyle?getComputedStyle(obj , null)[name]:obj.currentStyle[name];
				
			}

其他的样式相关的属性

注意:以下样式都是只读的,未指明偏移量都是相对于当前窗口左上角

clientHeight
元素的可见高度,包括元素的内容区和内边距的高度
clientWidth
元素的可见宽度,包括元素的内容区和内边距的宽度
offsetHeight
整个元素的高度,包括内容区、内边距、边框
offfsetWidth
整个元素的宽度,包括内容区、内边距、边框
offsetParent
当前元素的定位父元素
离他最近的开启了定位的祖先元素,如果所有的元素都没有开启定位,则返回body
offsetLeft
offsetTop
当前元素和定位父元素之间的偏移量
offsetLeft水平偏移量 offsetTop垂直偏移量

scrollHeight
scrollWidth
获取元素滚动区域的高度和宽度

scrollTop
scrollLeft
获取元素垂直和水平滚动条滚动的距离

判断滚动条是否滚动到底
垂直滚动条
scrollHeight -scrollTop = clientHeight

水平滚动
scrollWidth -scrollLeft = clientWidth

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>
	<style type="text/css">
		#box1 {
			width: 100px;
			height: 100px;
			background-color: red;
			padding: 10px;
			border: 10px solid yellow;
		}


		#box2 {
			padding: 100px;
			background-color: #bfa;
		}

		#box4 {
			width: 200px;
			height: 300px;
			background-color: #bfa;
			overflow: auto;
		}

		#box5 {
			width: 450px;
			height: 600px;
			background-color: yellow;
		}
	</style>
	<script type="text/javascript">

		window.onload = function () {
			var box1 = document.getElementById("box1");
			var btn01 = document.getElementById("btn01");
			var box4 = document.getElementById("box4");

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

				/*
				 * offsetWidth
				 * offsetHeight
				 * 	- 获取元素的整个的宽度和高度,包括内容区、内边距和边框
				 */
				//alert(box1.offsetWidth);

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

				//alert(op.id);

				/*
				 * offsetLeft
				 * 	- 当前元素相对于其定位父元素的水平偏移量
				 * offsetTop
				 * 	- 当前元素相对于其定位父元素的垂直偏移量
				 */

				//alert(box1.offsetLeft);

				/*
				 * scrollWidth
				 * scrollHeight
				 * 	- 可以获取元素整个滚动区域的宽度和高度
				 */
				alert(box4.clientHeight);  //height+toppadding+bottompadding
				alert(box4.scrollWidth);

				/*
				 * scrollLeft
				 * 	- 可以获取水平滚动条滚动的距离
				 * scrollTop
				 * 	- 可以获取垂直滚动条滚动的距离
				 */
				alert(box4.scrollLeft);
				alert(box4.scrollTop);

				//alert(box4.clientHeight); // 283

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

				//当满足scrollWidth - scrollLeft == clientWidth
				//说明水平滚动条滚动到底
				//alert(box4.scrollHeight - box4.scrollTop); // 600



			};

		};


	</script>
</head>

<body id="body">
	<button id="btn01">点我一下</button>
	<br /><br />

	<div id="box4">
		<div id="box5"></div>
	</div>



	<br /><br />

	<div id="box3">
		<div id="box2" style="position: relative;">
			<div id="box1"></div>
		</div>
	</div>


</body>

</html>

事件(Event)

事件对象

当响应函数被调用时,浏览器每次都会将一个事件对象作为实参传递进响应函数中,这个事件对象中封装了当前事件的相关信息,比如:鼠标的坐标,键盘的按键,鼠标的按键,滚轮的方向。。

可以在响应函数中定义一个形参,来使用事件对象,但是在IE8以下浏览器中事件对象没有作为实参传递进响应函数中,而是作为window对象的属性保存

例子:

元素.事件 = function(event){  
    event = event || window.event;  
};  
 

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

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

默认情况下当前的页面比可见窗口稍大,可以认为网页边上的滚动条已经不属于可见窗口的范围了,属于当前页面的范围

image-20211116222423806

image-20211116222938381

练习

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>
	<style type="text/css">
		#box1 {
			width: 100px;
			height: 100px;
			background-color: red;
			/*
				 * 开启box1的绝对定位
				 */
			position: absolute;
		}
	</style>

	<script type="text/javascript">
		window.onload = function () {

			//获取box1
			var box1 = document.getElementById("box1");
			//绑定鼠标移动事件
			document.onmousemove = function (event) {

				//解决兼容问题
				event = event || window.event;

				//获取到鼠标的坐标
				/*
				 * clientX和clientY
				 * 	用于获取鼠标在当前的可见窗口的坐标
				 * div的偏移量,是相对于整个页面的
				 */
				var left = event.clientX;
				var top = event.clientY;

				//设置div的偏移量
				box1.style.left = left + "px";
				box1.style.top = top + "px";

			};
		};
	</script>
</head>

<body style="height: 1000px;width: 2000px;">
	<div id="box1"></div>
</body>

</html>

以上代码会出现鼠标和box1位置不统一的结果:

image-20211116223612617

修改:

//获取到鼠标的坐标
/*
* clientX和clientY
* 	用于获取鼠标在当前的可见窗口的坐标
* div的偏移量,是相对于整个页面的
* pageX和pageY可以获取鼠标相对于当前页面的坐标
* 	但是这个两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用
*/
var left = event.pageX;
var top = event.pageY;

但是这个两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用

再修改

//获取滚动条滚动的距离
/*
* chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取
* 火狐等浏览器认为浏览器的滚动条是html的,
*/
var st = document.body.scrollTop || document.documentElement.scrollTop;
var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
var left = event.clientX;
var top = event.clientY;

//设置div的偏移量
box1.style.top = top + st + "px";
box1.style.left = left + sl + "px";

事件的冒泡(Bubble)

事件的冒泡指的是事件向上传导,当后代元素上的事件被触发时,将会导致其祖先元素上的同类事件也会触发。
事件的冒泡大部分情况下都是有益的,如果需要取消冒泡,则需要使用事件对象来取消
可以将事件对象的cancelBubble设置为true,即可取消冒泡

例子:

元素.事件 = function(event){  
    event = event || window.event;  
    event.cancelBubble = true;  
};  

事件的委派

指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。

事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能

我们希望,只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的
我们可以尝试将其绑定给元素的共同的祖先元素

target : event中的target表示的触发事件的对象

<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8" />
	<title></title>
	<script type="text/javascript">

		window.onload = function () {

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

			//点击按钮以后添加超链接
			var btn01 = document.getElementById("btn01");
			btn01.onclick = function () {
				//创建一个li
				var li = document.createElement("li");
				li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";

				//将li添加到ul中
				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表示的触发事件的对象
				 */
				//alert(event.target);


				//如果触发事件的对象是我们期望的元素,则执行否则不执行
				if (event.target.className == "link") {
					alert("我是ul的单击响应函数");
				}

			};

		};

	</script>
</head>

<body>
	<button id="btn01">添加超链接</button>

	<ul id="u1" style="background-color: #bfa;">
		<li>
			<p>我是p元素</p>
		</li>
		<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>

事件的绑定

addEventListener()
通过这个方法也可以为元素绑定响应函数
参数:
1.事件的字符串,不要on
2.回调函数,当事件触发时该函数会被调用
3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false

使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,
这样当事件被触发时,响应函数将会按照函数的绑定顺序执行

btn01.addEventListener("click",function(){
	alert(1);
false);
				
btn01.addEventListener("click",function(){
	alert(2);
},false);

这个方法不支持IE8及以下的浏览器

attachEvent()

在IE8中可以使用attachEvent()来绑定事件
参数:
1.事件的字符串,要on
2.回调函数

这个方法也可以同时为一个事件绑定多个处理函数,
不同的是它是后绑定先执行,执行顺序和addEventListener()相反

//先执行alert(2),再执行alert(1)
<script>
btn01.attachEvent("onclick",function(){  
alert(1);  
});  
  
btn01.attachEvent("onclick",function(){  
alert(2);  
});	  
<script>
  
//定义一个函数,用来为指定元素绑定响应函数  
/*  
* addEventListener()中的this,是绑定事件的对象  
* attachEvent()中的this,是window  
*  需要统一两个方法this  
*/  

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

事件的传播

关于事件的传播网景公司和微软公司有不同的理解
微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,
然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,
然后在向内传播给后代元素
W3C综合了两个公司的方案,将事件传播分成了三个阶段
1.捕获阶段
在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
2.目标阶段
事件捕获到目标元素,捕获结束开始在目标元素上触发事件
3.冒泡阶段
事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件

如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true
一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false

IE8及以下的浏览器中没有捕获阶段

image-20211117081339819

常用事件

鼠标事件

拖拽事件

<!DOCTYPE html>  
    <html>  
    <head>  
    <meta charset="UTF-8">  
        <title></title>  
<style type="text/css">  
  
    #box1{  
width: 100px;  
height: 100px;  
background-color: red;  
position: absolute;  
}  
  
#box2{  
width: 100px;  
height: 100px;  
background-color: yellow;  
position: absolute;  
  
left: 200px;  
top: 200px;  
}  
  
    </style>  
  
<script type="text/javascript">  
  
    window.onload = function(){  
    /*  
				 * 拖拽box1元素  
				 *  - 拖拽的流程  
				 * 		1.当鼠标在被拖拽元素上按下时,开始拖拽  onmousedown  
				 * 		2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove  
				 * 		3.当鼠标松开时,被拖拽元素固定在当前位置	onmouseup  
				 */  
  
    //获取box1  
    var box1 = document.getElementById("box1");  
    var box2 = document.getElementById("box2");  
    var img1 = document.getElementById("img1");  
  
    //开启box1的拖拽  
    drag(box1);  
    //开启box2的  
    drag(box2);  
  
    drag(img1);  
  
};  
  
/*  
			 * 提取一个专门用来设置拖拽的函数  
			 * 参数:开启拖拽的元素  
			 */  
function drag(obj){  
    //当鼠标在被拖拽元素上按下时,开始拖拽  onmousedown  
    obj.onmousedown = function(event){  
  
        //设置box1捕获所有鼠标按下的事件  
        /*  
					 * setCapture()  
					 * 	- 只有IE支持,但是在火狐中调用时不会报错,  
					 * 		而如果使用chrome调用,会报错  
					 */  
        /*if(box1.setCapture){  
						box1.setCapture();  
					}*/  
        obj.setCapture && obj.setCapture();  
  
  
        event = event || window.event;  
        //div的偏移量 鼠标.clentX - 元素.offsetLeft  
        //div的偏移量 鼠标.clentY - 元素.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";  
  
        };  
  
        //为document绑定一个鼠标松开事件  
        document.onmouseup = function(){  
            //当鼠标松开时,被拖拽元素固定在当前位置	onmouseup  
            //取消document的onmousemove事件  
            document.onmousemove = null;  
            //取消document的onmouseup事件  
            document.onmouseup = null;  
            //当鼠标松开时,取消对事件的捕获  
            obj.releaseCapture && obj.releaseCapture();  
        };  
  
 /*  
* 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,  
* 	此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,  
* 	如果不希望发生这个行为,则可以通过return false来取消默认行为  
*   
* 但是这招对IE8不起作用  
*/  
        return false;  
    };  
}  
  
  
</script>  
</head>  
<body>  
  
    我是一段文字  
  
<div id="box1"></div>  
  
<div id="box2"></div>  
  
<img src="img/an.jpg" id="img1" style="position: absolute;"/>  
    </body>  
</html>  


image-20211117131502291

滚轮事件:

<!DOCTYPE html>  
    <html>  
    <head>  
    <meta charset="UTF-8">  
        <title></title>  
<style type="text/css">  
  
    #box1{  
width: 100px;  
height: 100px;  
background-color: red;  
}  
  
    </style>  
<script type="text/javascript">  
  
    window.onload = function(){  
  
  
    //获取id为box1的div  
    var box1 = document.getElementById("box1");  
  
    //为box1绑定一个鼠标滚轮滚动的事件  
    /*  
				 * onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发,  
				 * 	但是火狐不支持该属性  
				 *   
				 * 在火狐中需要使用 DOMMouseScroll 来绑定滚动事件  
				 * 	注意该事件需要通过addEventListener()函数来绑定  
				 */  
  
  
    box1.onmousewheel = function(event){  
  
        event = event || window.event;  
  
  
        //event.wheelDelta 可以获取鼠标滚轮滚动的方向  
        //向上滚 120   向下滚 -120  
        //wheelDelta这个值我们不看大小,只看正负  
  
        //alert(event.wheelDelta);  
  
        //wheelDelta这个属性火狐中不支持  
        //在火狐中使用event.detail来获取滚动的方向  
        //向上滚 -3  向下滚 3  
        //alert(event.detail);  
  
  
        /*  
					 * 当鼠标滚轮向下滚动时,box1变长  
					 * 	当滚轮向上滚动时,box1变短  
					 */  
        //判断鼠标滚轮滚动的方向  
        if(event.wheelDelta > 0 || event.detail < 0){  
            //向上滚,box1变短  
            box1.style.height = box1.clientHeight - 10 + "px";  
  
        }else{  
            //向下滚,box1变长  
            box1.style.height = box1.clientHeight + 10 + "px";  
        }  
  
        /*  
					 * 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false  
					 * 需要使用event来取消默认行为event.preventDefault();  
					 * 但是IE8不支持event.preventDefault();这个玩意,如果直接调用会报错  
					 */  
        event.preventDefault && event.preventDefault();  
  
  
        /*  
					 * 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,  
					 * 这是浏览器的默认行为,如果不希望发生,则可以取消默认行为  
					 */  
        return false;  
  
  
  
  
    };  
  
    //为火狐绑定滚轮事件  
    bind(box1,"DOMMouseScroll",box1.onmousewheel);  
  
  
};  
  
  
function bind(obj , eventStr , callback){  
    if(obj.addEventListener){  
        //大部分浏览器兼容的方式  
        obj.addEventListener(eventStr , callback , false);  
    }else{  
        /*  
					 * this是谁由调用方式决定  
					 * callback.call(obj)  
					 */  
        //IE8及以下  
        obj.attachEvent("on"+eventStr , function(){  
            //在匿名函数中调用回调函数  
            callback.call(obj);  
        });  
    }  
}  
  
</script>  
</head>  
<body style="height: 2000px;">  
  
    <div id="box1"></div>  
  
</body>  
</html>  

键盘事件

键盘事件:
onkeydown
按键被按下
对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发
当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快,这种设计是为了防止误操作的发生。
onkeyup
按键被松开

键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document

  • 键盘对象的属性:

    • keyCode

      可以通过keyCode来获取按键的编码通过它可以判断哪个按键被按下
      除了keyCode,事件对象中还提供了几个属性

    • altKey

    • ctrlKey

    • shiftKey
      这个三个用来判断alt 、ctrl 和 shift是否被按下如果按下则返回true,否则返回false

      注意:这三个按键比较特殊可以结合其他按键一起按下,浏览器识别为一次单独的事件;

      ​ 其他按键只能单独按下,若多个按键一起按下浏览器识别为俩次事件

      //判断一个y是否被按下
      //判断y和ctrl是否同时被按下
      if(event.keyCode === 89 && event.ctrlKey){
      	console.log("ctrl和y都被按下了");
      }
      
      //以下的if语句永远为false
      //判断yx和y是否同时被按下,俩次事件---》每次事件的keyCode只有一个值
      if(event.keyCode ==88 && event.keyCode == 89){
          console.log("comming!!!")
      }
      

文本框中不能输入数字

//获取input
var input = document.getElementsByTagName("input")[0];
input.onkeydown = function(event){
event = event || window.event;
					
//使文本框中不能输入数字
if(event.keyCode >= 48 && event.keyCode <= 57){
    //在文本框中输入内容,属于onkeydown的默认行为
    //如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中
    return false;
}

练习:使div可以根据不同的方向键向不同的方向移动

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>
	<style type="text/css">
		#box1 {
			width: 100px;
			height: 100px;
			background-color: red;
			position: absolute;
		}
	</style>

	<script type="text/javascript">

		//使div可以根据不同的方向键向不同的方向移动
		/*
		 * 按左键,div向左移
		 * 按右键,div向右移
		 * 。。。
		 */
		window.onload = function () {
			var box1 = document.getElementById("box1");
			//为document绑定一个按键按下的事件
			document.onkeydown = function (event) {
				event = event || window.event;

				//定义一个变量,来表示移动的速度
				var speed = 10;

				//当用户按了ctrl以后,速度加快
				if (event.ctrlKey) {
					speed = 50;
				}

				/*
				 * 37 左
				 * 38 上
				 * 39 右
				 * 40 下
				 */
				switch (event.keyCode) {
					case 37:
						//alert("向左"); left值减小
						box1.style.left = box1.offsetLeft - speed + "px";
						break;
					case 39:
						//alert("向右");
						box1.style.left = box1.offsetLeft + speed + "px";
						break;
					case 38:
						//alert("向上");
						box1.style.top = box1.offsetTop - speed + "px";
						break;
					case 40:
						//alert("向下");
						box1.style.top = box1.offsetTop + speed + "px";
						break;
				}

			};

		};
	</script>
</head>

<body>
	<div id="box1"></div>
</body>
</html>

BOM

浏览器对象模型(browser object model)
BOM可以使我们通过JS来操作浏览器
在BOM中为我们提供了一组对象,用来完成对浏览器的操作
BOM对象
Window
代表的是整个浏览器的窗口,同时window也是网页中的全局对象
Navigator
代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
Location
代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
History
代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录
由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页,而且该操作只在当次访问时有效
Screen
代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息

这些BOM对象在浏览器中都是作为window对象的属性保存的,
可以通过window对象来使用,也可以直接使用

代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器,由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了,一般我们只会使用userAgent来判断浏览器的信息,userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,不同的浏览器会有不同的userAgent

var ua = navigator.userAgent;
console.log(ua);
if(/firefox/i.test(ua)){
	alert("你是火狐!!!");
}else if(/chrome/i.test(ua)){
	alert("你是Chrome");
}else if(/msie/i.test(ua)){
	alert("你是IE浏览器~~~");
    
/*
 * 如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息
 * 比如:ActiveXObject
 */
}else if("ActiveXObject" in window){
	alert("你是IE11,枪毙了你~~~");
}

火狐的userAgent
Mozilla5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko20100101 Firefox50.0

Chrome的userAgent
Mozilla5.0 (Windows NT 6.1; Win64; x64) AppleWebKit537.36 (KHTML, like Gecko) Chrome52.0.2743.82 Safari537.36

IE8
Mozilla4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)

IE9
Mozilla5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)

IE10
Mozilla5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)

IE11
Mozilla5.0 (Windows NT 6.1; WOW64; Trident7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko

History

对象可以用来操作浏览器向前或向后翻页
length
属性,可以获取到当前访问的链接数量
back()
可以用来回退到上一个页面,作用和浏览器的回退按钮一样
forward()
可以跳转下一个页面,作用和浏览器的前进按钮一样
go()
可以用来跳转到指定的页面
它需要一个整数作为参数
1:表示向前跳转一个页面 相当于forward()
2:表示向前跳转两个页面
-1:表示向后跳转一个页面
-2:表示向后跳转两个页面

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>
	<script type="text/javascript">
		/*
		 * History
		 * 	- 对象可以用来操作浏览器向前或向后翻页
		 */
		window.onload = function () {

			//获取按钮对象
			var btn = document.getElementById("btn");

			btn.onclick = function () {
				/*
				 * length
				 * 	- 属性,可以获取到当成访问的链接数量
				 */
				//alert(history.length);

				/*
				 * back()
				 * 	- 可以用来回退到上一个页面,作用和浏览器的回退按钮一样
				 */
				//history.back();

				/*
				 * forward()
				 * 	- 可以跳转下一个页面,作用和浏览器的前进按钮一样
				 */
				// history.forward();

				/*
				 * go()
				 * 	- 可以用来跳转到指定的页面
				 * 	- 它需要一个整数作为参数
				 * 		1:表示向前跳转一个页面 相当于forward()
				 * 		2:表示向前跳转两个页面
				 * 		-1:表示向后跳转一个页面
				 * 		-2:表示向后跳转两个页面
				 */
				history.go(1);
			};

		};

	</script>
</head>

<body>

	<button id="btn">点我一下</button>

	<h1>History</h1>

	<a href="01.BOM.html">去BOM</a>
</body>

</html>

Location

该对象中封装了浏览器的地址栏的信息
如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)

alert(location);

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

location = “http:www.baidu.com”;
location = “01.BOM.html”;

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

location.assign("http://www.baidu.com");

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

location.reload(true);

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

location.replace("01.BOM.html");

定时器

setInterval()
定时调用
可以将一个函数,每隔一段时间执行一次
参数:
1.回调函数,该函数会每隔一段时间被调用一次
2.每次调用间隔的时间,单位是毫秒

返回值:
返回一个Number类型的数据
这个数字用来作为定时器的唯一标识

clearInterval()

可以用来关闭一个定时器
方法中需要一个定时器的标识作为参数,这样将关闭对应的定时器

clearInterval()可以接收任意参数,
如果参数是一个有效的定时器的标识,则停止对应的定时器
如果参数不是一个有效的标识,则什么也不做

var num = 1;  
var timer = setInterval(function() {  
	count.innerHTML = num++;  
	if(num == 11) {  
		//关闭定时器  
		clearInterval(timer);  
	}  
}, 1000); 

setTimeout(延时调用)

延时调用:一个函数不马上执行,而是隔一段时间以后再执行,而且只会执行一次
延时调用和定时调用的区别,定时调用会执行多次,而延时调用只会执行一次
延时调用和定时调用实际上是可以互相代替的,在开发中可以根据自己需要去选择

var timer = setTimeout(function(){undefined
console.log(num++);
},3000); 

//使用clearTimeout()来关闭一个延时调用
clearTimeout(timer);

JSON

JavaScript Object Notation JS对象表示法

JS中的对象只有JS自己认识,其他的语言都不认识
JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,并且可以转换为任意语言中的对象,JSON在开发中主要用来数据的交互
JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号,其他的和JS语法一致
JSON分类:
1.对象 {}
2.数组 []

JSON中允许的值:
1.字符串
2.数值
3.布尔值
4.null
5.对象
6.数组

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

json --> js对象

/*
* json --> js对象
* 	 JSON.parse()
* 		- 可以将以JSON字符串转换为js对象
* 		- 它需要一个JSON字符串作为参数,会将该字符串转换为JS对象并返回
*/

JS对象 ---> JSON

/*
* JS对象 ---> JSON
* 	JSON.stringify()
* 		- 可以将一个JS对象转换为JSON字符串
* 		- 需要一个js对象作为参数,会返回一个JSON字符串
*/

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

//  json2.js
if (typeof JSON !== "object") {
    JSON = {};
}

(function () {
    "use strict";

    var rx_one = /^[\],:{}\s]*$/;
    var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
    var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
    var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
    var rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
    var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10
            ? "0" + n
            : n;
    }

    function this_value() {
        return this.valueOf();
    }

    if (typeof Date.prototype.toJSON !== "function") {

        Date.prototype.toJSON = function () {

            return isFinite(this.valueOf())
                ? this.getUTCFullYear() + "-" +
                f(this.getUTCMonth() + 1) + "-" +
                f(this.getUTCDate()) + "T" +
                f(this.getUTCHours()) + ":" +
                f(this.getUTCMinutes()) + ":" +
                f(this.getUTCSeconds()) + "Z"
                : null;
        };

        Boolean.prototype.toJSON = this_value;
        Number.prototype.toJSON = this_value;
        String.prototype.toJSON = this_value;
    }

    var gap;
    var indent;
    var meta;
    var rep;


    function quote(string) {

        // If the string contains no control characters, no quote characters, and no
        // backslash characters, then we can safely slap some quotes around it.
        // Otherwise we must also replace the offending characters with safe escape
        // sequences.

        rx_escapable.lastIndex = 0;
        return rx_escapable.test(string)
            ? "\"" + string.replace(rx_escapable, function (a) {
                var c = meta[a];
                return typeof c === "string"
                    ? c
                    : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
            }) + "\""
            : "\"" + string + "\"";
    }


    function str(key, holder) {

        // Produce a string from holder[key].

        var i;          // The loop counter.
        var k;          // The member key.
        var v;          // The member value.
        var length;
        var mind = gap;
        var partial;
        var value = holder[key];

        // If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === "object" &&
            typeof value.toJSON === "function") {
            value = value.toJSON(key);
        }

        // If we were called with a replacer function, then call the replacer to
        // obtain a replacement value.

        if (typeof rep === "function") {
            value = rep.call(holder, key, value);
        }

        // What happens next depends on the value's type.

        switch (typeof value) {
            case "string":
                return quote(value);

            case "number":

                // JSON numbers must be finite. Encode non-finite numbers as null.

                return isFinite(value)
                    ? String(value)
                    : "null";

            case "boolean":
            case "null":

                // If the value is a boolean or null, convert it to a string. Note:
                // typeof null does not produce "null". The case is included here in
                // the remote chance that this gets fixed someday.

                return String(value);

            // If the type is "object", we might be dealing with an object or an array or
            // null.

            case "object":

                // Due to a specification blunder in ECMAScript, typeof null is "object",
                // so watch out for that case.

                if (!value) {
                    return "null";
                }

                // Make an array to hold the partial results of stringifying this object value.

                gap += indent;
                partial = [];

                // Is the value an array?

                if (Object.prototype.toString.apply(value) === "[object Array]") {

                    // The value is an array. Stringify every element. Use null as a placeholder
                    // for non-JSON values.

                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || "null";
                    }

                    // Join all of the elements together, separated with commas, and wrap them in
                    // brackets.

                    v = partial.length === 0
                        ? "[]"
                        : gap
                            ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
                            : "[" + partial.join(",") + "]";
                    gap = mind;
                    return v;
                }

                // If the replacer is an array, use it to select the members to be stringified.

                if (rep && typeof rep === "object") {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        if (typeof rep[i] === "string") {
                            k = rep[i];
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (
                                    gap
                                        ? ": "
                                        : ":"
                                ) + v);
                            }
                        }
                    }
                } else {

                    // Otherwise, iterate through all of the keys in the object.

                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (
                                    gap
                                        ? ": "
                                        : ":"
                                ) + v);
                            }
                        }
                    }
                }

                // Join all of the member texts together, separated with commas,
                // and wrap them in braces.

                v = partial.length === 0
                    ? "{}"
                    : gap
                        ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
                        : "{" + partial.join(",") + "}";
                gap = mind;
                return v;
        }
    }

    // If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== "function") {
        meta = {    // table of character substitutions
            "\b": "\\b",
            "\t": "\\t",
            "\n": "\\n",
            "\f": "\\f",
            "\r": "\\r",
            "\"": "\\\"",
            "\\": "\\\\"
        };
        JSON.stringify = function (value, replacer, space) {

            // The stringify method takes a value and an optional replacer, and an optional
            // space parameter, and returns a JSON text. The replacer can be a function
            // that can replace values, or an array of strings that will select the keys.
            // A default replacer method can be provided. Use of the space parameter can
            // produce text that is more easily readable.

            var i;
            gap = "";
            indent = "";

            // If the space parameter is a number, make an indent string containing that
            // many spaces.

            if (typeof space === "number") {
                for (i = 0; i < space; i += 1) {
                    indent += " ";
                }

                // If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === "string") {
                indent = space;
            }

            // If there is a replacer, it must be a function or an array.
            // Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== "function" &&
                (typeof replacer !== "object" ||
                    typeof replacer.length !== "number")) {
                throw new Error("JSON.stringify");
            }

            // Make a fake root object containing our value under the key of "".
            // Return the result of stringifying the value.

            return str("", { "": value });
        };
    }


    // If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== "function") {
        JSON.parse = function (text, reviver) {

            // The parse method takes a text and an optional reviver function, and returns
            // a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

                // The walk method is used to recursively walk the resulting structure so
                // that modifications can be made.

                var k;
                var v;
                var value = holder[key];
                if (value && typeof value === "object") {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


            // Parsing happens in four stages. In the first stage, we replace certain
            // Unicode characters with escape sequences. JavaScript handles many characters
            // incorrectly, either silently deleting them, or treating them as line endings.

            text = String(text);
            rx_dangerous.lastIndex = 0;
            if (rx_dangerous.test(text)) {
                text = text.replace(rx_dangerous, function (a) {
                    return "\\u" +
                        ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

            // In the second stage, we run the text against regular expressions that look
            // for non-JSON patterns. We are especially concerned with "()" and "new"
            // because they can cause invocation, and "=" because it can cause mutation.
            // But just to be safe, we want to reject all unexpected forms.

            // We split the second stage into 4 regexp operations in order to work around
            // crippling inefficiencies in IE's and Safari's regexp engines. First we
            // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
            // replace all simple value tokens with "]" characters. Third, we delete all
            // open brackets that follow a colon or comma or that begin the text. Finally,
            // we look to see that the remaining characters are only whitespace or "]" or
            // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.

            if (
                rx_one.test(
                    text
                        .replace(rx_two, "@")
                        .replace(rx_three, "]")
                        .replace(rx_four, "")
                )
            ) {

                // In the third stage we use the eval function to compile the text into a
                // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
                // in JavaScript: it can begin a block or an object literal. We wrap the text
                // in parens to eliminate the ambiguity.

                j = eval("(" + text + ")");

                // In the optional fourth stage, we recursively walk the new structure, passing
                // each name/value pair to a reviver function for possible transformation.

                return (typeof reviver === "function")
                    ? walk({ "": j }, "")
                    : j;
            }

            // If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError("JSON.parse");
        };
    }
}());

练习

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>

	<!--
			如果需要兼容IE7及以下的JSON操作,则可以通过引入一个外部的js文件来处理
		-->
	<script type="text/javascript" src="js/json2.js"></script>
	<script type="text/javascript">

		/*
		 * JSON
		 * 	- JS中的对象只有JS自己认识,其他的语言都不认识
		 * 	- JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,
		 * 		并且可以转换为任意语言中的对象,JSON在开发中主要用来数据的交互
		 * 	- JSON
		 * 		- JavaScript Object Notation JS对象表示法
		 * 		- JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号
		 * 			其他的和JS语法一致
		 * 		JSON分类:
		 * 			1.对象 {}
		 * 			2.数组 []
		 * 
		 * 		JSON中允许的值:
		 * 			1.字符串
		 * 			2.数值
		 * 			3.布尔值
		 * 			4.null
		 * 			5.对象
		 * 			6.数组
		 */

		//创建一个对象


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

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

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

		/*
		 * 将JSON字符串转换为JS中的对象
		 * 	在JS中,为我们提供了一个工具类,就叫JSON
		 * 	这个对象可以帮助我们将一个JSON转换为JS对象,也可以将一个JS对象转换为JSON
		 */

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

		/*
		 * json --> js对象
		 * 	 JSON.parse()
		 * 		- 可以将以JSON字符串转换为js对象
		 * 		- 它需要一个JSON字符串作为参数,会将该字符串转换为JS对象并返回
		 */

		var o = JSON.parse(json);
		var o2 = JSON.parse(arr);

		//console.log(o.gender);
		//console.log(o2[1]);

		var obj3 = { name: "猪八戒", age: 28, gender: "男" };


		/*
		 * JS对象 ---> JSON
		 * 	JSON.stringify()
		 * 		- 可以将一个JS对象转换为JSON字符串
		 * 		- 需要一个js对象作为参数,会返回一个JSON字符串
		 */

		var str = JSON.stringify(obj3);
		//console.log(str);

		/*
		 * JSON这个对象在IE7及以下的浏览器中不支持,所以在这些浏览器中调用时会报错
		 */


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

		JSON.parse(str3);
	</script>
</head>

<body>
</body>

</html>
posted @ 2021-11-23 23:26  努力&选择  阅读(90)  评论(0)    收藏  举报