JavaScript
整理 JavaScript 模块、函数、对象、this 和页面交互等基础知识。
JavaScript
JavaScript 教程
在 HTML 中,可以通过 <script> 内联 JavaScript,也可以用 src 引入脚本文件。
能够在 HTML 文档中放置任意数量的脚本。
脚本可被放置与 HTML 页面的 <body> 或 <head> 部分中,或兼而有之。
<script src="myScript.js"></script>
注意是 src是引用 js 的方式。
通过 const 定义的变量与 let 变量类似,但==不能重新赋值。==
模板字面量_提供了一种将变量和表达式插入字符串的简单方法--${...}
箭头函数
hello = () => {
return "Hello World!";
}
模块(modules)
导出
JavaScript 模块允许您将代码分解成单独的文件。
这会使维护代码库更加容易。
模块是使用 import 语句从外部文件导入的。
模块还依赖于 < script > 标签中的 type="module"。
<script type="module">
import message from "./message.js";
</script>
命名导出(Named Exports)
让我们创建一个名为 person.js 的文件,并在其中填充我们要导出的内容。
您可以通过两种方式创建命名导出。一种是逐个内联创建,另一种是在文件底部一次性全部创建。
逐个内联创建:
person.js
export const name = "Bill";
export const age = 19;
在文件底部一次性创建:
person.js
const name = "Bill";
const age = 19;
export {name, age};
默认导出(Default Exports)
让我们创建另一个名为 message.js 的文件,并用其演示默认导出。
一个文件中只能有一个默认导出。
message.js
const message = () => {
const name = "Bill";
const age = 19;
return name + ' is ' + age + 'years old.';
};
export default message;
导入
您可以通过两种方式将模块导入到文件中,具体取决于它们是命名导出还是默认导出。
命名导出是使用大括号构造的。默认导出不是。
从命名导出中导入
从文件 person.js 导入命名导出:
import { name, age } from "./person.js";
从默认导出导入
从文件message.js导入默认导出:
import message from "./message.js";
JavaScript 性能优化
-
减少循环中的活动
-
减少 DOM 访问
-
缩减 DOM 规模
-
避免不必要的变量
-
延迟 JavaScript 加载
-
避免使用 with
执行期上下文
当函数执行时(准确来说,是在函数发生预编译的前一刻),会创建一个执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境。
每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立且独一无二的。当函数执行完毕,它所产生的执行期上下文会被销毁。
参考链接:https://www.cnblogs.com/chenyingjie1207/p/9966036.html
JavaScript 对象
set
JavaScript 的 Set(集合)是一组唯一值的集合。
每个值只能在 Set 中出现一次。
Set 可以容纳任何数据类型的值。
map
Map 保存键值对,其中键可以是任何数据类型。
Map 会记住键的原始插入顺序。
Map 提供表示映射大小的属性。
JavaScript 函数
参数传递
JavaScript 参数按值传递。对象传递的是引用值的副本:修改对象属性会被外部看到,给参数重新赋值则不会改变调用者的变量。
函数声明不限定实参数量,也不会自动检查参数类型;缺少的参数通常为 undefined。
this 指向
普通函数的 this 取决于调用方式:
obj.fn():通常为obj。new Fn():为正在创建的实例。- 独立调用
fn():严格模式下为undefined;非严格模式下会替换为全局对象,在浏览器中通常是window。 - DOM 事件的普通监听函数:通常为
event.currentTarget。 call、apply、bind:显式指定普通函数的this。
箭头函数没有自己的 this,使用外层作用域的值,不能通过上述方法重新绑定。
参考:MDN this。下面独立调用返回 window 的示例以浏览器非严格模式为前提。
第 1 条的举例:
function fun() {
console.log(this);
console.log(this.name);
}
var obj1 = {
name: 'smyh',
sayName: fun,
};
var obj2 = {
name: 'vae',
sayName: fun,
};
var name = '全局的name属性';
//以函数形式调用,this是window
fun(); //可以理解成 window.fun()
打印结果:
Window
全局的name属性
上面的举例可以看出,this 指向的是 window 对象,所以 this.name 指的是全局的 name。
第 2 条的举例:
function fun() {
console.log(this);
console.log(this.name);
}
var obj1 = {
name: 'smyh',
sayName: fun,
};
var obj2 = {
name: 'vae',
sayName: fun,
};
var name = '全局的name属性';
//以方法的形式调用,this是调用方法的对象
obj2.sayName();
打印结果:
Object
vae
上面的举例可以看出,this 指向的是 对象 obj2 ,所以 this.name 指的是 obj2.name。
ES6 箭头函数中 this 的指向
ES6 中的箭头函数并不使用上面的准则,而是会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。
改变函数内部的 this 指向
JS 专门为我们提供了一些方法来改变函数内部的 this 指向。常见的方法有 call()、apply()、bind() 方法。继续往下看。
call() 方法
call() 方法的作用
call() 方法的作用:可以调用一个函数,与此同时,它还可以改变这个函数内部的 this 指向。
call() 方法的另一个应用:可以实现继承。之所以能实现继承,其实是利用了上面的作用。
语法:
fn1.call(想要将this指向哪里, 函数实参1, 函数实参2);
call(null, ...) 会显式传入 null:严格模式下保留 null,非严格模式下会替换为全局对象,不能把它理解成“保持原来的 this”。
call() 方法举例
举例 1、通过 call() 调用函数:
const obj1 = {
nickName: 'qianguyihao',
age: 28,
};
function fn1() {
console.log(this);
console.log(this.nickName);
}
fn1.call(this); // this的指向并没有被改变,此时相当于 fn1();
上方代码的打印结果:
window
undefined
上面的代码,跟普通的函数调用 fn1() 没有区别。
举例 2、通过 call() 改变 this 指向:
var obj1 = {
nickName: 'qianguyihao',
age: 28,
};
function fn1(a, b) {
console.log(this);
console.log(this.nickName);
console.log(a + b);
}
fn1.call(obj1, 2, 4); // 先将 this 指向 obj1,然后执行 fn1() 函数
上方代码的打印结果:
obj1
qianguyihao
6
举例 3、通过 call() 实现继承:
// 给 Father 增加 name 和 age 属性
function Father(myName, myAge) {
this.name = myName;
this.age = myAge;
}
function Son(myName, myAge) {
// 【下面这一行,重要代码】
// 通过这一步,将 father 里面的 this 修改为 Son 里面的 this;另外,给 Son 加上相应的参数,让 Son 自动拥有 Father 里的属性。最终实现继承
Father.call(this, myName, myAge);
}
const son1 = new Son('千古壹号', 28);
console.log(JSON.stringify(son1));
上方代码中,通过 call() 方法,让 Son 继承了 Father 里面的 name 和 age 属性。
打印结果:
{"myName":"千古壹号","myAge":28}
apply() 方法
apply() 方法的作用
apply() 方法的作用:可以调用一个函数,与此同时,它还可以改变这个函数内部的 this 指向。这一点,和 call()类似。
apply() 方法的应用: 由于 apply()需要传递数组,所以它有一些巧妙应用,稍后看接下来的应用举例就知道了。
语法:
fn1.apply(想要将this指向哪里, [函数实参1, 函数实参2]);
call(null, ...) 会显式传入 null:严格模式下保留 null,非严格模式下会替换为全局对象,不能把它理解成“保持原来的 this”。
到这里可以看出, call() 和 apply() 方法的作用是相同的。唯一的区别在于,apply() 里面传入的实参,必须是数组(或者伪数组)。
apply() 方法举例
举例、通过 apply() 改变 this 指向:
var obj1 = {
nickName: 'qianguyihao',
age: 28,
};
function fn1(a) {
console.log(this);
console.log(this.nickName);
console.log(a);
}
fn1.apply(obj1, ['hello']); // 先将 this 指向 obj1,然后执行 fn1() 函数
注意,上方代码中,apply() 里面传实参时,需要以数组的形式。即便是传一个实参,也需要传数组。
打印结果:
obj1
qianguyihao
hello
apply() 方法的巧妙应用:求数组的最大值
我们知道,如果想要求数组中元素的最大值,数组本身是没有自带方法的。那怎么办呢?
虽然数组里没有获取最大值的方法,但是数值里有 Math.max(数字1,数字2,数字3) 方法,可以获取多个数值中的最大值。 另外,由于 apply() 方法在传递实参时,传的刚好是数组,所以我们可以 通过 Math.max() 和 apply() 曲线救国。
举例:求数组中多个元素的最大值:
const arr1 = [3, 7, 10, 8];
// 下面这一行代码的目的,无需改变 this 指向,所以:第一个参数填 null,或者填 Math,或者填 this 都可以。严格模式中,不让填null。
const maxValue = Math.max.apply(Math, arr1); // 求数组 arr1 中元素的最大值
console.log(maxValue);
const minValue = Math.min.apply(Math, arr1); // 求数组 arr1 中元素的最小值
console.log(minValue);
打印结果:
10
3
bind() 方法
bind() 方法的作用
bind() 方法不会调用函数,但是可以改变函数内部的 this 指向。
把call()、apply()、bind()这三个方法做一下对比,你会发现:实际开发中, bind() 方法使用得最为频繁。如果有些函数,我们不需要立即调用,但是又想改变这个函数内部的this指向,此时用 bind() 是最为合适的。
语法:
新函数 = fn1.bind(想要将this指向哪里, 函数实参1, 函数实参2);
参数:
-
第一个参数:在 fn1 函数运行时,指定 fn1 函数的this 指向。如果不需要改变 this 指向,则传 null。
-
其他参数:fn1 函数的实参。
解释:它不会调用 fn1 函数,但会返回 由指定this 和指定实参的原函数拷贝。可以看出, bind() 方法是有返回值的。
闭包
闭包(closure)的概念
闭包:如果外部作用域有权访问另外一个函数内部的局部变量时,那就产生了闭包。这个内部函数称之为闭包函数。注意,这里强调的是访问局部变量。
JavaScript 变量属于本地或全局作用域。
**全局变量能够通过闭包实现局部(私有)。
JavaScript 类
js 的类并不是对象,它是 js ==对象的模板==。
如需创建类继承,请使用 extends 关键字。 // 感觉这个和 java 很像了
==static== 关键字也和 java 用法类似
回调函数
[!NOTE] 简介 "I will call back later!"
回调 (callback) 是作为==参数传递给另一个函数的函数==
这种技术允许函数调用另一个函数
回调函数可以在另一个函数完成后运行
==将函数作为入参,只要函数名称即可,不用加其他任何东西==
通过回调使用异步js
实例
setTimeout(myFunction, 3000);
function myFunction() {
document.getElementById("demo").innerHTML = "I love You !!";
}
// 使用回调函数调用myFunction,setTimeout第一个参数是回调函数,第二个参数是多少毫秒后执行
等待文件
如果您创建函数来加载外部资源(如脚本或文件),则在内容完全加载之前无法使用这些内容。这是使用回调的最佳时机。
function myDisplayer(some) {
document.getElementById("demo").innerHTML = some;
}
function getFile(myCallback) {
let req = new XMLHttpRequest();
req.open('GET', "mycar.html");
req.onload = function() {
if (req.status == 200) {
myCallback(this.responseText);
} else {
myCallback("Error: " + req.status);
}
}
req.send();
}
getFile(myDisplayer);
JavaScript Promise
[!NOTE] 简介
"I Promise a Result!"
"Producing code(生产代码)" 是需要一些时间的代码
"Consuming code(消费代码)" 是必须等待结果的代码
Promise 是一个 JavaScript 对象,它链接生成代码和消费代码
JavaScript Promise 对象包含生产代码和对消费代码的调用:
let myPromise = new Promise(function(myResolve, myReject) {
// "Producing Code"(可能需要一些时间)
myResolve(); // 成功时
myReject(); // 出错时
});
// "Consuming Code" (必须等待一个兑现的承诺)
myPromise.then(
function(value) { /* 成功时的代码 */ },
function(error) { /* 出错时的代码 */ }
);
JavaScript Async
[!NOTE] "async and await make promises easier to write"
async 使函数返回 Promise
await 使函数等待 Promise
函数前的关键字 async 使函数返回 promise:
async function myFunction() {
return "Hello";
}
// 等同于:
async function myFunction() {
return Promise.resolve("Hello");
}
函数前的关键字 await 使函数等待 promise,我的理解是替代 promise 中的.then 后的函数,不用考虑对错的不同处理结果。
``let value = await promise;
JavaScrip Html DOM
通过 HTML DOM,JavaScript 能够访问和改变 HTML 文档的所有元素。
对象的 HTML DOM 树

