JavaScript教程
Q7nl1s admin

◼ JavaScript是一种广泛用于Web编程的轻量级脚本语言,用来处理页面逻辑和用户交互。

◼ JavaScript遵循ECMAScript规范,目前常用版本是ES6(ECMAScript 6.0, 2015年6月发布)。

◼ ECMAScript和JavaScript的关系是:前者是后者的规格,后者是前者的一种实现。

ECMA:欧洲计算机制造商协会

JavaScript基本特点

◼ JS是一种解释性脚本语言(代码不进行预编译,可在程序的运行过程中逐行进行解释)

◼ JS是一种基于对象的语言(不仅可以创建对象,也能使用自身的对象或其他语言创建的对象)

◼ JS是一种简单的弱类型脚本语言(未使用严格的数据类型)

◼ JS是一种跨平台脚本语言(不依赖于操作系统,仅需要浏览器的支持)

基础语法

JS声明

【方式1】 JS代码可直接嵌入在HTML页面

1
2
3
4
5
<script type="text/javascript"> //默认类型,可省略
...
JavaScript代码
...
</script>

注:JS可出现在HTML的任意地方,一般建议放在body底部

不放在head的原因是:HTML代码的执行顺序是由上而下的,浏览器由上至下解析html代码,如果在head里面引入js,可能会导致js代码执行时,页面标签还未加载,导致js找不到作用对象,从而失效。

JS示例

1
2
3
4
5
6
<button id="btn" onclick="clickme()">测试</button>
<script>
function clickme() {
console.log("hello");
}
</script>

【方式2】JS代码存放在单独的JS文件中

index.js

1
2
3
function clickme() {
console.log("hello");
}

注:JS文件中不用包含<script>标签

test.html

1
2
<button id="btn" onclick="clickme()">测试</button>
<script src="index.js"></script>

注:页面中使用<script src=”…”>来引用JS文件

JS代码调试:

js_0

注:添加断点后一般需刷新界面才可捕获

let和const

◼ let 命令用来声明变量(作用域是块级范围)

注:ES6已不推荐使用var命令

1
2
3
4
5
function clickme() {
let a = 1;
let b = 2;
alert(a + b);
}

注:ES6已不推荐使用var命令

变量命名规则

◼ 规则:由字母或下划线、$开头,后接任意个由一个数字、字母或者下划线、$组成的字符串

◼ 变量名不能是JavaScript的关键字(比较多)

◼ 变量对大小写敏感

例如:

正确的变量命名:$a 、 _a 、 $_a、 s_007 、$_$、Answer

错误的变量命名:this、 1a、 b% //JavaScript的关键字

const命令

◼ const 命令用来定义常量(作用域也是块级范围),且必须在声明时指定它的值

◼ const 声明的值是无法被改变的,也不能被重新声明。

const用法示例

1
2
const NUMBER = 123; // 建议常量全部采用大写字母
NUMBER = 456; // 报错,Uncaught TypeError: Assignment to constant variable
1
2
3
4
5
6
const ARR = [1, 2, 3];
ARR.push(4); // 允许,[1, 2, 3, 4]
ARR = [ ] ; // 报错
const OBJ = { name:"小明", age: 20 };
OBJ.age = 18 ; // 允许
OBJ = { name:"小丽", age: 19 }; // 报错

注:const 定义数组或对象时,可以修改其子项或者属性值,但是不能够对自身重新赋值。

变量传递

◼ JS中的数据类型可以分为两种:

​ ◼ 基本类型:String、Number、Boolean、null(空对象)、undefined(没有赋值的变量的默认值) 和 Symbol

​ ◼ 引用类型:Array、Object、Set、Map 等由多个值构成的复杂类型

变量定义

1
2
3
4
5
6
7
8
let x = 5; // Number类型(整数或浮点数),注:NaN是表示非数字的特殊值
let flag = true; // Boolean类型(true、false)
let car = "Benz"; // String类型(单引号也行)
let a; // a= undefined 变量如果没有赋值,默认值为undefined
let arr = ["Benz","Audi","BMW"]; // Array数组类型
arr = null; // 空对象
undefined == null // true undefined与null值相等
undefined === null // false undefined与null的类型是不同的

补充:在JS中,可以使用typeof来检测变量的类型

◼ typeof undefined 结果为:undefined

◼ typeof null 结果为:object

注:== 只判断值是否相等,=== 则是强比较,不仅要判断值是否相等,还要判断类型是否相同

Object定义

◼ 用 { } 定义对象,定义空对象:let stu = { }

◼ 属性:值 (键值对)

◼ 属性之间用逗号分隔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let stu = {
// 对象属性
name: "小明",
birth: "2001/10/05",
// 对象方法
getYear: function () {
let year = new Date( this.birth ).getFullYear();
return year ;
},
} ;
console.log( stu.name ); //属性访问,或 stu["name"]
console.log( stu.getYear() ); //方法访问
let stu = {
name: '小明',
birth: "2001/10/05",
// 对象可以嵌套
address: {
city: '武汉',
street: '黄家湖西路',
zipcode: '430068'
}
} ;
// 链式访问
console.log( p3.address.city ); // 武汉

Class定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {
// 构造函数
constructor(name, birth) {
// 左边是成员变量
this.name = name;
this.birth = birth;
}
getYear() {
// 成员函数(不加function关键字)
let year = new Date(this.birth).getFullYear();
return year;
}
}
//创建对象
let p = new Person("小明", "2001/10/05");
console.log(p.name);
console.log(p.getYear());

变量传递

基本类型变量保存的是变量引用类型变量保存的是内存地址

◼ 基本类型在赋值的时候拷贝值(值拷贝)

◼ 引用类型在赋值的时候只拷贝内存地址,不拷贝值(地址拷贝)

变量传递示例1:值传递

1
2
3
4
5
6
7
8
9
10
11
12
let num1 = 1;
let num2 = num1; // num1的值会被拷贝给num2,两者互相独立
num2 = 2; // 改变num2不会影响num1
console.log(num1, num2); // 1 2

function add(num) {
num += 1; // 这里的num也是按值传递的
return num;
}
let num3 = 3;
let num4 = add(num3); // 这里传递的是num3的值
console.log(num3, num4); // 3 4

变量传递示例2:地址传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let arr1 = [1, 2];
let arr2 = arr1; // arr1的地址会被拷贝给arr2,两者指向的是同一块内存数据
arr1.push(3); // 改变arr1,arr2也会一块改变
console.log(arr2); // [ 1, 2, 3 ]
arr2 = [ ]; // arr2被指向了一个新的内存地址,对arr1不产生影响
console.log(arr2); // [ ]
console.log(arr1); // [ 1, 2, 3 ]

