Web-开发技术-JavaScript

developer.mozilla.org

什么是 JavaScript

广义的定义

JavaScript 是一种脚本语言,可以用来创建动态更新的内容,控制多媒体,制作图像动画,还有很多.

其可以动态改变 HTML 和 CSS 的值.

如:

1
2
3
4
5
6
7
8
const para = document.querySelector('p');

para.addEventListener('click', updateName);

function updateName() {
let name = prompt('输入一个新的名字:');
para.textContent = '玩家 1:' + name;
}

两类 API:

  • 浏览器 API
    • DOM API (Document Object Model API)
    • Geolocation API
    • Canvas
    • 影音类 API
  • 第三方 API

JavaScript 在页面上做了什么

浏览器在读取一个网页时,代码(HTML, CSS 和 JavaScript)将在一个运行环境(浏览器标签页)中得到执行。

也就是说, 一个浏览器标签页就是一个运行环境

在 HTML 和 CSS 集合组装成一个网页后,浏览器的 JavaScript 引擎将执行 JavaScript 代码。这保证了当 JavaScript 开始运行之前,网页的结构和样式已经就位。

也就是说, JavaScript 需要在 HTML 和 CSS 加载完成之后再加载.

浏览器安全

每个浏览器标签页就是其自身用来运行代码的独立容器(这些容器用专业术语称为“运行环境”).

每个标签页中的代码完全独立运行,而且一个标签页中的代码不能直接影响另一个标签页(或者另一个网站).

向页面添加 JavaScript

<script> 元素处理内部和外部 JavaScript 代码.

内部 JavaScript

如:

1
2
3
4
5
<script>

// 在此编写 JavaScript 代码

</script>

外部 JavaScript

如:

1
<script src="script.js" async></script>

async 异步属性, 其告知浏览器在遇到 <script> 元素时不要中断后续 HTML 内容的加载。

脚本调用策略

1
2
3
document.addEventListener("DOMContentLoaded", function() {
. . .
});

这是一个事件监听器,它监听浏览器的 DOMContentLoaded 事件,即 HTML 文档体加载、解释完毕事件。事件触发时将调用 ... 处的代码,从而避免了错误发生.

asyncdefer

两种解决脚本阻塞问题的方法:

  • async
  • defer

浏览器遇到 async 脚本时不会阻塞页面渲染,而是直接下载然后运行。这样脚本的运行次序就无法控制, 如:

1
2
3
4
5
<script async src="js/vendor/jquery.js"></script>

<script async src="js/script2.js"></script>

<script async src="js/script3.js"></script>

三者的调用顺序是不确定的.

使用 defer 属性可解决上述问题:

1
2
3
4
5
<script defer src="js/vendor/jquery.js"></script>

<script defer src="js/script2.js"></script>

<script defer src="js/script3.js"></script>

添加 defer 属性的脚本将按照在页面中出现的顺序加载.

策略:

  • 如果脚本无需等待页面解析,且无依赖独立运行,那么应使用 async。
  • 如果脚本需要等待页面解析,且依赖于其他脚本,调用这些脚本时应使用 defer,将关联的脚本按所需顺序置于 HTML 中。

注释

///* */ 两种.

JavaScript 初体验

猜数字游戏

初始设置

Math.random() 不带任何参数, 生成的数位于 0~1 之间.

letconst 来声明局部变量.

注意:

1
2
3
const guesses = document.querySelector('.guesses');
const lastResult = document.querySelector('.lastResult');
const lowOrHi = document.querySelector('.lowOrHi');

其创建一个引用, 指向指定类名的元素

1
2
3
4
5
<div class="resultParas">
<p class="guesses"></p>
<p class="lastResult"></p>
<p class="lowOrHi"></p>
</div>

在浏览器渲染时, 如 <p class="guesses"></p> 中显示的内容可以用变量 guesses 来控制.

函数 (Function)

如:

1
2
3
function checkGuess() {
alert('I am a placeholder');
}

alert 用于创建一个弹窗.

开发者工具 JavaScript 控制台中可以直接调用这个函数.

+ 进行字符串拼接.

比较运算符用 ===!==

条件语句 (Conditional)

Number() 将一个量强制转换为数字.

条件语句如:

1
2
3
4
5
6
7
if () {

} else if () {

} else {

}

事件 (Event)

侦听事件发生的结构称为事件监听器 (Event Listener),响应事件触发而运行的代码块被称为事件处理器 (Event Handler)。

如:

1
guessesSubmit.addEventListener('click', checkGuess);

补全游戏功能

创建一个 HTML 元素, 如:

1
resetButton = document.createElement('button');

将这个 HTML 元素追加到页面之后:

1
document.body.append(resetButton);

循环 (Loop)

1
2
3
4
const fruits = ['apples', 'bananas', 'cherries'];
for (const fruit of fruits) {
console.log(fruit);
}

和 Perl 中:

1
2
3
4
my @fruits = qw(apples bananas cherries);
foreach my $fruit (@fruits) {
print $fruit;
}

类似.

浅谈对象 (Object)

1
guessField.focus();

其让光标在页面加载完毕时自动放置于 <input> 输入框内.

JavaScript 中一切都是对象。对象是存储在单个分组中的相关功能的集合。

1
const guessField = document.querySelector('.guessField');

这里, 调用 document 对象的 querySelector() 方法, 用于获得一个引用.

操作浏览器对象

改变值, 如:

1
2
guessField.value = 2;
guesses.textContent = "String";

修改样式如:

1
2
3
4
guesses.style.backgroundColor = 'yellow';
guesses.style.fontSize = '200%';
guesses.style.padding = '10px';
guesses.style.boxShadow = '3px 3px 6px black';

document.querySelector() 来获取一个元素的引用:

1
const guesses = document.querySelector('.guesses');

也就是利用选择器来确定一个元素. 其只 返回符合选择器的第一个元素.

document.querySelectorAll() 获取一个包含符合选择器的所有元素的 NodeList 对象:

1
2
3
4
5
6
7
// 获取所有 class 为 "example" 的元素
const elements = document.querySelectorAll('.example');

// 遍历 NodeList 中的所有元素
elements.forEach((element) => {
// 操作元素
});

查找并解决 JavaScript 代码的错误

在浏览器运行 HTML 之后, 可以在 开发工具 JavaScript 控制台中 查看是否有语法错误.

其会提示行号, 以及错误信息.

一般, “x” 不是一个函数 这类错误可能是由于 函数名拼写错误.

concole.log() 可以把值打印到控制台。

如何存储你需要的信息 – 变量

示例:

1
2
3
4
5
6
const button = document.querySelector('button');

button.onclick = function() {
let name = prompt('What is your name?');
alert('Hello ' + name + ', nice to see you!');
}

这里 prompt 用于弹出对话框.

+ 来拼接字符串.

变量类型

数组 Array

如:

1
2
let myNameArray = ['Chris', 'Bob', 'Jim'];
let myNumberArray = [10,15,40];

用下标访问如:

1
2
myNameArray[0]; // should return 'Chris'
myNumberArray[2]; // should return 40

哈希 (在 JavaScript 就是对象)

如:

1
let dog = { name : 'Spot', breed : 'Dalmatian' };

使用如:

1
dog.name

动态类型

JavaScript 是一种“动态类型语言”,这意味着不同于其他一些语言, 如 C、JAVA,不需要指定变量将包含什么数据类型(例如 number 或 string)

可以用 typeof 来查看变量类型:

1
2
3
4
let myNumber = '500'; // oops, this is still a string
typeof myNumber;
myNumber = 500; // much better — now this is a number
typeof myNumber

文本处理 – JavaScript 中的字符串

字符串拼接用 +, 如:

1
2
3
4
let one = 'Hello, ';
let two = 'how are you?';
let joined = one + two;
joined;

将数字转换为字符串, 用数字的 toString() 方法:

1
2
3
let myNum = 123;
let myString = myNum.toString();
typeof myString;

有用的字符串方法

获取字符串的长度

字符串的用 length 属性:

1
2
let browserType = 'mozilla';
browserType.length;

(再次印证了 “JavaScript 一切都是对象” 这句话.)

查找子字符串并提取

  1. indexOf() 方法, 如:
1
browserType.indexOf('zilla');

其返回首字母的索引.

当在主字符串中找不到子字符串时, 返回 -1

  1. 知道子字符串的位置进行提取, 用 slice 方法, 如:
