概述

JS是一种脚本语言,JS的目标程序都是以普通文本的形式保存,用记事本是可以直接打开的。

JS运行在浏览器中,浏览器有执行JS代码的内核;JS主要用来操作HTML中的节点,产生动态效果。

JS是网景公司开发的,JS之父是布兰登艾奇;前身叫LiveScript。网景开发JS的目的是占领浏览器市场,网景公司有一个浏览器 Navigator 领航者浏览器;JS是为领航者浏览器专门打造的。微软为了抢夺市场开发了JScript,只支持IE浏览器。

JS包括:ECMAScript、DOM、BOM

  1. ECMAScript是ECMA指定的262标准,是JS的核心语法。
  2. DOM是通过JS对HTML的DOM节点操作。DOM规范是W3C指定的。(网页中的元素/节点)
  3. BOM是对浏览器本身操作,例如:前进、后退、地址栏、关闭窗口。BOM缺少规范。(浏览器本身)

嵌入JS的三种方式

JS是一种事件驱动型的编程语言,通常都是在事件源发出信号之后执行代码。

事件包括很多:鼠标单击click、鼠标经过mouseover等。

并且在JS当中,任何一个事件都有对应的事件句柄;例如:

click对应的事件句柄是onclick;mouseover对应的事件句柄是onmouseover

所有的事件句柄都是以标签的属性形式存在。

例如 :input button就有一个onclick属性

只要用户点击了button按钮,发生了鼠标单击事件;注册在onclick事件当中的JS代码会被执行(浏览器执行)。

<input type="button" value="hello" onclick="doSome"/>

按钮是事件源,鼠标单击他就会发生事件;这还需要一个事件监听器去监听事件的发生:浏览器一直监听着这个事件什么时候发生

浏览器打开的时候就会把onclick后面的代码注册给onclick事件句柄。等待该按钮的click事件发生,只要发生后面的代码就会被事件监听器调用。

事件发生需要三要素:事件源、事件、监听器。

行内事件

JS中有一个内置的BOM对象,可以直接拿来使用,全部小写:window

其中window对象有一个函数:alert 这个函数专门用来弹出对话框。

<input type="button" value="hello" onclick='window.alert("hello world!");
											window.alert("hello kitty");
											window.alert("hello China");'/>

window可以省略:

<input type="button" value="hello" onclick="alert('hello world!');"/>

script脚本块

在脚本块中写的代码在页面打开的时候自上而下的顺序依次执行

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>脚本块</title>
	</head>
	<body>
		
		<input type="button" value="button1">
		
		<script type="text/javascript">
			alert("hello world");
			alert("hello zhangsan");
			alert("hello lisa");
		</script>
		
		<input type="button" value="button2">
	</body>
</html>

使用火狐浏览器可以观察到效果:先生成9行的button1,再产生三个弹窗,最后生产button2

引入外部js文件

有外部js文件:1.js

alert("hello world");
alert("hello kitty");

通过script标签引入:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<!--引入外部JS文件 文件中的代码遵循自上而下依次执行-->
		<script src="js/1.js" type="text/javascript" charset="utf-8"></script>
	</body>
</html>

但是注意

  1. 引入外部js文件的script标签体中不能写js代码,不会执行
  2. script标签不能自闭合

输出

document.write() //写入HTML的body
window.alert()   //弹窗
console.log()    //写入浏览器控制台

变量与函数

变量

声明:

var i = 10;

var a , b , c = 300;

声明三个变量a,b,c,并且c赋值300,其中a和b变量没有赋值,系统赋默认值undefined

undefined在js中是一个具体的值

js是一种弱类型语言,没有编译阶段,浏览器打开就开始解释执行。所以在JS中不需要指定变量类型,程序在运行过程中赋什么类型的值,变量就是什么数据类型,而且变量的数据类型是可变的。

var i;
i = 100; //到这里i是整数型
i = false;	//到这里i是布尔类型
i = 3.14;	//i是double类型
i = new Object();

变量的声明

  • let声明变量

  • const声明常量,不能重新赋值(运行报错)

  • var可以重复声明,let不可以

  • let没有变量提升,必须先声明

函数

普通函数

   function add(a,b){  
    return a + b;  
   }  
  
let result1 = add(1,2);  
let result2 = add();  
let result3 = add(1,2,3);  
   console.log(result1)  
   console.log(result2)  
   console.log(result3)
  • JS是弱类型语言,定义函数时形参和返回值都无需指定类型
  • 函数的声明优先级很高,打开网页的时候网页中所有的函数进行声明

调用方法可以随意传参

JS的特性:调用方法可以随意传参

function doSome(x,y) {  
    console.log('x = ' + x + ', y = ' + y);  
}  
  
doSome();      //x = undefined, y = undefined  
doSome(1);     //x = 1, y = undefined  
doSome(1,2);   //x = 1, y = 2  
doSome(1,2,3); //x = 1, y = 2

匿名函数

  • 匿名函数没有名称,不能直接通过函数名来调用,而是通过变量表达式来调用
  • 匿名函数定义可以通过两种方式:函数表达式 和 箭头函数
函数表达式
//需要使用变量接收这个function,function在JS中也是一种数据类型,所以可以用变量接收  
let add = function (a, b) {  
    return a + b;  
}  
  
let result = add(1,2);  
console.log(result)
箭头函数
let add = (a, b) => {  
    return a + b;  
}  
  
let result = add(1,2);  
console.log(result)