- JavaScript 能改变页面中的所有 HTML 元素
- JavaScript 能改变页面中的所有 HTML 属性
- JavaScript 能改变页面中的所有 CSS 样式
- JavaScript 能删除已有的 HTML 元素和属性
- JavaScript 能添加新的 HTML 元素和属性
- JavaScript 能对页面中所有已有的 HTML 事件作出反应
- JavaScript 能在页面中创建新的 HTML 事件
JavaScript HTML DOM 动画
function animateElement() {
var animatedElement = document.getElementById("animate");
var position = 0;
var intervalId = setInterval(updatePosition, 5);
function updatePosition() {
if (position == 350) {
clearInterval(intervalId);
} else {
position++;
animatedElement.style.top = position + "px";
animatedElement.style.left = position + "px";
}
}
}
JavaScript HTML DOM 事件
onmouseover 和 onmouseout 事件可用于当用户将鼠标移至 HTML 元素上或移出时触发某个函数
onmousedown, onmouseup 以及 onclick 事件构成了完整的鼠标点击事件。
首先当鼠标按钮被点击时,onmousedown 事件被触发;然后当鼠标按钮被释放时,onmouseup 事件被触发;最后,当鼠标点击完成后,onclick 事件被触发。
var button = document.getElementById("myBtn");
button.addEventListener("mouseover", myFunction);
button.addEventListener("click", mySecondFunction);
button.addEventListener("mouseout", myThirdFunction);
JavaScript API
约束验证 DOM 方法
| 属性 | 描述 |
|---|---|
| checkValidity() | 如果 input 元素包含有效数据,则返回 true。 |
| setCustomValidity() | 设置 input 元素的 validationMessage 属性。 |
约束验证 DOM 属性
| 属性 | 描述 |
|---|---|
| validity | 包含与输入元素有效性相关的布尔属性。 |
| validationMessage | 包含当有效性为 false 时浏览器将显示的消息。 |
| willValidate | 指示是否将验证 input 元素。 |
AJAX 简介
AJAX 是开发者的梦想,因为您能够:
- 不刷新页面更新网页
- 在页面加载后从服务器请求数据
- 在页面加载后从服务器接收数据
- 在后台向服务器发送数据
什么是 AJAX?
AJAX = ==A==synchronous ==J==avaScript ==A==nd ==X==ML.
AJAX 并非编程语言。
AJAX 仅仅组合了:
- 浏览器内建的 XMLHttpRequest 对象(从 web 服务器请求数据)
- JavaScript 和 HTML DOM(显示或使用数据)
Ajax 是一个令人误导的名称。Ajax 应用程序可能使用 XML 来传输数据,但将数据作为纯文本或 JSON 文本传输也同样常见。
Ajax 允许通过与场景后面的 Web 服务器交换数据来异步更新网页。这意味着可以更新网页的部分,而不需要重新加载整个页面。
AJAX 如何工作