1
browserType.slice(0,3);

也可以:

1
browserType.slice(2);

来获取索引 2 之后的内容.

大小写转换

toLowerCase()toUpperCase() 方法, 如:

1
2
3
let radData = 'My NaMe Is MuD';
radData.toLowerCase();
radData.toUpperCase();

替换字符串的部分

replace() 方法, 将字符串中的一部分替换为另一个字符串:

1
browserType = browserType.replace('moz','van');

数组

什么是数组

在 JavaScript 中, 数组是一个包含了多个值的对象。

创建数组

如:

1
let shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles'];

获取数组长度

length 属性获取数组的长度:

1
2
sequence.length;
// should return 7

一些有用的数组方法

字符串和数组之间的转换

split() 方法将字符串拆分为数组.

如:

1
2
3
let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
let myArray = myData.split(',');
myArray;

将数组转换为字符串, 用 join() 方法:

1
2
let myNewString = myArray.join(',');
myNewString;

添加和删除数组项

  1. 使用 push()pop() 方法, 作用于数组尾部:

    1
    2
    3
    let myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];
    myArray.push('Cardiff');
    let removedItem = myArray.pop();
  2. 也可以用 unshift()shift() 方法, 作用于数组头部

    1
    2
    myArray.unshift('Edinburgh');
    let removedItem = myArray.shift();

条件语句

逻辑运算符: 与, 或, 非

同样为 &&, ||!

switch 语句

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
switch (表达式) {
case 选择1:
运行这段代码
break;

case 选择2:
否则,运行这段代码
break;

// 包含尽可能多的情况

default:
实际上,仅仅运行这段代码
}

三元运算符

? :, 如:

1
2
3
const greeting = isBirthday
? '小王生日快乐,祝你有个美好的一天!'
: '小王早上好。';

循环

for 循环

1
2
3
4
5
6
for (var i = 0; i < 100; i++) {
ctx.beginPath();
ctx.fillStyle = 'rgba(255,0,0,0.5)';
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
ctx.fill();
}

同样可以用 break 跳出循环以及用 continue 跳过迭代.

whiledo ... while 语句

while 语句的格式如:

1
2
3
4
5
6
initializer
while (exit-condition) {
// code to run

final-expression
}

do ... while 语句的格式为:

1
2
3
4
5
6
initializer
do {
// code to run

final-expression
} while (exit-condition)

函数

浏览器内置函数

内置浏览器函数不是核心 JavaScript 语言的一部分——被定义为浏览器 API 的一部分,它建立在默认语言之上,以提供更多的功能.

匿名函数

通常将匿名函数与事件处理程序一起使用:

1
2
3
4
5
var myButton = document.querySelector('button');

myButton.onclick = function() {
alert('hello');
}

也可以分配给变量, 如:

1
2
3
4
var myGreeting = function() {
alert('hello');
}
myGreeting();

事件介绍

事件是您在编程时系统内发生的动作或者发生的事情——系统会在事件出现时产生或触发某种信号,并且会提供一个自动加载某种动作(列如:运行一些代码)的机制.

常见的事件有:

  • 用户在某个元素上点击鼠标或悬停光标。
  • 用户在键盘中按下某个按键。
  • 用户调整浏览器的大小或者关闭浏览器窗口。
  • 一个网页停止加载。
  • 提交表单。
  • 播放、暂停、关闭视频。
  • 发生错误。

每个可用的事件都会有一个事件处理器,也就是事件触发时会运行的代码块。当我们定义了一个用来回应事件被激发的代码块的时候,我们说我们注册了一个事件处理器。注意事件处理器有时候被叫做事件监听器.

一个简单的例子

当按下 button 时, 随机改变背景颜色.

创建 button 如:

1
<button>Change color</button>

JavaScript 处理代码:

1
2
3
4
5
6
7
8
9
10
const btn = document.querySelector('button');

function random(number) {
return Math.floor(Math.random()*(number+1));
}

btn.onclick = function() {
const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
document.body.style.backgroundColor = rndCol;
}

使用网页事件的方式

可以通过多种不同的方法将事件侦听器代码添加到网页,以便在关联的事件被触发时运行它.

事件处理器属性

onclick 属性:

1
2
3
4
5
6
const btn = document.querySelector('button');

btn.onclick = function() {
const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
document.body.style.backgroundColor = rndCol;
}

其相当于注册一个事件处理器, 将一些代码赋值给它的时候,只要事件触发代码就会运行

也可以如:

1
2
3
4
5
6
7
8
const btn = document.querySelector('button');

function bgChange() {
const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
document.body.style.backgroundColor = rndCol;
}

btn.onclick = bgChange;

addEventListener()removeEventLisener()

addEventListener() 方法用于添加事件处理器.

removeEventLisener() 方法用于移除事件处理器.

尽可能用这两个方法处理事件.

如:

1
2
3
4
5
6
7
8
9
const btn = document.querySelector('button');

function bgChange() {
const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
document.body.style.backgroundColor = rndCol;
}

btn.addEventListener('click', bgChange);
btn.removeEventListener('click', bgChange);

addEventListener() 方法可以给同一个监听器注册多个处理器:

1
2
3
4
5
6
7
// later one will cover former one
myElement.onclick = functionA;
myElement.onclick = functionB;

// run both two
myElement.addEventListener('click', functionA);
myElement.addEventListener('click', functionB);

其他事件概念

事件对象

其固定名称为 event, enve, 其会被自动传递给事件处理函数, 来提供额外信息:

1
2
3
4
5
6
7
function bgChange(e) {
const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
e.target.style.backgroundColor = rndCol;
console.log(e);
}

btn.addEventListener('click', bgChange);

这里的 e.target 就指代 btn 按钮本身.

不是只有 button 才有 onclick 属性:

1
2
3
4
5
6
7
const divs = document.querySelectorAll('div');

for (let i = 0; i < divs.length; i++) {
divs[i].onclick = function(e) {
e.target.style.backgroundColor = bgChange();
}
}

阻止默认行为

在事件对象上调用 preventDefault() 函数:

1
2
3
4
5
6
7
8
9
10
11
12
const form = document.querySelector('form');
const fname = document.getElementById('fname');
const lname = document.getElementById('lname');
const submit = document.getElementById('submit');
const para = document.querySelector('p');

form.onsubmit = function(e) {
if (fname.value === '' || lname.value === '') {
e.preventDefault();
para.textContent = 'You need to fill in both names!';
}
}

事件冒泡及捕获

事件冒泡和捕捉是两种机制,主要描述当在一个元素上有两个相同类型的事件处理器被激活会发生什么.

现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。在捕获阶段:

  • 浏览器检查元素的最外层祖先 <html>,是否在捕获阶段中注册了一个 onclick 事件处理程序,如果是,则运行它。
  • 然后,它移动到 <html> 中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素。

在冒泡阶段,恰恰相反:

  • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个 onclick 事件处理程序,如果是,则运行它
  • 然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达 <html> 元素。

在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册。

stopPropagation() 修复问题

在事件对象上调用 stopPropagation() 方法, 可以让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行 (不会向上冒泡).

图片库

JavaScript 对象基础

在 JavaScript 中,大多数事物都是对象.

对象基础

对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法).

创建一个对象, 如:

1
var person = {};

更新对象:

1
2
3
4
5
6
7
8
9
10
11
12
var person = {
name : ['Bob', 'Smith'],
age : 32,
gender : 'male',
interests : ['music', 'skiing'],
bio : function() {
alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
},
greeting: function() {
alert('Hi! I\'m ' + this.name[0] + '.');
}
};

点表示法

点表示法 (dot notation) 来访问对象的属性和方法.

对象的名字表现为一个命名空间 (namespace).

访问如:

1
2
3
person.age
person.interests[1]
person.bio()

子命名空间

一个对象来做另一个对象成员的值:

1
2
3
4
name : {
first : 'Bob',
last : 'Smith'
},

访问如:

1
2
person.name.first
person.name.last

括号表示法

如:

1
2
person.age
person.name.first

可以替换为:

1
2
person['age']
person['name']['first']

因此对象有时被称之为关联数组 (associative array)

设置对象成员

可以直接创建新成员:

1
2
person['eyes'] = 'hazel'
person.farewell = function() { alert("Bye everybody!") }

this 的含义

关键字 this 指向了当前代码运行时的对象, 如:

1
2
3
4
5
6
7
8
9
10
11
12
13
var person1 = {
name : 'Chris',
greeting: function() {
alert('Hi! I\'m ' + this.name + '.');
}
}

var person2 = {
name : 'Brian',
greeting: function() {
alert('Hi! I\'m ' + this.name + '.');
}
}

每个页面在加载完毕后,会有一个 Document 的实例被创建,叫做 document,它代表了整个页面的结构,内容和一些功能,比如页面的 URL。同样的,这意味 document 有一些可用的方法和属性。

如:

1
2
var myDiv = document.createElement('div');
var myVideo = document.querySelector('video');

对象原型

原型是 JavaScript 对象相互继承特性的机制.

原型链

JavaScript 中所有的对象都有一个内置属性,称为它的 prototype(原型)。它本身是一个对象,故原型对象也会有它自己的原型,逐渐构成了原型链。原型链终止于拥有 null 作为其原型的对象上。

访问对象原型的标准方法是

1
Object.getPrototypeOf(myObject) // Object {  }

当你试图访问一个对象的属性时:如果在对象本身中找不到该属性,就会在原型中搜索该属性。如果仍然找不到该属性,那么就搜索原型的原型,以此类推,直到找到该属性,或者到达链的末端,在这种情况下,返回 undefined.

有个对象叫 Object.prototype,它是最基础的原型,所有对象默认都拥有它。Object.prototype 的原型是 null,所以它位于原型链的终点

如:

一个对象链的示例:

1
2
3
4
5
6
7
8
9
10
11
const myDate = new Date();
let object = myDate;

do {
object = Object.getPrototypeOf(object);
console.log(object);
} while (object);

// Date.prototype
// Object { }
// null

属性遮蔽

如:

1
2
3
4
5
6
7
8
9
const myDate = new Date(1995, 11, 17);

console.log(myDate.getYear()); // 95

myDate.getYear = function () {
console.log("别的东西!");
};

myDate.getYear(); // '别的东西!'

设置原型

介绍两种方法:

  • Object.create()
  • 构造函数

Object.create()

其用于创建一个新对象, 并可以指定一个对象作为对象原型:

1
2
3
4
5
6
7
8
const personPrototype = {
greet() {
console.log("hello!");
},
};

const carl = Object.create(personPrototype);
carl.greet(); // hello!

使用构造函数

在 JavaScript 中,所有的函数都有一个名为 prototype 的属性。当你调用一个函数作为构造函数时,这个属性被设置为新构造对象的原型.

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
const personPrototype = {
greet() {
console.log(`你好,我的名字是 ${this.name}!`);
},
};

function Person(name) {
this.name = name;
}

Object.assign(Person.prototype, personPrototype);
// 或
// Person.prototype.greet = personPrototype.greet;

在这段代码之后,使用 Person() 创建的对象将获得 Person.prototype 作为其原型,其中自动包含 greet 方法:

1
2
const reuben = new Person("Reuben");
reuben.greet(); // 你好,我的名字是 Reuben!

自有属性

直接在对象中定义的属性, 被称为自有属性,你可以使用静态方法 Object.hasOwn() 检查一个属性是否是自有属性:

1
2
3
4
const irma = new Person("Irma");

console.log(Object.hasOwn(irma, "name")); // true
console.log(Object.hasOwn(irma, "greet")); // false

面向对象编程基本概念

类与实例

就其本身而言,类并不做任何事情,类只是一种用于创建具体对象的模板.

通常来说,需要将构造函数作为类定义的一部分明确声明,并且构造函数通常具有和类名相同的函数名。

在 JavaScript 中, 经常会使用函数或对象字面量创建对象, 也就是说, JavaScript 可以在没有特定的类定义的情况下创建对象.

尽管原型链看起来很像是继承的层级结构,并且在某些方面,原型链的行为与继承的行为也很类似,但是在其他方面,二者之间仍然存在区别:

  • 在继承方式下,当一个子类完成继承时,由该子类所创建的对象既具有其子类中单独定义的属性,又具有其父类中定义的属性(以及父类的父类,依此类推)
  • 在原型链中,每一个层级都代表了一个不同的对象,不同的对象之间通过 __proto__ 属性链接起来