自执行函数

匿名函数定义后可以立刻执行,被称为自执行函数

//自执行函数  
let result = (function (a, b){  
    return a + b;  
})(1,2);  
  
console.log(result)

function外的()代表函数要立即执行,(1,2)代表执行该函数传入的参数

//自执行函数  
let result = ((a, b) => {  
    return a + b;  
})(1,2);  
  
console.log(result)

js没有方法重载

			function test(a,b){
				alert("test(a,b)");
			}
			function test(){
				alert("test()");
			}
			
			test(1,2); /* 指定的永远都是最后定义的方法*/
			test();

局部变量和全局变量

  • 函数体之外声明的变量即为全局变量
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>在函数体之外声明的变量 叫做全局变量</title>
	</head>
	<body>
		<script>
			/* 全局变量 */
			var username = "zhangsan";
			
			function sayHello(){
				/* 局部变量 */
				var username = "lisi";
				alert(username); /* 输出lisi*/
			}
			
			alert(username); /* 输出zhangsan*/
		</script>
		
		<input type="button" value="hello" onclick="sayHello()">
	</body>
</html>
  • 不用用var定义在函数体中的变量,在函数被调用后成为全局变量
			function doSome(){
				emaile = "zhangsan@123.com";
			}
			
			doSome();
			alert(emaile); //zhangsan@123.com

如果函数没有调用,就是该变量未定义,报错:

			function doSome(){
				emaile = "zhangsan@123.com";
				age;
			}
			
			doSome();

			alert(age); /*报错:age未定义*/

数据类型

ES6之前有6种数据类型:

  • 字符串 var str = "hello world"

  • 数字 var num = 1

  • 布尔类型 var bool = true

  • Object类型 var obj = {name:"zhangsan",age:18}

  • 默认值undefined var ud ;

  • 空值var kong = null;

其中Undefined、Number、String、Boolean、Null都属于原始类型,或者叫做基本数据类型;其中Object属于引用数据类型(对象类型)。

在ES6后引入了:Symbol、Bigint;一共八种类型

typeof可以动态获取数据类型

要求:计算两个数字的和,要求x和y必须都是数字类型,如果不是要提示错误信息

typeof的运算结果是以下6个字符串之一:

  1. “undefined”

  2. “number”

  3. “string”

  4. “boolean”

  5. “object”

  6. “function”

add = function (a,b) {  
    if (typeof a === "number" && typeof b === "number"){  
       return a + b;  
    }else {  
       throw new Error("a或b不为数字");  
    }  
}  
  
console.log(add(1, 2));  
console.log(add('1', 2));  
console.log(add(1, 2));
var i;
console.log(typeof i); /*undefined*/

var k = 3.14;
conlose.log(typeof k); /*number*/

var username = "zhangsan";
console.log(typeof username); /*string*/

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

var v = null;
console.log(typeof v); /*object*/

console.log(typeof sum) /*function*/

var newObj = new Object();
console.log(typeof newObj); /*object*/

null是一种原始数据类型,但是null的typeof运算结果是object,因为null一定代表了某个对象为空

undefined

  • 只有一个值 就是undefined

  • 当一个变量声明后没有手动赋值,系统默认赋值undefined

var k = undefined;  
  
console.log(k)  //undefined  
console.log(k == undefined)  //undefined  
console.log(k === undefined) //undefined

Null

  • Null类型也是属于原始类型
  • Null类型只有一个值:null
  • typeof null 的运算结果是object
var k = null;  
console.log(k)          //null  
console.log(k == null)  //true  
console.log(k === null) //true  
console.log(typeof k === 'object') // true

Number

  • Number类型属于原始类型

  • Number类型的值包括整数和浮点数

  • Number类型的值包括:NaNInfinity(无穷大)

Infinity

var retValue = 100 / 0;
console.log(retValue); /*Infinity*/

NaN

当一个数学表达式的运算结果本应该返回一个数字,但是最终无法返回一个数字的时候,结果是NaN

NaN:Not a Number不是一个数字,但NaN是一个值,属于Number类型

var k = NaN;  
console.log('k = ' + k)          //null  
console.log('typeof k = ' + typeof k) //number  
console.log('typeof k === \'object\'' + typeof k === 'object') // false
var result = 100 / "中";
console.log(result); /*NaN*/
  • NaN != NaN

isNaN()

该函数对传入的参数尝试解析为数字,如果解析成功返回false,代表是一个数字,如果解析失败返回true,表示不是一个数字

可以用来判断一个数据是否是NaN

console.log(isNaN(8),isNaN(NaN));  //false true
	<body>
		<script>
			function sum(x,y){
				console.log(typeof x,typeof y);
				console.log(isNaN(x),isNaN(y)); /* false false*/
			}
		</script>
		<input type="button" value="sum" onclick="sum(true,100)">
	</body>
  • true被解析为1

如果传入的是非数字型字符串:

console.log(isNaN("CHINA")); /*转换字符串失败 返回true*/

如果传入的是数字型字符串

console.log(isNaN("123")); /*转换字符串成功 返回false*/

对上文程序改进:

function sum(x,y){
	/* 需要动态获取数据类型 */
	if(isNaN(x) || isNaN(y))
	alert("not a number"); 
	
	alert(x + y);/* 执行到此说明不是数字*/
}

但是还是存在问题的,如果x或y有一个数字型字符串:”123″ + 123 ,第五行得到的结果是 123123,与预期结果不符

Number()

