概述
JS是一种脚本语言,JS的目标程序都是以普通文本的形式保存,用记事本是可以直接打开的。
JS运行在浏览器中,浏览器有执行JS代码的内核;JS主要用来操作HTML中的节点,产生动态效果。
JS是网景公司开发的,JS之父是布兰登艾奇;前身叫LiveScript。网景开发JS的目的是占领浏览器市场,网景公司有一个浏览器 Navigator 领航者浏览器;JS是为领航者浏览器专门打造的。微软为了抢夺市场开发了JScript,只支持IE浏览器。
JS包括:ECMAScript、DOM、BOM
- ECMAScript是ECMA指定的262标准,是JS的核心语法。
- DOM是通过JS对HTML的DOM节点操作。DOM规范是W3C指定的。(网页中的元素/节点)
- 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>
但是注意
- 引入外部js文件的script标签体中不能写js代码,不会执行
- 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个字符串之一:
-
“undefined”
-
“number”
-
“string”
-
“boolean”
-
“object”
-
“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类型的值包括:NaN、Infinity(无穷大)
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
- 生成 0 – 10 的随机数
-
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
类型转换
某些运算被执行时,系统内部自动将数据类型进行转换,这种转换被称为隐式转换
- 字符串与数字的隐式转换
-
- 左右有一个是字符串,自动将另一个转换为字符串
- 除了 + 的运算符, – / * 都会自动将字符串转换为数字(NaN)
- 其他类型与布尔的隐式转换
- Number: 0 和 NaN 为false,其他均为true
- string:空字符串为false,其他均为true
- 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)
:指定延迟后执行一次CallbackFunctionsetInterval(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>
发送请求的多种方式
跳转页面:
- 地址栏写url
- 超链接
- 提交表单
- window.open()
- window.location.href (href)可以省略
- 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')
}
};
遍历对象
- 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]);
}
}
- 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')
* }
* */
- 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 定义了字符串的组成规则
- 作用:验证数据格式、查找替换文本
- 定义
- 创建正则表达式字面量(不要加引号)
- 创建正则对象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文件中进行导入/导出的操作就需要使用模块化技术
模块化技术:
- 在被使用js文件的方法/对象位置export
- 在使用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}