原型链的行为并不太像是继承,而更像是委派(delegation).

JavaScript 中的类

类和构造函数

可以用 class 关键字声明一个类, 用 constructor 关键字声明构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {

name;

constructor(name) {
this.name = name;
}

introduceSelf() {
console.log(`Hi! I'm ${this.name}`);
}

}

也可以给 name 设置默认值, 如:

1
name = '';

创建一个实例如:

1
2
3
const giles = new Person('Giles');

giles.introduceSelf(); // Hi! I'm Giles

省略构造函数

在不需要初始化任何内容时, 可以省略构造函数, 此时会生成默认的构造函数:

1
2
3
4
5
6
7
8
9
10
11
class Animal {

sleep() {
console.log('zzzzzzz');
}

}

const spot = new Animal();

spot.sleep(); // 'zzzzzzz'

继承

extends 关键字来继承:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Professor extends Person {

teaches;

constructor(name, teaches) {
super(name);
this.teaches = teaches;
}

introduceSelf() {
console.log(`My name is ${this.name}, and I will be your ${this.teaches} professor.`);
}

grade(paper) {
const grade = Math.floor(Math.random() * (5 - 1) + 1);
console.log(grade);
}

}

构造函数中需要做的第一件事是使用 super() 调用父类的构造函数,并传递 name 参数.

封装

#varname 来声明私有变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Student extends Person {

#year;

constructor(name, year) {
super(name);
this.#year = year;
}


introduceSelf() {
console.log(`Hi! I'm ${this.name}, and I'm in year ${this.#year}.`);
}

canStudyArchery() {
return this.#year > 1;
}

}

这里的 year 就是私有变量.

私有方法

同样以 # 开头, 可以声明私有方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Example {

somePublicMethod() {
this.#somePrivateMethod();
}

#somePrivateMethod() {
console.log('You called me?');
}

}

const myExample = new Example();

myExample.somePublicMethod(); // 'You called me?'

myExample.#somePrivateMethod(); // SyntaxError

使用 JSON

JSON (JavaScript Object Notation), 用于将结构化数据表示为 JavaScript 对象的标准格式,通常用于在网站上表示和传输数据.

什么是 JSON

JSON 是一种按照 JavaScript 对象语法的数据格式, 其基于 JavaScript 语法,但它独立于 JavaScript.

一个 JSON 对象可以被储存在它自己的文件中,这基本上就是一个文本文件,扩展名为 .json,还有 MIME type 用于 application/json.

JSON 结构

JSON 示例如:

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
41
{
"squadName" : "Super hero squad",
"homeTown" : "Metro City",
"formed" : 2016,
"secretBase" : "Super tower",
"active" : true,
"members" : [
{
"name" : "Molecule Man",
"age" : 29,
"secretIdentity" : "Dan Jukes",
"powers" : [
"Radiation resistance",
"Turning tiny",
"Radiation blast"
]
},
{
"name" : "Madame Uppercut",
"age" : 39,
"secretIdentity" : "Jane Wilson",
"powers" : [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
},
{
"name" : "Eternal Flame",
"age" : 1000000,
"secretIdentity" : "Unknown",
"powers" : [
"Immortality",
"Heat Immunity",
"Inferno",
"Teleportation",
"Interdimensional travel"
]
}
]
}

JSON 数组

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"name" : "Molecule Man",
"age" : 29,
"secretIdentity" : "Dan Jukes",
"powers" : [
"Radiation resistance",
"Turning tiny",
"Radiation blast"
]
},
{
"name" : "Madame Uppercut",
"age" : 39,
"secretIdentity" : "Jane Wilson",
"powers" : [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
}
]

其也是合法的 JSON 对象.

注意事项

  • JSON 是一种纯数据格式,它只包含属性,没有方法。
  • JSON 要求在字符串和属性名称周围使用双引号。单引号无效。
  • 一个错位的逗号或分号会导致 JSON 文件出错。
  • JSON 可以将任何标准合法的 JSON 数据格式化保存,不只是数组和对象。比如,一个单一的字符串或者数字可以是合法的 JSON 对象。虽然不是特别有用处……
  • 与 JavaScript 代码中对象属性可以不加引号不同,JSON 中只有带引号的字符串可以用作属性。