作用:将一个非Number类型的数据转换为Number(完全解析字符串)

console.log(Number("123") + 1); /*124*/

注意:

console.log(Number("7.8元")); /*NaN 与parseInt方法得到的结果不同*/

最终的求和函数:

sum = function (a,b) {  
    if (isNaN(a) || isNaN(b)){  
       throw new Error("is NaN")  
    }  
    return Number(a) + Number(b);  
}

parseInt()函数

将字符串”123.456″转换成数字,并且只取整数位(部分解析字符串)

var s1 = "123.456";
var num = parseInt(s1);
console.log(num);
console.log(parseInt("7.8元"));  //7
console.log(parseInt("123456.呵呵")); //123456
console.log(typeof(parseInt(100,16)))  //得到 16进制的100 对应十进制整数

但是注意:如果以字符开始就会变为NaN

console.log(parseInt("元123.456")); /*NaN*/

String与Number的混合运算

  • + 操作会进行字符串拼接
  • - 操作会对字符串进行 parseInt 操作
console.log(1 + "1"); // 11
console.log(1 - "1"); //0
console.log(11 + "1" - 1) // 111 --> 110

对于非数值型字符串,进行 - 操作,得到的结果是 NaN

console.log("liu" - 1) //NaN

Math类

  • Math.floor() 向下取整参数
log(Math.floor(8.5)); // 8
  • Math.round() 四舍五入取整
log(Math.round(8.5)); // 9
  • Math.random() 生成一个 [0,1)的随机数

    • 生成 0 – 10 的随机数 Math.random() * 11
    • 生成 100 – 999 的随机数 Math.random() * 900 + 100
  • Math.ceil() 向上取整

console.log(Math.ceil(8.1)); // 9

10 / 3

console.log(10 / 3); //3.3333333333333333335

得到的结果与Java不同,等同于var i = 10 / 3,在JS中不需要指定类型,等号右边是什么类型改变量就是什么类型

浮点数运算

console.log(0.1 + 0.2) // 0.3000000000004

也就是说在JavaScript中不能直接判断浮点数

console.log((0.1 + 0.2) == 0.3) //false

String

let str1 = "";
let str2 = '';
let str3 = `${}`;

运算符

比较运算符

===== 的区别

  • == 在比较的时候判断值是否相等,会进行类型转换
  • ===比较的时候判断值是否相等,不会进行类型转换
let age = 20;  
let _age = '20';  
let $age = 20;  
  
alert(age == _age);   //true
alert(age === _age);  //false
alert(age === $age);  //true

类型转换

某些运算被执行时,系统内部自动将数据类型进行转换,这种转换被称为隐式转换

  • 字符串与数字的隐式转换
    • 左右有一个是字符串,自动将另一个转换为字符串
  1. 除了 + 的运算符, – / * 都会自动将字符串转换为数字(NaN)
  • 其他类型与布尔的隐式转换
  1. Number: 0 和 NaN 为false,其他均为true
  2. string:空字符串为false,其他均为true
  3. null和undefined为false