- 网页中发生一个事件(页面加载、按钮点击)
- 由 JavaScript 创建 XMLHttpRequest 对象
- XMLHttpRequest 对象向 web 服务器发送请求
- 服务器处理该请求
- 服务器将响应发送回网页
- 由 JavaScript 读取响应
- 由 JavaScript 执行正确的动作(比如更新页面)
AJAX - XMLHttpRequest 对象
XMLHttpRequest 对象是 AJAX 的基石。
- 创建 XMLHttpRequest 对象
- 定义回调函数
- 打开 XMLHttpRequest 对象
- 向服务器发送请求
// 创建 XMLHttpRequest 对象
httpRequest = new XMLHttpRequest();
// 定义回调函数
xhttp.onload = function() {
// 当响应准备就绪时要做什么
}
// 发送请求
// 如需向服务器发送请求,您可以使用 XMLHttpRequest 对象的 open() 和 send() 方法
xhttp.open("GET", "ajax_info.txt");
xhttp.send();
JSON
JSON 简介
JSON: ==J==ava==S==cript ==O==bject ==N==otation(JavaScript 对象标记法)。
JSON 是一种存储和交换数据的语法。
JSON 是通过 JavaScript 对象标记法书写的文本。
通过 JSON.parse() 解析数据,这些数据会成为 JavaScript 对象。
通过 JSON.stringify() 把 JavaScript 对象转换为字符串。
jQuery DOM 选择器
都有 JavaScript 语法与其对应,以后再说