异步 JavaScript 简介

异步编程技术使你的程序可以在执行一个可能长期运行的任务的同时继续对其他事件做出反应而不必等待任务完成。与此同时,你的程序也将在任务完成后显示结果.

同步编程

如:

1
2
3
4
const name = 'Miriam';
const greeting = `Hello, my name is ${name}!`;
console.log(greeting);
// "Hello, my name is Miriam!"

代码是一行一行执行的.

浏览器会等待代码的解析和工作,在上一行完成后才会执行下一行.

事件处理程序

事件处理程序实际上就是异步编程的一种形式:你提供的函数(事件处理程序)将在事件发生时被调用(而不是立即被调用)。如果“事件”是“异步操作已经完成”,那么你就可以看到事件如何被用来通知调用者异步函数调用的结果的。

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const log = document.querySelector('.event-log');
document.querySelector('#xhr').addEventListener('click', () => {
log.textContent = '';
const xhr = new XMLHttpRequest();
xhr.addEventListener('loadend', () => {
log.textContent = `${log.textContent}完成!状态码:${xhr.status}`;
});
xhr.open('GET', 'https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json');
xhr.send();
log.textContent = `${log.textContent}请求已发起\n`;});
document.querySelector('#reload').addEventListener('click', () => {
log.textContent = '';
document.location.reload();
});

回调

事件处理程序是一种特殊类型的回调函数。而回调函数则是一个被传递到另一个函数中的会在适当的时候被调用的函数.

但在嵌套回调 (回调函数中调用回调函数) 中, 代码会变得难以理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function doStep1(init, callback) {
const result = init + 1;
callback(result);
}
function doStep2(init, callback) {
const result = init + 2;
callback(result);
}
function doStep3(init, callback) {
const result = init + 3;
callback(result);
}
function doOperation() {
doStep1(0, result1 => {
doStep2(result1, result2 => {
doStep3(result2, result3 => {
console.log(`结果:${result3}`);
});
});
});
}
doOperation();

如何使用 Promise

Promise 是现代 JavaScript 中异步编程的基础,是一个由异步函数返回的可以向我们指示当前操作所处的状态的对象。在 Promise 返回给调用者的时候,操作往往还没有完成,但 Promise 对象可以让我们操作最终完成时对其进行处理(无论成功还是失败).

使用 fetch() API

fetch() API 是一个现代的、基于 Promise 的、用于替代 XMLHttpRequest 的方法.

fetch() API 来发起请求获取服务器上的一个 JSON 文件:

1
2
3
4
5
6
7
8
9
const fetchPromise = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');

console.log(fetchPromise);

fetchPromise.then( response => {
console.log(`已收到响应:${response.status}`);
});

console.log("已发送请求……");

DOM 概述

DOM 将文档表示为节点和对象.

document 代表 HTML 文档本身.

DOM 由多个 API 构建而成, 如:

  • HTML DOM API
  • SVG API

DOM 被设计成与特定编程语言相独立, 使文档的结构表述可以通过一致的 API 获得. 如用 Python 为:

1
2
3
4
5
6
# Python DOM 示例
import xml.dom.minidom as m
doc = m.parse(r"C:\Projects\Py\chap1.xml")
doc.nodeName # 文档对象的 DOM 属性
p_list = doc.getElementsByTagName("para")

严格来说, 名不是每一个节点都是一个元素.

在一个 HTML 文档中, 一个对象可以是一个元素节点, 也可以是一个文本节点或属性节点.

常见接口:

  • document.querySelector(), 返回选择器组匹配的第一个 Element 对象
  • document.querySelectorAll(), 返回选择器组匹配的元素列表, NodeList 对象
  • document.createElement(), 创建一个指定标签
  • element.setAttribute(name, value), 设置某个元素的属性
  • element.getAttribute(name, value), 获取某个元素的属性
  • element.removeAttribute(name, value), 删除某个元素的属性
  • EventTarget.addEventListener(), 这里的 EventTarget 可以是 Element, Document, Window 等, 其注册指定的监听器
  • EventTarget.removeEventLisener, 移除监听器

Web-开发技术-JavaScript
http://example.com/2023/05/15/Web-开发技术-JavaScript/
作者
Jie
发布于
2023年5月15日
许可协议