//类型转换 - 字符串 <-> 数字  
alert(typeof ('10' - 1));  //number  
alert(typeof ('10' + 1));  //string  
alert(parseInt('123'));    //123  
alert(parseInt('12A3'));   //12  
alert(parseInt('A123'));   //undefined
//类型转换 - 其他类型转为boolean  
if(0){  
    alert("0 转换为false");   //0 转为 false}  
if(NaN){                     //NaN 转为 false    
	alert("NaN 转换为false");  
}  
if(1){  
    alert("除0和NaN其他数字都转为 true");  
}  
  
if(""){                      //空字符串为false  
    alert("空字符串为 false, 其他都是true");  
}  
  
if(null){                    //null为false  
    alert("null 转化为false");  
}  
if(undefined){               //undefined为false  
    alert("undefined 转化为false");  
}

类的定义

Object

在JS中内置了一个类型 Object,可以将Object类型看作所有对象的超类/基类;在JS中默认定义的类型若无特殊说明默认继承Object

Object.keys()

Object.ownPropertyNames()

Object.defineProperty()

Object.defineProperty(
	新增对象,
    '属性名',
    {
        配置项
    }
)

配置项需要设置writeable:true 指定该属性是可以修改的

为phone对象新增颜色属性:

let phone = {};  
Object.defineProperty(phone,'color',{  
    value : 'black',  
    writable : true  
});  
console.log(phone.color); //black  
  
phone.color = 'blue';  
console.log(phone.color); //blue

getter/setter方法配置项:

let phone = {};  
Object.defineProperty(phone,'color',{  
    get : function () {  
       //读取属性值的时候自动调用getter方法  
    },  
    set : function () {  
       //修改属性值的时候自动调用setter方法  
    }  
});
  • 指定了getter/setter后不能再指定value和writable

setter方法应该是有参数的,参数就是赋值时传递的数据。

其中的get方法就代表了读取属性时的返回值,当前先返回固定的值:

let phone = {};  
Object.defineProperty(phone,'color',{  
    get : function () {  
       //读取属性值的时候自动调用getter方法  
       return 'black';  
    },  
    set : function (color) {  
       //修改属性值的时候自动调用setter方法  
       console.log(color);  
    }  
});

但这样做是不满足需求的,读取的属性值必须是动态的。

如果这样设置getter/setter:

let phone = {};  
Object.defineProperty(phone,'color',{  
    get : function () {  
       //读取属性值的时候自动调用getter方法  
       //this代表调用者,phone.color的调用者就是phone  
       return this.color;  
    },  
    set : function (color) {  
       //修改属性值的时候自动调用setter方法  
       this.color = color;  
    }  
});

这样是不行的,不管调用set/get都会递归OOM,因为get方法return this.color就是在读取属性值,会调用get方法,get方法一直在递归调用,set方法亦然。

解决办法:设置一个变量记录属性值,get返回这个值,set就设置这个值

let phone = {};  
let colorObj;  
Object.defineProperty(phone,'color',{  
    get : function () {  
       //读取属性值的时候自动调用getter方法  
       //this代表调用者,phone.color的调用者就是phone  
       return colorObj;  
    },  
    set : function (color) {  
       //修改属性值的时候自动调用setter方法  
       colorObj = color;  
    }  
});

phone就是代理对象,访问phone的属性就访问到了phoneObj的属性。

定义类

第一种方式:

function 类名(形式参数列表){
    
    this.属性名 = 参数;
    this.方法名 = function(){
        
    }
}

第二种方式:

类名 = function(形式参数列表){
    
    this.属性名 = 参数;
    this.方法名 = function(){
        
    }
}

这样既是一个类,又是一个函数。

function sayHello(){
    
}
  • 如果这样调用,就是看作函数:
sayHello();
  • 如果这样调用,就是看作对象:
var obj = new sayHello();

如果没有使用new运算符调用,表示普通函数调用,不会在堆中new对象,使用new运算符调用这个函数,会在浏览器的堆内存中开辟一个对象。

function Emp(empno,ename,sal){
				this.empno = empno;
				this.ename = ename;
				this.sal = sal;
				
				this.work = ()=>{
					console.log(this.ename + " is working");
				}
			}
			
			var e0 = new Emp(); 
			e0.work(); //undefined is working
			var e = new Emp(11,"king");
			e.work(); //king is working
			var e2 = new Emp(22,"smith",800);
			e2.work(); //smith is working
					
			//扩展方法
			Emp.prototype.getSal = function(){
				return this.sal;
			}
			
			console.log(e2.getSal()); //800

访问对象的属性

也可以:引用["属性名"]

			console.log(e2["empno"]);
			console.log(e2["ename"]);
			console.log(e2["sal"]);

这样就可以使用forin遍历对象:

for (let property in emp) {  
    console.log(emp[property])   //property就是字符串
}

Array

JS中的数组相当于Java中的集合,数组长度可变并且类型可变

JS中的数组也分为静态初始化和动态初始化:

  • 静态初始化
var a = [1,2,"three",new Object()];
var a1 = []; //创建长度为0的数组对象
var a2 = [1,2,"three",new Object()]; //数组不限制数据类型	
  • 动态初始化
var a3 = new Array(5); //初始化长度为5的数组

还有一种静态初始化的方式:

var a2 = new Array(1,2,"three","four"); 

但是这样做,在只有一个参数 1 的时候两种初始化方式会混淆,ES6提出了一种新的动态初始化方式:

var a4 = Array.of(5);  //动态初始化一个长度是5的数组

注意:JS中数组的长度是可变的;JavaScript中数组下标可以越界访问:

a1[8] = "liuyibo";

此时8号位置被赋值,数组当前有9个元素,没有赋值的都是undefined

常用方法

	  //1. 定义数组  
	  let arr = [1,2,3,4,5];  
	  //可以越界访问  
      arr[10] = 'A';  //此时数组中有11个元素  
      //2. 数组属性 - length      for (let i = 0; i < arr.length; i++) {  
       console.log(arr[i]); // 打印出11个元素,包含undefined  
      }  
  
      //3. 数组方法 - forEach , map,  push , pop , unshift , shift , splice//forEach  
      arr.forEach((e) => { console.log(e) }) // 打印6个元素,不会遍历到undefined  
            //map  
      arr.map((e) => {return e + 1}).forEach((e) => { console.log(e) }) // map后遍历输出,还是6个元素  
      //push pop 模拟栈,对数组尾元素操作  
      arr.push('obj');  
	  arr.pop();  
  
	  //shift unshift  
      //与栈相反,对数组头部元素操作  
      arr.shift('shift');  
	  arr.unshift();  
  
      //reverse  反转数组  
      arr.reverse().forEach((e) => { console.log(e) });  
    
      //join 数组元素以指定参数连接为字符串返回  
      console.log(arr.join('-'));  
  
      //splice(begin, deleteCount, values ... )  
      // deleteCount = 0     添加第三个参数指定的元素  
      // deleteCount = 1..n  删除指定个数的元素  
      arr.splice(0,0,7,8,9);  
      console.log(arr);  
        
      //concat 两个数组合并为一个,返回值是新数组不会对原数组产生影响  
      //slice([begin,end))  返回数组切片  
      arr.splice(1,2).forEach((e) => { console.log(e) });  
      //无参:获得数组克隆  
      arr.splice().forEach((e) => { console.log(e) });
  • 数组的push和pop方法是模拟了栈数据结构
			var a = [1,2,3];
			a.push(false); /* 向数组中添加元素并且加到末尾*/
			for(var index in a){
				console.log(a[index]);
			}
			
			console.log(a.pop(),a.length); //false
			console.log(a.pop(),a.length); //3
			console.log(a.pop(),a.length); //2
			console.log(a.pop(),a.length); //1
			
			var arr = [1,2,3];
			arr.reverse(); /* 翻转数组*/
			for(var index in arr){
				console.log(arr[index]);
			}
			
			console.log(arr.join("$")); //3$2$1