function update(user) {
user.age += 1; // user是一个对象,传进来的是地址,对user修改会影响原数据
}
let user1 = { age: 18 };
update(user1); // 传入的是user1的地址
console.log(user1); // { age: 19 }

let arr3 = [ { age: 18 }, { age: 24 } ];
let arr4 = arr3.slice(1); // arr4=[ { age: 24 } ]
arr4[0].age += 1; // 会影响原数组数据
console.log(arr3); // [ { age: 18 }, { age: 25 } ]

注: slice切片操作不改变原始数组

注: slice虽然返回的是一个新数组,但是里面的子元素对象指向的仍然是原始的数据地址

解构赋值

◼ 通过解构赋值,可以将值、属性从数组、对象中取出,赋值给其他变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
let array = [1, 2, 3];
let a = array[0];
let b = array[1];
let c = array[2];
// 解构数组 -> let [a, b, c] = [1, 2, 3]; //a=1,b=2,c=3
// 注意用 [ ]

let object = { a: 1, b: 2, c: 3 };
let a = object.a;
let b = object.b;
let c = object.c;
// 解构数组 -> let { a, b, c } = { a: 1, b: 2, c: 3 }; //a=1,b=2,c=3
// 注意用 { },且变量必须与属性同名

解构数组示例1

1
2
3
4
5
let [a, b] = [1,2,3]; 			// a=1, b=2 部分解构
let [a, b] = [1]; // a=1, b=undefined 解构不成功,变量值=undefined
let [a, , , b] = [1, 2, 3, 4]; // a=1, b=4 可以忽略掉某些值
let [a = 1, b = 2] = [5]; // a=5, b=2 可以给左边数组中的变量设置默认值
let [a, ... b] = [1, 2, 3] // a=1, b= [2,3] 将剩余的数组赋值给一个变量(剩余模式)

解构数组示例2

1
2
3
4
let a = 1;
let b = 2;
// 通过解构直接交换两个变量
[a, b] = [b, a] ; //a=2, b=1
1
2
3
4
5
function foo() {
return [1, 2];
}
// 解析函数返回值
let [a, b] = foo(); //a=1, b=2

解构对象示例1

1
2
3
4
5
let object = { a: 1, b: 2, c: 3 };
let { a, b, x } = object; // a=1, b=2, x=undefined 变量不与属性同名将无法解构,值= undefined
let object = { a: 5 };
let { a = 1, b = 2 } = object; // a=5, b=2 解构对象也可以指定默认值
let { a, ...b } = { a: 1, b: 2, c: 3 }; // a=1, b={ b:2,c:3 } 解构对象也支持剩余模式
1
2
3
let object = { a: 1, b: 2, c: 3 };
// 提取的值给和属性名不同的变量
let { a: aa, b: bb } = object; // aa=1, bb=2 部分解构 注意此处:console.log(a) 会报错:a is not defined

解构对象示例2

1
2
3
4
5
6
7
8
9
function foo(obj) {
console.log( obj.id, obj.name );
}
let user = {
id: 1,
name: "小明",
};
foo(user);

从函数参数对象中解构数据->

1
2
3
4
5
6
7
8
function foo( { id, name } ) {
console.log( id, name );
}
let user = {
id: 1,
name: "小明",
};
foo(user);

箭头函数

◼ JS函数的定义:

普通函数

1
2
3
4
5
6
7
8
// 方式1:普通函数
// function 为关键字
// 参数只写参数名,不用指定类型
function foo(num) {
return num+1;
}
//调用函数
let a = foo(100) ; // a=101

匿名函数

1
2
3
4
5
6
7
8
9
// 方式2:匿名函数
// 没有函数名
// 匿名函数可以赋值给变量
let foo = function(num) {
return num + 1;
}
// 调用函数
// 该变量实际是函数
let a = foo(100) ; // a=101

箭头函数示例1

1
2
3
4
5
let b = () => 5 ;
// 相当于
let a = function() {
return 5;
}
1
2
3
4
5
let c = (x, y) => x + y ;
// 相当于
let c = function(x, y) {
return x + y;
}
1
2
3
4
5
let d = (x, y) => {
let s = x + y;
return s;
}
// 注意:如果箭头函数有多条语句,则花括号不能省略

箭头函数示例2

注意:箭头函数返回对象时,外面要加上小括号(不能用大括号)

1
2
let foo = (name) => ( { name : name } ) ; // 说明:第一个name是属性名,第二个name属性值(参数变量)
let obj = foo('小明'); // obj = { name: '小明' }

箭头函数示例3

1
2
3
4
let arr = [1, 2, 3, 4, 5];
let result = arr.map( item => item * 2 ); // map(function):返回一个由回调函数的返回值组成的新数组
// 箭头函数最常用的应用场景是简化回调函数
console.log(result); // [2, 4, 6, 8, 10]

常用API

字符串操作

注:字符串所有方法都不会修改字符串本身

◼ 模板字符串:

​ ◼ 模板字符串是增强版的字符串,用**反引号 (`)**来标识

​ ◼ 它可当作普通字符串来使用

​ ◼ 也可以用来定义多行文本

​ ◼ 或者通过 ${ } 在字符串中嵌入变量或表达式

模板字符串示例

1
2
3
4
5
6
7
8
9
let a = `template string`; // 和普通字符串一样

let name = "小明";
let b = `Hello ${name}!`; // ${ } 嵌入变量或表达式 b="Hello 小明!"

// 多行文本
let c = `<div>
<p> ${ name.length > 10 ? true : false } </p>
</div>`;

字符串长度:length属性

1
2
let str = "0123456789";
let len = str.length; // len=10

toUpperCase和toLowerCase

toUpperCase() 把字符串转换为大写

toLowerCase() 把字符串转换为小写

1
2
3
let text1 = "Hello"; 
let text2 = text1.toUpperCase(); // text2 = "HELLO"
let text3 = text1.toLowerCase(); // text3 = "hello"

substring

◼ 语法:substring(start, end?)

◼ 返回一个字符串在start到end索引之间的一个子串(不含end位置),或者从start到字符串末尾的一个子串(不写第二个参数)。

1
2
3
4
5
let str = "0123456789";
console.log( str.substring(0, 3) ); // '012'
console.log( str.substring(3, 6) ); // '345'
console.log( str.substring(3) ); // '3456789'
console.log( str.substring(0, 0) ); // 空串

slice

◼ slice 和 substring 非常类似,不同的是,slice 的参数可以为负数,表示倒数第几个字符

1
2
3
4
5
6
7
8
let str = "0123456789";
// 以下三者用法同substring
console.log( str.slice(0, 3) ); // '012'
console.log( str.slice(3, 6) ); // '345'
console.log( str.slice(3) ); // '3456789'

console.log( str.slice(0, -3) ); // '0123456',表示从第0各字符提取到倒数第三个字符
console.log( str.slice(-3, -1) ); // '78'

includes

◼ 语法:str.includes(searchString, position?) // position表示开始搜索的索引位置,默认为0

◼ 判断一个字符串是否包含在另一个字符串中,根据情况返回 truefalse

1
2
3
let str = "0123456789";
console.log( str.includes("123") ); // true
console.log( str.includes("123", 4) ); // false

startsWith

◼ 语法:str.startsWith(searchString, position?) // position表示开始搜索的索引位置,默认为0

◼ 判断当前字符串是否以另外一个给定的子字符串开头,并根据判断结果返回 true 或 false。

1
2
3
4
let str = '0123456789';
console.log( str.startsWith('0123') ); // true
console.log( str.startsWith('1234') ); // false
console.log( str.startsWith('1234', 1) ); // true

endsWith

◼ 用来判断当前字符串是否以另外一个给定的子字符串结尾,第二个参数是可选的 str 长度。

1
2
3
let str = '0123456789';
console.log( str.endsWith('789') ); // true
console.log( str.endsWith('456', 7) ); // true,此处的 7 表示长度值,相当于判断 '0123456'.endsWith('456')

repeat

◼ 返回一个新字符串,表示将原字符串重复 n 次。

1
let str = 'abc'.repeat(2) // str= 'abcabc'

padStart、padEnd

◼ 这两个方法提供了字符串补全长度的功能,如果某个字符串不够指定的长度,会在头部或者尾部补全,padStart 用于头部补全,padEnd 用于尾部补全。

1
2
3
let a = "5".padStart(5, "0"); // '00005'
let b = "123".padEnd(5); // '123 _ _',默认使用空格补全
let c = "12345".padStart(4); // '12345',超出长度,不会变化

trim、trimStart、trimEnd

trim 用来消除字符串首尾的空格trimStart 用来消除字符串头部的空格,trimEnd 用来消除字符串尾部的空格,他们返回的都是新字符串,不会改变原值

1
2
3
4
let str = " abc ";
let a = str.trim(); // 'abc'
let b = str.trimStart(); // 'abc '
let c = str.trimEnd(); // ' abc'

replace 和 replaceAll

◼ 字符串替换方法,replace() 只会替换第一个匹配,replaceAll() 可以一次性替换所有匹配。

1
2
3
'aabbcc'.replace('b', 'x') // 'aaxbcc'
'aabbcc'.replace(/b/g, 'x') // 'aaxxcc' 注:/b/g (正则式) /b表示字符'b' ,/g表示全局,合在一起表示匹配所有字符'b'
'aabbcc'.replaceAll('b', 'x') // 'aaxxcc'

split

◼ 使用指定的分割字符将一个字符串分割子字符串数组,以一个指定的分割字符串来决定每个拆分的位置。

1
2
let a = 'Hello JavaScript'.split(' '); // 用空格字符分割 a = [ 'Hello', 'JavaScript' ]
let b = 'Hello'.split('') // 用空串分割 b = [ 'H', 'e', 'l', 'l', 'o' ]

数组操作

◼ 数组遍历:

1
2
3
4
5
6
7
8
9
10
let arr = [1, 2, 3, 4, 5];
for ( let i = 0; i < arr.length; i++ ) {
console.log(arr[i]); //常规遍历
}
for ( let item of arr ) { // for-of 遍历数组元素
console.log(item);
}
arr.forEach( (item, index) => {
console.log(item, index); // item为当前元素,index为索引值
});

补充:for-in遍历的是序号

for ( let index in arr ) {

​ console.log(index); // 0 1 2 3 4

}

fill

◼ 将一个固定值替换数组的元素。

1
2
3
4
5
6
let fruits = ["Banana", "Orange", "Apple"];
fruits.fill("Mango"); // 长度>6的串构成的新数组
console.log(fruits); // ["Mango", "Mango", "Mango"]
let arr = [1,2,3,4,5];
arr.fill(9,2,4); // fill(value, start, end),不含end位置
console.log(arr); // [1,2,9,9,5]

map

◼ 返回一个由回调函数的返回值组成的新数组。

1
2
3
let arr = [1, 2, 3]
let tpl = arr.map( item => `<span>${item}</span>` )
console.log(tpl) // [ '<span>1</span>', '<span>2</span>', '<span>3</span>' ]

reduce

◼ 从左到右为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次的回调函数,并返回最后一次回调函数的返回值。

◼ 语法:arr.reduce( callback, [initialValue] )

​ ◼ callback函数中包含四个参数

​ ◼ - previousValue (上一次调用回调返回的值,或者是提供的初始值initialValue)

​ ◼ - currentValue (数组中当前被处理的元素)

​ ◼ - index (当前元素在数组中的索引)

​ ◼ - array (调用的数组)

​ ◼ initialValue :作为第一次调用 callback 的第一个参数

reduce示例1

js_1

reduce示例2

1
2
3
let arr = [1, 2, 3];
let tpl = arr.map( item => `<span>${item}</span>` );
console.log(tpl); // [ '<span>1</span>', '<span>2</span>', '<span>3</span>' ]

用reduce改写

1
2
3
let arr = [1, 2, 3];
let tpl = arr.reduce( (prev, curr) => prev + `<span>${curr}</span>`, ""); // initialValue为空字符串""
console.log(tpl); // '<span>1</span><span>2</span><span>3</span>' // 返回结果是字符串

reduce示例3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const scores = [
{
subject: "math",
score: 88,
},
{
subject: "chinese",
score: 95,
},
{
subject: "english",
score: 80,
},
];

const w = {
math: 0.5,
chinese: 0.3,
english: 0.2,
};

const sum = scores.reduce((pre, item) => {
return pre + item.score * w[item.subject];
}, 0);

console.log(sum); // 88.5

find 和 findIndex

◼ find:找到第一个满足测试函数的元素并返回该元素的值,如果找不到,则返回 undefined

◼ findIndex:找到第一个满足测试函数的元素并返回那个元素的索引,如果找不到,则返回 -1

1
2
3
let arr = [1, 2, 3, 4, 5]
let found = arr.find( item => item > 3 ) // found=4
let index = arr.findIndex( item => item > 3 ) //index=3

indexOf

◼ 返回数组中第一个与指定值相等的元素索引,如果找不到这样的元素,则返回 -1

1
2
3
let arr = [1, 2, 3, 4, 5]
let index = arr.indexOf(4)
console.log(index) // 3

includes

◼ 判断当前数组是否包含某指定的值,如果是返回 true,否则返回 false。

1
2
3
let arr = [1, 2, 3, 4, 5]
console.log( arr.includes(3) ) // true
console.log( arr.includes('2') ) // false

join

◼ 连接所有数组元素组成一个字符串。

1
2
3
let arr = [1, 2, 3, 4, 5]
console.log( arr.join('') ) // 用空串进行连接 '12345'
console.log( arr.join('-') ) // 用'-'进行连接 '1-2-3-4-5'

concat

◼ 用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

1
2
3
4
let arr1 = [1, 2, 3]
let arr2 = [4, 5]
let arr3 = arr1.concat(arr2)
console.log(arr3) // [ 1, 2, 3, 4, 5 ]

reverse

颠倒数组中元素的排列顺序,即原先的第一个变为最后一个,原先的最后一个变为第一个,该方法会改变原数组

1
2
3
let arr = [1, 2, 3, 4, 5]
arr.reverse()
console.log(arr) // [ 5, 4, 3, 2, 1 ],原数组被改变

slice

◼ 抽取当前数组中的一段元素组合成一个新数组,原始数组不会被改变。(浅拷贝)

1
2
3
let arr = [1, 2, 3, 4, 5]
console.log( arr.slice(2) ) // [ 3, 4, 5 ]
console.log( arr.slice(1, 3) ) // [ 2, 3 ]

splice

◼ 在任意位置给数组添加或删除任意个元素。此方法会改变原数组

◼ 语法:arr.splice(index, [howmany,] [item1,] ... [itemX])

​ ◼ index:指定在什么位置添加/删除项目,使用负值指定从数组末尾开始的位置

​ ◼ howmany:可选,要删除的项目数。如果设置为 0,则不会删除任何项目。

​ ◼ item1, …, itemX:可选,要添加到数组中的新项目。

splice示例1

◼ 插入元素:

1
2
3
let arr = [1, 2, 3, 4, 5]
arr.splice(2, 0, 6) //在位置值=2处插入元素6
console.log(arr) // [ 1, 2, 6, 3, 4, 5 ]

◼ 删除元素:

1
2
3
4
let arr = [1, 2, 3, 4, 5]
let item = arr.splice(1, 2) //在位置值=1处删除2个元素
console.log(arr) // [ 1, 4, 5 ]
console.log(item) // [ 2, 3 ]

splice示例2

◼ 删除元素的同时插入元素:

1
2
3
4
let arr = [1, 2, 3, 4, 5]
let item = arr.splice(1, 2, 6, 7) //在位置值=1处删除2个元素并添加6,7两个元素
console.log(arr) // [ 1, 6, 7, 4, 5 ]
console.log(item) // [ 2, 3 ]

模拟堆栈和队列操作:会改变原数组

push:在数组的末尾增加一个或多个元素,并返回数组的新长度。

pop删除数组的最后一个元素,并返回这个元素。

unshift:在数组的开头增加一个或多个元素,并返回数组的新长度,与 push 对应。

shift删除数组的第一个元素,并返回这个元素,与 pop 对应。

push和pop示例

◼ push:

1
2
3
4
let arr = [1, 2, 3, 4, 5]
console.log( arr.push(6) ) // 6 push返回数组新长度
console.log( arr.push(7, 8) ) // 8 在队尾添加多个
console.log(arr) // [ 1, 2, 3, 4, 5, 6, 7, 8 ]

◼ pop:

1
2
3
4
let arr = [1, 2, 3, 4, 5]
let item = arr.pop() // 在队尾删除
console.log(item) // 5 pop返回删除的元素
console.log(arr) // [ 1, 2, 3, 4 ]

unshift和shift示例

◼ unshift:

1
2
3
4
let arr = [1, 2, 3, 4, 5]
console.log( arr.unshift(6) ) // 6 unshift返回数组新长度
console.log( arr.unshift(7, 8) ) // 8 在队头添加多个
console.log(arr) // [ 7, 8, 6, 1, 2, 3, 4, 5 ]

◼ shift:

1
2
3
let arr = [1, 2, 3, 4, 5]
console.log( arr.shift() ) // 1 在队头删除并返回删除值
console.log(arr) // [ 2, 3, 4, 5 ]

sort

◼ 对数组的元素进行排序,并返回数组,会改变原数组

◼ 默认排序顺序是在将元素转换为字符串,然后比较它们的 UTF-16 值,默认升序。

1
2
3
let arr = ["b", "d", "a", "c"];
arr.sort();
console.log(arr); // ['a', 'b', 'c', 'd']

自定义排序

1
2
3
4
5
6
7
8
9
10
11
let arr = [3, 5, 1, 4, 2];
arr.sort((a, b) => {
return a-b; // 基本口诀:第1个减第2个 -- 升序
});
console.log(arr); // [ 1, 2, 3, 4, 5 ] 升序


arr.sort((a, b) => {
return b-a; // 基本口诀:第2个减第1个 -- 降序
});
console.log(arr); // [ 5, 4, 3, 2, 1 ] 降序

数学计算

◼ Math常用的几个:

​ ◼ ceil(x):上取整(返回大于x的最小整数)

​ ◼ floor(x):下取整(返回≤x的最大整数)

​ ◼ round(x):四舍五入

​ ◼ trunc(x):简单取整(直接去除小数点之后的部分)

​ ◼ random():[0,1) 之间随机数(伪随机)

示例

1
2
3
4
5
6
7
8
9
10
11
12
Math.ceil(d):向上取整,有小数就整数部分加1:;
Math.ceil(11.1) //12
Math.ceil(-11.1) //-11
Math.floor(d):向下取整,正数舍弃小数位,负数整数位减一
Math.floor(11.1) //11
Math.floor(-11.1) //-12
Math.round(d):四舍五入
Math.round(20.5) //21
Math.round(-20.9) //-21
Math.trunc(x):简单取整(直接去除小数点之后的部分)
Math.trunc(3.1) // 3
Math.trunc(0.5) // 0

随机数示例

生成[min,max]范围的随机整数

1
2
3
function random(min, max) {
return Math.floor( Math.random() * (max - min+1) + min )
}

补充:JS内置函数 parseInt()

1
2
3
4
5
// parseInt(d):丢弃小数部分,保留整数部分 注:支持字符串转int
parseInt(11.5) //11
parseInt(-11.5) //-11
parseInt("123") //123
parseInt("11.5a") //11

对象操作

◼ 遍历对象:

1
2
3
4
5
6
7
8
9
10
let obj = { a: 1, b: 2, c: 3 }
// for-in遍历的是key值(属性),注:不能用for-of
for (let key in obj) {
// obj[key]获取属性值
console.log( key, obj[key] )
}
运行结果:
a 1
b 2
c 3

对象的keys和values

keys:返回一个包含所有给定对象自身可枚举属性名称的数组。

values:返回给定对象自身可枚举值的数组。

1
2
3
let obj = { a: 1, b: 2, c: 3 }
console.log( Object.keys(obj) ) // [ 'a', 'b', 'c' ]
console.log( Object.values(obj) ) // [ 1, 2, 3 ]

window对象

◼ window对象表示一个包含DOM文档的窗口,是一个全局对象,代表了正在运行的窗口

js_2

alert、confirm和prompt //实际是window.alert()window.confirm()window.prompt()

alert(msg):显示msg信息和一个确认按钮的警告框。

result = confirm(msg):显示msg信息,以及”确定”和”取消”两个按钮的对话框。点击”确定”返回 true,点击”取消”返回 false。

result = prompt(msg, [default]):显示可提示用户输入的对话框(default为初始值)。点击”确定”,返回输入框输入的文本(如果为空,则返回一个空串),点击”取消”则返回 null。

示例

1
2
3
4
5
let result = confirm("确认删除吗?");
if (result === true) {
// 删除操作
alert("删除成功");
}

js_3

1
2
3
4
5
6
let age = prompt("请输入年龄", 18);
if (age >= 100 || age <= 0) {
alert("输入年龄不正确");
} else {
alert(`你的年龄是${age}岁!`);
}

js_4

window.location

◼ 用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面。

1
2
let url = window.location; // 获得当前页面的地址 
window.location = "https://www.wust.edu.cn"; // 重定向

setTimeout和clearTimeout

setTimeout(code,millisec):在指定的毫秒数后调用函数或计算表达式。(异步操作

clearTimeout(id_of_settimeout)取消setTimeout() 方法设置的定时操作。

1
<button id="ok">3秒之后确定</button>
1
2
3
4
5
6
let btn = document.getElementById("ok");
btn.disabled = true;
let t = setTimeout(() => {
btn.disabled = false;
clearTimeout(t);
}, 3000);
示例 1:倒计时
1
<button id="ok">3秒之后确定</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
let btn = document.getElementById("ok");
btn.disabled = true;
let t = 3;
function count(){
t--;
btn.innerHTML = t + "秒之后确定";
if (t <= 0) {
clearInterval(id);
btn.innerHTML = "确定";
btn.disabled = false;
}
}
let id = setInterval(count, 1000);

js_5

示例2:进度条

js_6
1
2
3
4
5
<div id="myProgress">
<div id="myBar"></div>
</div>
<br />
<button id="btn">开始</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let btn = document.getElementById("btn");
let el = document.getElementById("myBar");
btn.addEventListener("click", () => {
let width = 1;
let id = setInterval(() => {
if (width >= 100) {
clearInterval(id);
} else {
width++;
el.style.width = width + "%";
el.innerHTML = width + "%";
}
}, 10); //每隔0.01秒执行一次
});

文档对象模型

◼ 文档对象模型:DOM(Document Object Model)

◼ DOM 是载入到浏览器中的文档模型(html或xml),以节点树的形式来表现文档,每个节点代表文档的构成部分。

js_2

DOM操作

​ ◼ 通过JS的DOM API,可以完成DOM

​ ◼ 查询操作

​ ◼ 创建操作

​ ◼ 删除操作

​ ◼ 替换操作

​ ◼ 样式修改

​ ◼ 事件监听(如鼠标点击、键盘输入等)

(1)查询操作:常用id或者css选择器查询

1
2
3
4
5
<ul id="list">
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let list = document.getElementById('list') // 命中id="list"的元素,注意不带#,不是css选择器
console.log(list.innerHTML) //查看元素的HTML内容
let first = document.querySelector('.item') // 命中第一个 class="item" 参数为class选择器
console.log(first.innerHTML)
let second = document.querySelector('.item:nth-child(2)') // 命中第二个 .item 复杂的css选择器
console.log(second.innerHTML)
let items = document.querySelectorAll('.item') // 获得包含所有 .item 的集合(NodeList)
console.log(items.length) //查看集合长度
for ( let el of items ) { //遍历集合
console.log(el)
}

// 普通遍历:
/* for ( let i = 0; i < items.length; i++ ) {
items[i]…
} */
js_6

(2)创建操作:document.createElement

1
2
3
4
5
6
7
8
9
10
let list = document.createElement('ul') //创建1个ul元素
list.id = 'list' // 设置元素的id属性
for ( let i = 0; i < 3; i++ ) {
let item = document.createElement('li') //循环创建3个li元素
item.className = 'item' // 设置元素的class属性
item.innerText = `${i + 1}` // 设置元素的innerText属性 (使用了模板字符串)
list.appendChild(item) // 将创建好的元素添加到父节点
}
// 将list添加到body
document.body.appendChild(list)

相当于动态创建

1
2
3
4
5
<ul id="list">
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
</ul>

(3)删除操作:父元素.removeChild

1
2
3
4
5
6
7
8
//(1)删除一个子节点
let item = document.querySelector('.item')
item.parentNode.removeChild(item) //父元素才能删除子元素 (删除的节点将从DOM树上移除)
// (2)清空list下所有子节点
let list = document.getElementById('list')
list.innerHTML = "" // 将innerHTML属性置为空串(相当于删除所有子节点)
//(3) 一次性删除list节点
document.body.removeChild(list)

(4)替换操作:父元素.replaceChild

1
2
3
4
5
6
7
8
9
// 示例:将第二个.item节点替换为新的节点
let oldItem = document.querySelector('.item:nth-child(2)')
let list = document.getElementById('list')

let newItem = document.createElement('li') //准备新节点
newItem.className = 'new-item'
newItem.innerText = 'new-item'

list.replaceChild(newItem, oldItem) // 由父元素完成替换

(5)样式修改:

◼ 修改元素的单个样式值:element.style.样式属性 = “值” (注:要用字符串)

1
2
3
4
5
6
7
8
<p id="p1">Hello World!</p>
<p id="p2">Hello World!</p>

<script>
// 要求使用驼峰方式(去掉连接线,首字母变大写)如下列的fontSize
document.getElementById("p1").style.color = "blue";
document.getElementById("p2").style.fontSize = "20px";
</script>
js_7

◼ 修改元素的样式类:element.className = “类名”

1
2
3
4
5
6
7
8
9
10
11
12
<p id="p1">Hello World!</p>
<p id="p2">Hello World!</p>

<script>
document.getElementById("p1").className = "strong";
/*
.strong {
color: red;
font-weight: 700;
}
*/
</script>
js_8
示例1:侧滑菜单

js_9

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="mySidenav" class="sidenav">
// href="javascript:void(0)" 用于阻止a标签默认行为的方法
<a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
<a href="#">About</a>
<a href="#">Services</a>
<a href="#">Clients</a>
<a href="#">Contact</a>
</div>

<div id="main">
<h2>侧边栏实例 - 页面主体向右移动</h2>
<span style="font-size: 30px; cursor: pointer" onclick="openNav()">&#9776; 打开</span>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
.sidenav {
height: 100%;
width: 0px; /*初始宽度=0不显示内容*/
background-color: #111;
padding-top: 30px;
overflow-x: hidden; /*x轴溢出处理*/
position: fixed;
top: 0px;
left: 0px;
z-index: 999;
transition: 0.5s; /*过渡动画*/
}

.sidenav a:link,
.sidenav a:visited {
text-decoration: none;
display: block; /*块级元素*/
padding: 8px 8px 8px 32px;
font-size: 20px;
color: #818181;
transition: 0.3s; /*过渡动画*/
}

.sidenav a:hover,
.sidenav a:active {
color: #f1f1f1;
}

.sidenav .closebtn {
/* 此处相对父元素sidenav定位 */
position: absolute;
top: 0px;
right: 5px;
font-size: 20px;
}

#main {
transition: margin-left 0.5s; /*过渡动画*/
padding: 16px;
}
1
2
3
4
5
6
7
8
9
10
<script>
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
document.getElementById("main").style.marginLeft = "250px";
}
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
document.getElementById("main").style.marginLeft = "0";
}
</script>

(6)事件监听操作:addEventListener

◼ 基本语法

1
2
3
4
element.addEventListener(event, function)
参数说明:
event:事件名(字符串) // 注:没有 "on" 前缀。 例如:使用"click",而不是使用"onclick"
function:事件触发时执行的函数(事件监听),函数的第一个参数为事件对象 。

注:事件对象的类型取决于特定的事件。例如, “click” 事件属于 MouseEvent(鼠标事件) 对象

示例1:鼠标事件

1
<button id="btn">Click</button>
1
2
3
4
5
6
7
8
9
10
let btn = document.getElementById("btn");
// 监听鼠标点击事件
btn.addEventListener("click", (event) => {
alert("hello");
});
// 其他写法==>
btn.onclick = function(event) {
alert("hello");
}
btn.onclick = (event) => alert("hello");

示例2:键盘事件

1
<input type="text" id="username" />
1
2
3
4
5
6
7
let input = document.getElementById("username");
// keypress为击键事件
input.addEventListener("keypress", (event) => {
console.log( event ); // 显示event对象
if( event.key === "Enter" ) // 判断是否是回车键,十分重要
console.log( event.target.value ); // 按下回车键时显示输入的值,event.target 是引发事件的目标元素
});
js_10

示例3:input事件

1
2
<input type="text" id="username" />
<p id="tip"></p>
1
2
3
4
5
6
let input = document.getElementById("username");
// 输入事件 (用户输入时触发)
input.addEventListener("input", (event) => {
let x = event.target.value;
document.getElementById("tip").innerHTML = "你输入的是: " + x;
});
js_11

示例4:change事件

1
2
3
4
5
<select id="link">
<option value="">请选择</option>
<option value="http://www.163.com">网易</option>
<option value="http://www.sohu.com">搜狐</option>
</select>
1
2
3
4
5
let link = document.getElementById("link");
// change事件 (当输入域的内容改变并失去焦点时发生)
link.addEventListener("change", (event) => {
window.location = event.target.value;
});

注:change 事件多用于以下三种情况:

  • 当元素是 :checked 状态时(通过点击或者使用键盘),见于 <input type="radio"><input type="checkbox">
  • 当用户显式提交改变时(例如:点击了<select>中的一个选项,从 <input type="date"> 标签选择了一个日期,通过 <input type="file"> 标签上传了一个文件等);
  • 当标签的值被修改并且失去焦点后,但未提交时(例如:对<textarea>或者 <input type="text">的值进行编辑后)。
示例 2:表格数据搜索
js_12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<input type="text" id="myInput" placeholder="搜索公司..." />
<table id="myTable">
<tr class="header">
<th style="width: 60%">公司名称</th>
<th style="width: 40%">国家</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
</table>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function search() {
let input = document.getElementById("myInput");
let filter = input.value.toUpperCase();
let table = document.getElementById("myTable");
let tr = table.querySelectorAll("tr");
// 循环表格每一行,查找匹配项
for (let i = 0; i < tr.length; i++) {
let td = tr[i].querySelectorAll("td")[0]; //获得第一列(公司名称)
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
let input = document.getElementById("myInput");
input.addEventListener("input", search);

注:如果js、css外部文件有使用到相对路径时,需要注意其相对路径的基准是不一样的。

  • js文件的相对路径是以引用该js文件的页面为基准
  • css文件的相对路径是以自身的位置为基准

具体参考这篇文章:js、css外部文件的相对路径问题

示例 3:验证码
js_13
1
2
3
4
<div>
<span id="capcha">5位验证码</span>
<img src="images/arrow_03.png" id="change_capcha" alt="" >
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
div {
width: 500px;
margin: 30px auto;
text-align: center;
}
span {
display: inline-block;
width: 80px;
cursor: pointer;
}
img {
vertical-align: middle;
width: 30px;
cursor: pointer;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//验证码:由大小写字母或数字组成
let codeStr =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
56789";

//验证码长度
let length = 5;

let capcha = document.getElementById("capcha");
let change_capcha = document.getElementById("change_capcha");

// 用来生成一个[n,m]随机整数
function getRandom(n, m) {
return parseInt(Math.random() * (m - n + 1) + n);
}

// 将随机生成的整数下标对应的字母放入span中
function getCode() {
let str = "";
// 验证码有几位就循环几次
for (let i = 0; i < length; i++) {
let index = getRandom(0, 61);
str += codeStr.charAt(index);
}
capcha.innerHTML = str;
}

// 页面初始加载时就调用函数生成验证码,页面刷新也会执行
getCode();

// 点击刷新验证码
capcha.addEventListener("click", getCode);
change_capcha.addEventListener("click", getCode);
示例4:级联
js_14
1
2
3
4
5
6
7
8
<select name="" id="province">
<option value="0">选择省</option>
<option value="1">湖北</option>
<option value="2">湖南</option>
</select>
<select name="" id="city">
<option value="0">选择市</option>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let province = document.getElementById("province");
let city = document.getElementById("city");
province.addEventListener("change", createCity);
//创建city信息
function createCity() {
let val = province.value;
let ops;
switch (val) {
case "0": //case用字符串
city.innerHTML = '<option value="0">选择市</option>';
break;
case "1":
city.innerHTML = ""; //清空
ops = createOp(0, "武汉");
city.appendChild(ops);
ops = createOp(1, "黄石");
city.appendChild(ops);
break;
case "2":
city.innerHTML = "";
ops = createOp(0, "长沙");
city.appendChild(ops);
ops = createOp(1, "湘潭");
city.appendChild(ops);
break;
}
}
function createOp(val, cname) {
let ops = document.createElement("option");
ops.value = val;
ops.innerHTML = cname;
return ops;
}

JSON

◼ JSON:JavaScript Object Notation(JavaScript 对象表示)

◼ JSON 是轻量级的文本数据交换格式 (纯文本)

◼ JSON 比 XML 更小、更快,更易解析

JSON对象

1
2
3
4
5
let obj = { 
"name":"小明",
"age":20,
"site":null
};

◼ JSON对象用 { } 定义

◼ JSON对象可以包含多个 key:value(键/值对)

◼ key 和 value 中使用冒号 : 分割

◼ 每个 key/value 对使用逗号 , 分割

◼ key 必须是字符串,value 可以是字符串、数字、布尔值、对象、 数组 或 null)

JSON对象访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let obj = { 
"name":"小明",
"age":20,
"site":null
};

// 使用点号 . 来访问对象的值
let name = obj.name; // 读取
obj.name = "小丽"; // 修改

// 也可使用中括号[ ]来访问对象的值
let age = obj["age"]; // 读取
obj["age"] = 18; // 修改

// 遍历:使用 for-in 循环(遍历的是key值,不能用for-of)
let s="";
for (let key in obj) {
s += obj[key];
}

JSON嵌套

1
2
3
4
5
6
7
8
9
10
11
let obj = {
name: "小明",
age: 20,
// json嵌套
site: {
"site1" : "www.abc.com",
"site2" : "m.abc.com",
"site3" : "mail.abc.com",
}
};
let url = obj.site.site1; // 读取

JSON数组

1
2
3
4
5
6
7
8
9
10
11
12
// json数组
let arr = [
{ name: "wust", url: "https://www.wust.edu.cn" },
{ name: "hust", url: "https://www.hust.edu.cn" },
{ name: "whu", url: "https://www.whu.edu.cn" },
];

// 使用 for-of 遍历数组元素
let s="";
for (let x of arr) {
s += x.url; // 获取json对象数据
}

JSON.parse

JSON.parse(text [, reviver]) :将JSON格式字符串转换为JavaScript对象

◼ 参数说明:

​ ◼ text:必需,一个有效的JSON字符串 (如格式不正确则解析会出错)

​ ◼ reviver:可选,一个转换结果的函数, 将为对象的每个成员调用此函数

示例

1
2
3
4
5
6
7
let s1 = '{"name":"wust", "url":"www.wust.edu.cn", "age":120}' ; // json串
let obj = JSON.parse(s1) ;
// obj = { name:"wust", url:"www.wust.edu.cn", age:120 } 注:JS对象属性名没有双引号

let s2 = '[{"id":101,"name":"计算机科学"},{"id":102,"name":"软件工程"}]' ; // json数组串
let arr = JSON.parse(s2);
// arr = [ {id:101,name:"计算机科学"}, {id:102,name:"软件工程"} ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let jstr = '{"name":"wust", "url":"www.wust.edu.cn", "birthday":"1898-11-21"}';
let obj = JSON.parse( jstr, function(key, value) {
if (key == "name") {
return value.toUpperCase();
}
if (key == "url") {
value = "https://" + value;
return value;
}
if (key == "birthday") {
let diff = new Date() - new Date(value); //计算距今的毫秒数
let year = parseInt(diff / 1000 / 60 / 60 / 24 / 365); //相差的年数
return year;
}
return value; //此句必须要
});

console.log(obj.name);
console.log(obj.url);
console.log(obj.birthday);

JSON.stringify

JSON.stringify(obj) :将 JavaScript 对象转换为字符串(obj通常为对象或数组)

1
2
3
4
5
6
7
8
9
// 将js对象或json对象转为json串
let obj = { name:"wust", url:"www.wust.edu.cn", age:120 } ; // JS对象
let jstr = JSON.stringify(obj);
// jstr = '{ "name":"wust", "url":"www.wust.edu.cn", "age":120 }'

// 将一般数组转为字符串:
let arr = [ "Google", "Taobao", "Facebook" ];
let str = JSON.stringify(arr);
// str = '[ "Google", "Taobao", "Facebook" ]'
示例1

◼ 读取武汉天气预报信息(返回json数据),解析获取今天或未来5天所有12:00:00的气温值。

天气预报url = https://api.openweathermap.org/data/2.5/forecast?q=Wuhan,cn&appid=800f49846586c3ba6e7052cfc89af16c

可通过浏览器插件(如:edge的JSON格式化工具)来对JSON数据在web中进行分析

js_15
1
2
3
<button id="btn">读取</button>
<div id="show"></div>
<script src="./index.js"></script>

重要:如何读取json数据

注:fetch()一种现代通用的Ajax请求方法

◼ JavaScript 可以使用 fetch() 方法向服务器发送网络请求,并从服务器获取信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 基本用法:
//(1)先将fetch()封装成异步函数:
// async为异步函数的关键字
async function get(url) {
// 等待,await必须在async函数中使用
let res = await fetch(url); // 调用fetch(),前面要加await
let json = await res.json(); // 将res(服务器响应)解析为JSON格式
return json;
}
//(2)然后调用封装的函数:
async function test(url) {
// 还是要加await,且函数必须是async
let data = await get(url);
// ...处理data
}

注:async/await是一种异步编程模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
async function get(url) { 
let res = await fetch(url); // 调用fetch(),前面要加await
let json = await res.json(); // 将res(服务器响应)解析为JSON格式
return json;
}

let url = "https://api.openweathermap.org/data/2.5/forecast?q=Wuhan,cn&appid=800f49846586c3ba6e7052cfc89af16c";

let show = document.getElementById("show");
show.innerHTML = "未来5天12点气温:<br>";

let btn = document.getElementById("btn");
btn.addEventListener("click", async () => {
let weather = await get(url); //调用get
console.log(weather);
// 解析json
// list字段存放天气信息,该值为json数组
let list = weather.list;
for ( let x of list ) {
let d = new Date(x.dt_txt); // dt_txt字段存放的是日期时间串
if ( d.getHours() == 12 ) {
let temp = x.main.temp - 273.15; //temp为K氏温度值,转为摄氏度
show.innerHTML += d.toLocaleDateString() + " 12:00温度:" + temp.toFixed(2) + "<br>"; // toFixed(2)保留2位小数
}
}
});
示例2:JSON + script模板
js_16
1
2
3
4
5
6
7
8
9
10
[
{
"name": "武汉科技大学",
"site": "https://www.wust.edu.cn"
},
{
"name": "武汉大学",
"site": "https://www.whu.edu.cn"
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<section>
<div class="navbar">
<ul class="nav">
<!-- id="tpl" 的模板将被插入到此处 -->
</ul>
</div>
</section>

<!-- ★ 定义script模板 ★ -->
<script type="text/template" id="tpl">
// 此处设置两个占位字符串,后面将把data.json相关数据填充进来
<li><a href="{{site}}" class="link">{{name}}</a></li>
</script>

<!-- 加载js -->
<script src="./index.js"></script>

script模板用法说明:

◼ script模板用type=”text/template”声明

◼ script模板中的内容不会被执行,也不会显示在页面上

◼ script模板中的内容可以在其他script里通过获取插入到html页面中

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// fetch函数
async function get(url) {
let res = await fetch(url); // 调用fetch(),前面要加await
let json = await res.json(); // 将res(服务器响应)解析为JSON格式
return json;
}

async function run() {
// colleges是JSON数组
let colleges = await get("data.json");
// 获得id=tpl的script模板的内部内容(innerHTML)
let tpl = document.getElementById("tpl").innerHTML;
// 使用map遍历colleges数组:填充模板并返回html串
let html = colleges.map( (college) => {
// 回顾:数组map用法
// 替换script模板内容
// 用遍历的对象数据替换模板中的占位符
let result = tpl
.replace( "{{site}}", college.site )
.replace( "{{name}}", college.name );
return result;
}).join(""); //map返回的是数组,使用join函数把数组元素连接为字符串
// 将生成的模板内容填充到.nav标签中
document.querySelector(".nav").innerHTML = html;
} //end run
run(); // 执行一下

运行情况

js_17

Module模块化

◼ 随着应用规模不断扩大,需要把JS代码拆分到不同的文件,进行多人协作开发,但会带来问题,比如: 不同js文件之间很容易出现命名冲突 – 通过模块化机制解决。

js_18

模块机制特点

◼ 模块机制特点:与面向对象的概念类似

​ ◼ 每个模块都有自己的作用域,外部模块不能直接访问

​ ◼ 模块可以导出变量或方法给外部模块访问,导出的方法可以访问自身模块的内部成员

​ ◼ 模块可以导入其他模块导出的方法或变量

Module基本命令

◼ 导出单个元素

1
2
export element 或 export default element
// 这个称为默认导出,一个模块只能有一个export default导出,默认导出的元素,在导入时可以自定义名称

◼ 导出多个元素

1
export { element1,element2,.... }

◼ 导入单个元素:如果导入有相同的element名时,可使用as重命名

1
import element [as 别名] from ".js文件"

◼ 导入多个元素

1
2
import { element1 [as 别名], element2 [as 别名], … } from ".js文件"
import * as 命名空间 from "module-name" 导入整个模块的内容

示例1

新建一个demo项目文件夹,js文件位于scripts文件夹

js_19

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 版本号
let version = "1.0";

// 求面积
function area(radius) {
return Math.PI * radius * radius;
}

// 求周长
function circumference(radius) {
return 2 * Math.PI * radius;
}

// 一次性导出(也可一个个导出)
export { version, area, circumference };
1
2
3
4
5
6
7
8
<script type="module">
// 使用*导出到一个命名空间circle
import * as circle from "./scripts/circle.js";
// 使用circle模块
console.log( "版本:" + circle.version );
console.log( "圆面积:" + circle.area(4) );
console.log( "圆周长:" + circle.circumference(14) );
</script>
js_20

示例2

新建一个demo项目文件夹,js文件位于scripts文件夹

js_21

user.js

1
2
3
4
5
6
7
8
9
10
11
// 该模块只导出一个默认成员
export default class User {
constructor() {
this.name = "";
}
setName(name) {
if (name.length >= 2) {
this.name = name;
}
}
}

store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 导入user模块的默认导出成员
// 建议用相对路径名
import User from "./user.js";

// _users是模块内部私有成员
let _users = [ ];

// 导出addUser方法 (单个导出)
export function addUser(name) {
let user = new User();
user.setName(name);
_users.push(user);
}

// 导出getUserCount方法 (单个导出)
export function getUserCount() {
return _users.length;
}

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 使用*导出到一个命名空间store
import * as store from "./store.js";

// 或者使用下面写法
// import { addUser, getUserCount } from './store.js'

// _name和_users都是模块内部私有成员
let _name = "Tom";
let _users = 0;

// 调用store模块导出的方法addUser
store.addUser(_name);
// 调用store模块导出的方法getUserCount
_users = store.getUserCount();

// 直接测试一下
console.log(_users);

问题及处理方法

问题

今天写了一个H5 的小demo,然后在浏览器中运行时就报了这个错误。

from origin ‘null’ has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome-extension, edge, chrome-untrusted, https, isolated-app.

原因分析

加载js文件时使用了file协议,该协议会导致跨域,而使用http、https等协议时则没有跨域问题。

解决方案

VSCode 安装插件Live Server

js_22

底部注意切换

切换前:

js_23

切换后:

js_24

注:如果只在单个html文件中进行上述操作会出现error:Open a folder or workspace... (File -> Open Folder)

原因是文件没有在文件夹中打开。

感谢:

【VSCode】from origin ‘null‘ has been blocked by CORS policy: Cross origin requests are only supported_戈叁铭的博客-CSDN博客_live server跨域 vscode

VsCode 使用 live Server 插件 报Open a folder or workspace…_跳墙网 (tqwba.com)

提供的技术指导

 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
Unique Visitor Page View