数组遍历

		//数组循环方式
		arr["yuan"] = "lei";
		
		for(var i in arr){ //i - index 可以直接用下标 不能直接用value(不建议用)
			console.log(i + " : " + arr[i]); // for-in可以将索引为字符串的也遍历出
		}
		
		for(var v of arr){ //v - value 可以直接用value 不能直接用index(不建议用)
			console.log(arr.indexOf(v) + " : " + v); //对于重复的元素 查询出错
		}
		
		arr.forEach((v,i)=>{ // i - v 都可以使用
			console.log(i + " : " + v);
		})

String

String的创建方式有两种:

//1.
let str = new String('...');
//2.
let str = '...';
let str = "...";
let str = `...`;

属性:length

方法:

charAt() //返回指定位置的字符
indexOf() //返回指定内容出现的索引
trim()  //去除两边空格
substring() //截取字符串
      //1. 创建字符串  
	  let str = 'Hello world';  
      //2. 字符串属性 - length      for (let i = 0; i < str.length; i++) {  
       console.log(str.charAt(i));  
      }  
      //3. 字符串方法 - charAt , indexOf , trim , substring      console.log(str.indexOf('lo')); //3  
      console.log(str.trim());  //Hello world  
      console.log(str.substring(0,6)) // Hello

DOM&BOM

BOM:浏览器对象模型 Browser Object Model 通过BOM的对象和方法可以完成浏览器窗口的操作:前进、后退、关闭浏览器、修改地址栏上的信息等,BOM的顶级对象是window

DOM:文档对象模型 Document Object Model 通过DOM的对象和方法可以完成网页中元素的增删改,让网页产生动态效果,DOM的顶级对象是document

BOM

BOM:浏览器对象模型 Browser Object Model,允许JS与浏览器对话,JS将浏览器的各个部分封装为对象

  • 组成:
    • Window:浏览器窗口对象
    • Navigator:浏览器对象
    • Screen:屏幕对象
    • History:历史记录对象
    • Location:地址栏对象

Window

window.可以省略

常用方法:

  • confirm(String message): boolean:确认消息
  • alert(String message): void:提示消息
  • setTimeout(Function callbackFn,number time):指定延迟后执行一次CallbackFunction
  • setInterval(Function callbackFn,number time) :以周期调用CallbackFunction

Window.location

  • 属性:href:返回完整URL
//alert('hello world');  
  
let isConfirm = confirm('confirm?');  
if (isConfirm){  
    alert('confirm')  
}else {  
    alert('cancle')  
}  
  
//执行一次  
setTimeout(() => {  
    window.location.href = 'https://www.jd.com'  
},3000);  
  
//执行多次  
let intervalRev = setInterval(() => {  
    alert('set interval')  
},3000);  
  
clearInterval(intervalRev);

DOM

Document Object Model :文档对象模型

将HTML的各个组成部分封装为对应的对象:

  • Document:文档对象
  • Element:元素对象
  • Attribute:属性对象
  • Text:文本对象
  • Comment:注释对象

JS通过操作DOM就能对HTML进行操作,进而达成动态网页效果

  • 改变HTML元素的内容
  • 改变HTML元素的样式
  • 对HTML DOM元素事件做出反应
  • 添加或删除HTML元素

DOM对象

DOM对象就是浏览器根据HTML标签生成的JS对象

  • 所有标签属性均可在该对象上找到
  • 修改该对象的属性,自动映射到标签上

DOM核心思想:将网页内容当作对象处理

document对象:

  • 网页中所有内容封装在document对象中
  • 提供了操作网页内容的方法

操作网页内容:

  • 获取DOM元素对象
  • 操作DOM对象的属性或方法(查文档)

获取DOM对象

document.querySelector('选择器');
document.querySelectorAll('选择器');

注意:得到的是一个NodeList节点集合,是一个伪数组(有长度,有索引、无push pop等数组方法)

  <span id="sid">DOM元素1</span>  
  <span class="txt">DOM元素2</span>  
  <span class="txt">DOM元素3</span>  
  
  <script>   let spanSid = document.querySelector('#sid');  
spanSid.style.display = 'block';  
   spanSid.style.backgroundColor = 'black';  
spanSid.style.width = '300px';  
spanSid.style.height = '300px';  
  
let nodeList = document.querySelectorAll('span');  
nodeList.forEach((e) => {e.style.fontSize = '30px'})  
  </script>

发送请求的多种方式

跳转页面:

  1. 地址栏写url
  2. 超链接
  3. 提交表单
  4. window.open()
  5. window.location.href (href)可以省略
  6. document.location.href (href)可以省略

练习

  <div class="center">  
      您好, 支付完成, <span id="time">5</span> 秒之后将自动跳转至 <a href="https://www.jd.com">官网</a> 首页 ~  
  </div>  
  
  <script>      let element = document.querySelector('#time');  
let time = element.innerHTML;  
      console.log(time)  
setInterval(() => {  
    if (--time <= 0){  
       location.href = 'https://www.jd.com'  
    }else {  
       element.innerHTML = time;  
    }  
},1000);  
  </script>

JSON

JavaScript Object Notation ,JavaScript标记对象,简称JSON;是一种轻量级的数据交换格式。

轻量级体现在JSON体积小,但是能表示的数据很多。

数据交换:C语言和Java语言之间交换数据,Python和Java语言之间交换数据,JavaScript和Java之间交换数据

现代开发中,JSON和XML都可以做数据交换。XML体积大,解析难度大,语法严格;JSON解析更容易,语法相对松散。

在JS当作,JSON是以对象的形式存在

eval()

可以把一段字符串当作JS代码解释并执行

			window.eval("var i = 100");
			console.log(i); // 100

创建JSON对象

            var jsonObj = {
                    "属性名" : 属性值,
                    "属性名" : 属性值,
            }

			var emp = {
				"empno" : 7369,
				"ename" : "smith",
				"sal"	: 800,
			}

注意:在JS中, []是数组对象,{}是JSON对象。

访问对象属性:

			console.log(emp.empno);
			console.log(emp["empno"]);

所以可以使用for-in遍历json对象

属性值也可以是个json对象

		var user = {
			"name" : "zhangsan",
			"password" : "123",
			"email": "zhangsan@123.com",
			"address" :  {"city" : "beijing","street" : "daxing"}
        }
        
        console.log(user.address.city); //beijing
			var students = {
				"total"	: 3,
				"data" : [
					{"sno" : "001","sname" : "zhangsan"},
					{"sno" : "002","sname" : "lisi"},
					{"sno" : "003","sname" : "wangwu"},
						]
					}
					
			for(var i in students.data){
				with(students){
					console.log(data[i].sno + " : " + data[i].sname);
				}
				
			}

JSON交换数据

Java和JavaScript语言交换数据:Java通过JDBC连接数据库查询数据,将数据封装成JSON格式的字符串,将JSON格式的字符串传给JavaScript,JS将该字符串转换成JSON对象,这样就完成了数据的交换。

		//Java传过来的JSON格式的字符串
		var fromJavaJson = "{\"name\" : \"zhangsan\",\"age\" : 20}";
		
		//将JSON格式的字符串转换为JSON对象
		window.eval("var stu = " + fromJavaJson);
		/* "var stu = {\"name\" : \"zhangsan\",\"age\" : 20}" */
		
		console.log(stu.name + " : " + stu.age);

或者可以直接使用JSON对象的内置parse方法进行转换。

对象

      //1. 自定义JS对象  
let user = {  
    username : 'zhansgan',  
    password : '123',  
    address : {  
       province : 'HeNan',  
       city : 'ZhengZhou',  
    },  
    sing : function () {  
       alert(this.username + ' is singing')  
    }  
};  
        
      console.log(user.username);  
      console.log(user.address.province); 
      console.log(user["username"]); //这种方式也可以遍历对象 
      user.sing();

: function 可以省略

      //1. 自定义JS对象  
let user = {  
    username : 'zhansgan',  
    password : '123',  
    address : {  
       province : 'HeNan',  
       city : 'ZhengZhou',  
    },  
    sing() {  
       alert(this.username + ' is singing')  
    }  
};

遍历对象

  1. for in遍历

for-in遍历方式可以获取到对象所有可枚举的属性和方法

for in 遍历出的是字符串类型的属性名

let user = {  
    username : 'zhansgan',  
    password : '123',  
    address : {  
       province : 'HeNan',  
       city : 'ZhengZhou',  
    },  
    sing() {  
       alert(this.username + ' is singing')  
    }  
};  
  
for (let property in user) {  
    if (typeof user[property] === 'object'){  
       for (let userElementKey in user[property]) {  
          console.log('user.' + property + '.' + userElementKey + ' = ' + 
													          user[property][userElementKey]);  
       }  
    }else {  
       console.log('user.' + property + ' = ' + user[property]);  
    }  
}
  1. Object.keys(obj) 得到的是对象属性名的字符串数组
let user = {  
    username : 'zhansgan',  
    password : '123',  
    address : {  
       province : 'HeNan',  
       city : 'ZhengZhou',  
    },  
    sing() {  
       alert(this.username + ' is singing')  
    }  
};  
  
let keys = Object.keys(user);  
  
keys.forEach(key => {console.log(user[key])} )  
  
/**  
 * zhansgan 
 * 123 
 * Object city: "ZhengZhou" province: "HeNan" [[Prototype]]: Object 
 * ƒ sing() { 
 *        alert(this.username + ' is singing') 
 *     } 
 * */
  1. Object.getOwnPropertyNames(obj)
let user = {  
    username : 'zhansgan',  
    password : '123',  
    address : {  
       province : 'HeNan',  
       city : 'ZhengZhou',  
    },  
    sing() {  
       alert(this.username + ' is singing')  
    }  
};  
  
//let keys = Object.keys(user);  
  
let keys = Object.getOwnPropertyNames(user);  
  
keys.forEach(key => {console.log(user[key])} )

JSON

JSON对象:

//2. JSON对象  
let userJson = {  
 "username" : "zhansgan",  
 "password" : "123",  
 "age" : 18,  
 "gender" : true,  
 "address" : {  
  "province" : 'HeNan',  
  "city" : 'ZhengZhou',  
 },  
 "hobby" : ["smoke","drink"]  
};

JSON对象的key必须是双引号括起来的字符串,value可以是如下类型:

  • 数字
  • 字符串
  • 逻辑值
  • 数组
  • 对象
  • null

JSON格式的字符串

let jsonStr = '{"name":"Tom", "age":18, "gender": "男"}';

必须用单引号括起来整个JSON对象

  • JSON对象userJson转换为JSON格式的字符串userJsonStr:JSON.stringify(JSON obj)
      let userJson = {  
       "username" : "zhansgan",  
       "password" : "123",  
       "age" : 18,  
       "gender" : true,  
       "address" : {  
        "province" : 'HeNan',  
        "city" : 'ZhengZhou',  
       },  
       "hobby" : ["smoke","drink"]  
      };  
        
let userJsonStr = JSON.stringify(userJson);  
console.log(userJsonStr);

/**  
 * {"username":"zhansgan","password":"123","age":18,"gender":true, * "address":{"province":"HeNan","city":"ZhengZhou"}, * "hobby":["smoke","drink"]} * @type {string}  
 */
  • JSON格式字符串转换为JSON对象 JSON.parse(String jsonStr)
      //2. JSON对象  
      let userJson = {  
       "username" : "zhansgan",  
       "password" : "123",  
       "age" : 18,  
       "gender" : true,  
       "address" : {  
        "province" : 'HeNan',  
        "city" : 'ZhengZhou',  
       },  
       "hobby" : ["smoke","drink"]  
      };  
        
let userJsonStr = JSON.stringify(userJson);  
  
let parseObj = JSON.parse(userJsonStr);  
      console.log(parseObj.hobby[1]);

但是注意,JSON格式的字符串不能换行:

let jsonStr = '{"name":"Tom",' +  
  ' "age":18, "gender": "男"}';

在WebS中换行会自动变为拼接

如果不想拼接,可以使用 \

let jsonStr = '{"name":"Tom", \  
  "age":18, "gender": "男"}';

事件监听

  • 事件:HTML元素上发生的事情,比如:按钮被点击、鼠标移动到元素上、按下键盘按键
  • 事件监听:JavaScript可以在事件触发时,立刻调用一个函数做出响应,也成为 注册事件
事件源.addEventListener('事件类型', callBackFunction)

事件监听三要素:

  • 事件源
  • 事件
  • 回调函数
  <input type="button" id="btn1" value="点我一下试试1">  
  <input type="button" id="btn2" value="点我一下试试2">  
  
  <script>document.querySelector('#btn1').addEventListener('click',() => {  
    console.log('message1 from btn1')  
});  
document.querySelector('#btn1').addEventListener('click',() => {  
    console.log('message111 from btn1')  
});  
  
  
document.querySelector('#btn2').onclick = () => {  
    console.log('message2 from btn2')  
};  
document.querySelector('#btn2').onclick = () => {  
    console.log('message222 from btn2')  
};  
  
  </script>

发现:

  • addEventListener添加的事件不会被覆盖,可以添加多个事件
  • onclick 指定的事件会被覆盖,不能添加多个事件

常见事件

<form action="" style="text-align: center;">  
    <input type="text" name="username" id="username">  
    <input type="text" name="age" id="age">  
    <input id="b1" type="submit" value="提交">  
    <input id="b2" type="button" value="单击事件">  
</form>  
  
<br><br><br>  
  
<table width="800px" border="1" cellspacing="0" align="center">  
    <tr>        <th>学号</th>  
        <th>姓名</th>  
        <th>分数</th>  
        <th>评语</th>  
    </tr>    <tr align="center">  
        <td>001</td>  
        <td>张三</td>  
        <td>90</td>  
        <td>很优秀</td>  
    </tr>    <tr align="center" id="last">  
        <td>002</td>  
        <td>李四</td>  
        <td>92</td>  
        <td>优秀</td>  
    </tr></table>  
  
  
  
<script>  
    //click: 鼠标点击事件  
    document.querySelector('#b2').addEventListener('click', () => {  
        console.log("我被点击了...");  
    })  
  
    //mouseenter: 鼠标移入  
    document.querySelector('#last').addEventListener('mouseenter', () => {  
        console.log("鼠标移入了...");  
    })  
  
    //mouseleave: 鼠标移出  
    document.querySelector('#last').addEventListener('mouseleave', () => {  
        console.log("鼠标移出了...");  
    })  
  
    //keydown: 某个键盘的键被按下  
    document.querySelector('#username').addEventListener('keydown', () => {  
        console.log("键盘被按下了...");  
    })  
  
    //keydown: 某个键盘的键被抬起  
    document.querySelector('#username').addEventListener('keyup', () => {  
        console.log("键盘被抬起了...");  
    })  
  
    //blur: 失去焦点事件  
    document.querySelector('#age').addEventListener('blur', () => {  
        console.log("失去焦点...");  
    })  
  
    //focus: 元素获得焦点  
    document.querySelector('#age').addEventListener('focus', () => {  
        console.log("获得焦点...");  
    })  
  
    //input: 用户输入时触发  
    document.querySelector('#age').addEventListener('input', () => {  
        console.log("用户输入时触发...");  
    })  
  
    //submit: 提交表单事件  
    document.querySelector('form').addEventListener('submit', () => {  
        alert("表单被提交了...");  
    })  
</script>

练习一

<body>  
    <div>        <h1>用户注册</h1>  
        <form>            <label for="username">用户名:</label>  
            <input type="text" id="username" name="username" placeholder="用户名不能为空且长度在4-16个字符">  
            <span class="tip" id="name_msg"></span> <br>  
  
            <label for="phone">手机号:</label>  
            <input type="text" id="phone" name="phone" placeholder="手机号不能为空且长度为11位">  
            <span class="tip" id="phone_msg"></span>  
            <br>  
            <input type="submit" value="提交" class="btn">  
            <input type="reset" value="重置" class="btn">  
        </form>    </div>  
  
    <script>        let inputUserName = document.querySelector('#username');  
        let inputPhoneNumber = document.querySelector('#phone');  
         
       checkUserName = function () {  
          let username = inputUserName.value;  
          console.log(username);  
          let errMsg = '';  
          if (username.length < 4 || username.length > 16){  
             errMsg = '用户名不合法';  
          }  
          setErrMsg('#name_msg',errMsg);  
          return errMsg.length === 0;  
       }  
          
        checkPhoneNumber = function () {  
            let phoneNumber = inputPhoneNumber.value;  
            let errMsg = '';  
            if (phoneNumber.length !== 11){  
               errMsg = '手机号不合法';  
            }  
            setErrMsg('#phone_msg',errMsg);  
            return errMsg.length === 0;  
        }  
         
       setErrMsg = function (spanId,errMsg) {  
          let tip = document.querySelector(spanId);  
          tip.innerHTML = errMsg;  
       }  
         
       inputUserName.addEventListener('blur', checkUserName)  
       inputPhoneNumber.addEventListener('blur', checkPhoneNumber)  
      
        document.querySelector('form').addEventListener('submit', (e) => {  
          if (!checkUserName() || !checkPhoneNumber()){  
             alert('表单信息不合法');  
             e.preventDefault();  
          }  
        })  
    </script>

正则表达式

  • 正则表达式 Regular Express 定义了字符串的组成规则
  • 作用:验证数据格式、查找替换文本
  • 定义
    1. 创建正则表达式字面量(不要加引号)
    2. 创建正则对象RegExp
  • 方法
    test(String):判断指定字符串是否符合规则,符合返回true,不符合返回false

在前端程序中,正则表达式一般用来做表单提交时的数据验证

语法:

  • 普通字符:大多数字符只能描述本身,被称为普通字符,比如字母和数字
  • 特殊字符:具有特殊含义的字符,提高匹配功能和灵活性
  • 量词:表达要匹配的字符或表达式的数量

特殊字符:

量词:

在前文的表单注册验证手机号和用户名时,可以用正则进行验证:

const phoneRegex = /1[1-3]\d{9}/;  
const usernameRegex = /\w{4,16}/;

但是这样做是有漏洞的,当前正则表达式仅表示 要在字符串中匹配出这些数据,匹配到了就返回true,但是我们目前的需求是 限制字符串仅能由这些字符组成,所以要加上字符串开始和结束标记

const phoneRegex = /^1[1-3]\d{9}$/;  
const usernameRegex = /^\w{4,16}$/;

JS模块化

JS提供了一种将JavaScript程序拆分为若干可按需导入的单独模块机制(export、import)

在上文的示例中,首先将页面中的js脚本抽取到外部check.js文件中:

在html中使用的时候就是:

在其他页面中,如果想使用这两个验证方法就需要导入check.js文件,但是check.js可能非常庞大,有很多不需要的内容。

解决方法:将check.js的两个方法抽取为checkFn.js

//checkFn.js
checkUserName = function () {  
    let username = inputUserName.value;  
    console.log(username);  
    let errMsg = '';  
    if (username.length < 4 || username.length > 16){  
       errMsg = '用户名不合法';  
    }  
    setErrMsg('#name_msg',errMsg);  
    return errMsg.length === 0;  
}  
  
checkPhoneNumber = function () {  
    let phoneNumber = inputPhoneNumber.value;  
    let errMsg = '';  
    if (phoneNumber.length !== 11){  
       errMsg = '手机号不合法';  
    }  
    setErrMsg('#phone_msg',errMsg);  
    return errMsg.length === 0;  
}

但是在check.js中,需要导入checkFn.js中的这两个方法

在js文件中进行导入/导出的操作就需要使用模块化技术

模块化技术:

  1. 在被使用js文件的方法/对象位置export
  2. 在使用js文档中进行import

export:

export function checkUserName () {  
    let username = inputUserName.value;  
    console.log(username);  
    let errMsg = '';  
    if (username.length < 4 || username.length > 16){  
       errMsg = '用户名不合法';  
    }  
    setErrMsg('#name_msg',errMsg);  
    return errMsg.length === 0;  
}  
  
export function checkPhoneNumber () {  
    let phoneNumber = inputPhoneNumber.value;  
    let errMsg = '';  
    if (phoneNumber.length !== 11){  
       errMsg = '手机号不合法';  
    }  
    setErrMsg('#phone_msg',errMsg);  
    return errMsg.length === 0;  
}

注意:export导出时必须是普通函数,不能是匿名函数

import:

import {checkUserName,checkPhoneNumber} from './checkFn';  
  
let inputUserName = document.querySelector('#username');  
let inputPhoneNumber = document.querySelector('#phone');  
  
inputUserName.addEventListener('blur', checkUserName)  
inputPhoneNumber.addEventListener('blur', checkPhoneNumber)  
  
document.querySelector('form').addEventListener('submit', (e) => {  
    if (!checkUserName() || !checkPhoneNumber()){  
       alert('表单信息不合法');  
       e.preventDefault();  
    }  
})

html使用check.js必须指定导入方式为module

<script type="module" src="js/check.js"></script>

并且必须运行在服务器中

导入导出重命名

  • 导入重命名
import {checkUserName as checkName,checkPhoneNumber} from './checkFn.js';
  • 导出重命名
export {checkPhoneNumber, checkUserName as checkName}