Web 前端开发技术 —— JavaScript
总结 JavaScript
内容!
文章目录
- Web 前端开发技术 —— JavaScript
- 一、js 的引用方式与执行顺序
- 1、引用方式
- 在标签中直接写 js 代码
- 复用 js 代码
- 通过 import 方式
- 2、执行顺序
- 3、html、css、js 三者之间的关系
- 二、变量与运算符
- 变量
- 运算符
- 三、输入和输出
- 输入
- 输出
- 常用输出
- 格式化输出字符串
- 四、判断语句
- 五、循环语句
- 六、对象
- 创建
- 调用
- 对象的解构
- 对象的展开
- 七、数组
- 定义
- 访问和赋值
- 数组的常用属性和函数
- 数组展开
- 八、函数
- 定义
- 方式 1(一般定义方式)
- 方式 2(定义一个函数变量)
- 方式 3(方式 2 的简写方式,箭头函数)
- 箭头函数的简写方式
- 函数调用
- 返回值
- 九、类
- 1. 类与实例的关系
- 2. 类的定义
- 3. 继承
- 4. 静态方法与静态变量
- 静态方法
- 静态变量
- 5. ES6 语法补充
- export
- 使用bind()函数绑定this取值
- 箭头函数不重新绑定this的取值
- 十、事件
- 鼠标
- 键盘
- 十一、常用库
- 第一:jQuery
- 1. 安装
- 2. 选择器
- 3. 事件
- 4. 标签的隐藏和显示
- 5. 标签的添加和删除
- 6. ajax
- 第二:setTimeout与setInterval
- 第三:requestAnimationFrame
- 第四:Map与Set
- map
- set
- 第五:localStorage
- 第六:JSON
- 第七、WebSocket
- 第八、window
- 第九、canvas
一、js 的引用方式与执行顺序
引用 js 代码方式与使用加载 css
文件类似,在 HTML
页面中的任意想要执行 js
代码的位置加上<script type="module"></script>
标签即可。
1、引用方式
在标签中直接写 js 代码
<script type="module">
中的 type=“modul” 的作用**:会严格限制每个变量等在应有的作用域内,不会对作用域外其它部分 js
代码产生影响。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 方式1 -->
<script type="module">
let x = 3;
console.log(x);
</script>
</body>
</html>
复用 js 代码
让一份代码在多个页面里执行,用一个文件管理 js
代码,然后在页面任意位置引入 js文件
即可。
只能引用一个文件。
// /static/js/index.js文件中的内容为
console.log("Hello World")
<!-- <script type="module"></script>中的内容为: -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 方式2 -->
<script type="module" src="/js课/static/js/index.js"></script>
</body>
</html>
通过 import 方式
将 js 文件内某些内容通过 import
关键字引入到当前作用域(只希望用到 js 文件中的某些变量或函数)。
通过 export
将其它文件可以调用的变量、函数、类等暴露出来。
通过 import
将 js 文件里暴露出来的内容引入到当前作用域。
可以引入多个文件。
// /static/js/index.js文件中的内容为
let name = "yjx";
let age = 18
function print() {
console.log("My name is " + name);
}
export {
name,
print
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="module">
import { name, print } from "/js课/static/js/index.js";
console.log(name);
print();
</script>
</body>
</html>
2、执行顺序
js
与C++
和Java
不同的地方在于C++
和Java
执行从主函数的入口开始执行,而js
代码没有明确的执行入口,按照在页面中从上到下的顺序依次执行,与渲染html
和css
的顺序一样。- 事件驱动方式执行(更多用):页面中有很多事件(例如,点击、移动、双击、修改、输入),通过事件来触发函数执行相应的功能。
3、html、css、js 三者之间的关系
css
可以操控html
,反之不行。js
可以操控css
和html
。js 可以改变 html 的结构,在 html 里面随意添加和删除标签和内容,也可以通过 js 改变 css 对应样式。
二、变量与运算符
变量
-
变量的定义
- let 用来定义变量(可以重新赋值),不需要声明类型。如果一个变量
- 只声明不定义:
let a;
- 定义若干个变量:
let x = 3, name = "yjx";
- 只声明不定义:
- const 用来定义常量
const y = 6;
,无法重新赋值,只能赋值一次,也不能被重新声明
- let 用来定义变量(可以重新赋值),不需要声明类型。如果一个变量
-
变量类型动态变化:let 定义变量时,不用声明类型,js 中的变量类型是动态的(一个变量的类型可以在执行过程当中变化)。
let name = "yjx", x = 6; let d = { name: "yjx", age: 20, }
-
变量类型
-
number 数值变量:
js
中不管是整数还是浮点数统一为number
类型。例如,1
,2.5
。 -
string 字符串:
- 不区分单引号
''
和双引号""
- 字符串中每一个字符都是只读变量,不能修改,要修改的话通过 substr 重新构造
substr
函数,使用方法同 C++
- 不区分单引号
-
boolean 布尔值:
true
,false
-
undefined:未定义的变量
-
object:对象类型,类似于 C++ 中的指针(地址),例如,
[1,2,3]
,{name:"yjx"}
,null
。-
类似于 C++ 中的
map
和 python 中的字典
的写法,js 中对象的关键字一般都是字符串,每个关键字对应的值可以是任意类型。对象中的关键字既可以用引号括起来也可以不用引号括起来let d = { // 定义的时候用冒号 : name: 'yxc', age: 18, }; // 等价于下面写法 let d = { "name": 'yxc', "age": 18, }; // 直接输出一个对象:`console.log(b);`,类型为 object
-
调用 value
- 方式 1:
d["name"]
或d['name'];
,引号必须加 - 方式 2:
d.name;
- 方式 1:
-
动态添加值:
d["school"] = "pku";
或者d.school = "pku";
-
删除对象中的某个 value:
delete d.school;
-
null
也是一种 value,表示空对象 -
undefined
只声明未定义。例如:let x;
类型就是 undefined,因为 js 判断类型是根据具体的值来判断数据类型
-
-
引用数据类型
- 引用数据类型解释
- 引用类型的值是保存在内存中的对象
- 当一个变量是一个对象时,实际上变量中保存的并不是对象本身而是对象的引用
- 当从一个变量向另一个变量复制引用类型的值时,会将对象的引用复制到变量中,并不是创建一个新的对象
- 这时,两个变量指向的是同一个对象。因此,改变其中一个变量会影响另一个
- 引用数据类型解释
-
运算符
**
表示乘方===
等于,!==
不等于,会同时判断变量的类型和数值console.log("1" == 1); // 判断字符串1是否等于数字1,true console.log("1" == 1); // false a)不同类型间比较,== 之比较 "转化成同一类型后的值" 看 "值" 是否相等, === 如果类型不同,其结果就是不等。 b)同类型比较,直接进行 "值" 比较,两者结果一样。
三、输入和输出
输入
- 通过页面交互来输入。例如通过
input
、textarea
等标签获取用户的键盘输入,通过click
、hover
等事件获取用户的鼠标输入。 - 通过从服务器端获取输入,通过
Ajax
与WebSocket
从服务器端获取输入。 - 从标准输入里读取信息
let fs = require('fs'); let buf = ''; // 当输入缓冲区内有内容时会执行下面的函数 process.stdin.on('readable', function() { // 如果有输入从缓冲区中将内容读进来,将内容放到 buf 里 let chunk = process.stdin.read(); if (chunk) buf += chunk.toString(); }); // 当输入缓冲区内没有内容时(输入完成)会执行下面的函数 process.stdin.on('end', function() { buf.split('\n').forEach(function(line) { // 对于一行的输入内容用空格将其隔开,每一个数转换成整数放到 tokens 里。 let tokens = line.split(' ').map(function(x) { return parseInt(x); }); if (tokens.length != 2) return; console.log(tokens.reduce(function(a, b) { return a + b; })); }); });
输出
常用输出
- 调试用console.log,会将信息输出到浏览器控制台
- 改变当前页面的HTML与CSS
- 通过Ajax与WebSocket将结果返回到服务器
格式化输出字符串
C++ 中格式化输出字符串(用某些值填充字符串)。例如,printf("result is %d", result);
- 字符串中填入数值:
let name = 'yjx', age = 18; let s = `My name is ${name}, I'm ${age} years old.`; ${}里面写表达式
- 定义多行字符串
let s = `<div> <h2>标题</h2> <p>段落</p> /div>`
四、判断语句
五、循环语句
- 和 C++ 中的循环类似
for (let i = 0; i < 10; i++) { console.log(i); }
- 枚举对象或数组时可以有下面两种写法
for-in
循环,枚举数组中的下标,以及对象中的key
for-of
循环,枚举数组中的值,以及对象中的value
六、对象
js 中很常用的两个数据结构一个是数组,另一个就是对象,js 中一切皆对象,!
创建
对象是由 key-value
对构成的,key
是字符串,可以用 “”
括起来也可以不括起来,value
可以是变量、数组、对象、函数等。在 js
中对象名也是变量
创建方式 1
let person = {}; // 定义一个空对象
let person = {
name: 'yjx',
age: 18,
money: 0,
friends: ['BOb', 'Alice', 'Lucy'],
clothes: {
color: "red",
price: 20,
},
add_money: function (x) {
this.money += x; // 函数中的this是指拥有这个函数的对象,此函数在person这个对象里,所以this指person,等价于person.money
},
}
创建方式 2
let person = new Object();
person.name = "yjx";
person.age = 18;
console.log(person);
调用
- 方式 1:对象属性的调用:
person.name;
,对象函数的调用:person.add_money();
,() 函数调用,里面可加参数 - 方式 2:对象属性的调用:
person["name"];
,对象函数的调用:person["add_money"]();
function main() {
// 调用方式 1
console.log(person.money);
person.add_money(10); // ():执行函数
console.log(person.money);
// 调用方式 2
console.log(person["money"]);
person["add_money"](10);
console.log(person["money"]);
}
对象的解构
获取对象里的某些属性
const person = {
name: "yjx",
age: 18,
height: 180,
};
const name = person.name, age = per.age; // 不用解构方式获取属性,输出:yjx 18
const {name, age} = person; // 可等价于上面的写法
const {name : nm, age} = person; // 可以起别名,nm 是name的别名
对象的展开
const a = {name: "yxc"};
const c = {...a, height: 180}; // 等价于 c = {name: "yxc",height: 180}
七、数组
数组是对象来实现的,也是一种特殊的对象,类型为 object。
定义
数组中的元素类型可以不同的,元素可以是变量、数组、对象、函数。
let a = [1, 2, "yjx", [3, 4, 5]];
let b = []; // 定义一个空数组
let c = [ // 数组中每个元素用 , 隔开
1, // 变量
"yjx", // 变量
['a', 'b', 3], // 数组
function () { // 函数
console.log("Hello World");
},
{ name: "yxc", age: 18 } // 对象
];
访问和赋值
通过下标(一个整数),例如:c[0];
,c[0] = 2;
没有数组下标越界的概念。
数组的常用属性和函数
length
:返回数组长度,注意不要加 ()push()
:向数组末尾添加元素pop()
:删除数组末尾元素splice(a, b)
:删除下标从 a 开始的 b 个数sort()
:将数组从小到大排序- 自定义比较函数:逆序:
let main = { a.sort(function(a, b)) { return b - a; });
- 自定义比较函数:逆序:
数组展开
一个数组前加 ...
表示将这个数组展开。
- 实现数组合并
let a = [1,2,3]; let b = [4,5,6]; let c = [...a,7,8]; // 等价于 let c = [1,2,3,7,8] let d = [-1,0,...a,...b,3.5,7];
- 实现复制
let a = [1, 2, 3]; let b = [...a]; // b是a的复制,将 a 数组复制一遍给b,a 和 b不是一个东西
八、函数
Js 在底层实现时是用对象来实现的,类型是 function
。函数未执行时,返回的是函数体定义,当 ()
执行时才输出函数执行结果。
定义
定义有 3
种方式,函数定义时不用指定返回值类型,如果函数不变的的话用 const
,变的话用 let
定义。包含两部分,一是函数参数列表,另一个是函数体。
方式 1(一般定义方式)
修饰符为 function
// 第一种方式,function 为函数修饰符
function add (a, b) {
return a + b;
}
let main = function () {
console.log(add(3, 4));
}
方式 2(定义一个函数变量)
js
中函数定义好之后,函数名
就是一个一般的变量名,可随便赋值。
// 第二种方式:定义一个函数变量,函数名add就是一个一般的变量名,可随便赋值
let add = function (a, b) {
return a + b;
}
let main = function () {
console.log(add(3, 4));
}
let add = 3; // 函数名可以直接赋值
let main = function () {
console.log(add); // 结果为3
}
方式 3(方式 2 的简写方式,箭头函数)
在定义的时候发现函数有两部分组成,一部分为传入参数列表,另一部分为函数体,简写为将 function
换成 =>
。
// 箭头函数
let add = (a, b) => {
return a + b;
}
let main = function () {
console.log(add(3, 4));
console.log(add()); // 如果参数没有传进来的话会输出undefined
}
箭头函数的简写方式
ES6 语法,箭头函数简写方式:当函数只有一个参数可以去掉 ()
,当函数体只有一句话时,可以去掉 return
和 {}
const f = (x) => {
return x * x;
};
// 简写为:
const f = x => x * x;
函数调用
// 函数定义
let add = (a, b) => {
return a + b;
}
// 函数调用
add();
返回值
如果没有返回值,则返回 undefined
。
let add = (a, b) => {
}
let main = function () {
console.log(add()); // 没有定义返回值会输出undefined
}
let add = (a, b) => {
return;
}
let main = function () {
console.log(add()); // 没有定义返回值会输出undefined
}
返回值可以是任意的,例如,返回一个对象或者函数等。
// 返回一个对象
let add = (a,b) => {
return {
name: "yjx",
age: 18,
}
}
// 返回一个函数
let add = (a,b) => {
return () => {
console.log("Hello World")
}
}
let main() = function () {
console.log(add(3, 5)); // 没有执行返回的是函数定义
console.log(add(3, 5)()); // 执行返回函数
}
九、类
与 C++中的 Class 类似。C++ 中类的成员有 private、public、protected 等
js 中所有成员都是 public。
1. 类与实例的关系
一个类可以生成多个实例。
2. 类的定义
constructor()
: 构造函数
定义成员变量用 this.
来定义,类中定义成员变量时不仅可在构造函数中定义,也可在任意函数里定义。
定义成员函数不用写 function
关键字。
类中的 this
代表当前类生成的某一个实例对象。
类用在什么地方:将一个前端页面分为多个组件组成,每一个组件都是一个 class
,如果一个组件复杂会将其继续细分,每细分出来的组件都是一个新的 class
,用 class
来维护每一个组件的各种行为。
// 定义
class Point {
constructor(x, y) { // 构造函数
this.x = x; // 定义成员变量用 this.来定义
this.y = y;
}
// 定义成员函数
init() {
this.sum = this.x + this.y; //
}
}
// 用类生成对象
let main = function () {
let p = new Point(3, 4); // 生成一个对象会调用构造函数
p.x;
p.init();
}
3. 继承
将所有元素共有的部分定义为基类,所有元素可以从基类继承。
super
:用在构造函数中指父类的构造函数,用在其它成员函数时指父类的对象。
class Point {
constructor(x, y) { // 构造函数
this.x = x; // 成员变量,this 指当前类的实例
this.y = y;
}
toString() { // 成员函数
return `(${this.x}, ${this.y})`;
}
}
class ColorPoint extends Point { // 类的命名一般用驼峰命名:每个单词的首字母大写
constructor(x, y, color) {
super(x, y); // super()指父类的构造函数,先初始化父类的构造函数。super()只能用在构造函数中
this.color = color; // this 一定要在 super 后调用
}
toString() {
return `${this.color} ${super.toString()}`; // super指父类的实例,与上面super()不是一个意思,
}
}
let main = function () {
let p = new ColorPoint(3, 4, 'red');
console.log(p.toString()); //当子类和父类的成员函数名称相同时,调用时当前的子类的成员函数会将父类的成员函数覆盖掉,类似于C++中多态
}
export {
main
}
4. 静态方法与静态变量
静态方法
静态方法的定义(static)与 访问
class Point {
constructor(x, y) { // 构造函数
this.x = x; // this 指当前实例
this.y = y;
}
toString() {
return `(${this.x}, ${this.y})`;
}
static print_class_name() { // 静态成员函数
console.log('Ponit');
}
}
let main = function () {
let p = new ColorPoint(3, 4); // 初始化实例时不会将静态成员变量和函数初始化,只会将非静态成员变量和函数初始化
Point.print_class_name(); // 通过类名来访问静态成员函数
}
静态变量
静态变量的定义与 访问。
class Point {
constructor(x, y) { // 成员函数
this.x = x; // this 指当前实例
this.y = y;
Point.cnt++; // 静态变量通过类名来访问
}
toString() {
return `(${this.x}, ${this.y})`;
}
static print_class_name() { // 静态成员函数
console.log('Ponit');
}
}
Point.cnt = 0;
let main = function () {
for (let i = 0; i < 3; i++) {
new Point(3, 4); // 每次调用构造函数都会让静态变量 cnt ++
}
console.log(Point.cnt); // 输出为 3
}
export {
main
}
5. ES6 语法补充
export
想 import
一个默认的不能加大括号,且可以重新起名。impot
一个非默认的,必须加大括号,名字必须一样,如果想重命名可以用 关键字 as
ecport default class Player {
constructor() {
consloe.log("player");
}
}
let id = 1;
ecport {
id
}
import MyPlayer, {id as id2} from "./player"; // 重命名
let player = new MyPlayer;
使用bind()函数绑定this取值
使用 bind()
函数绑定 this
取值:bind 函数将一个对象绑定到函数内部的 this
上
同样的 this
在函数内可能指向不同的对象,例子如下:
const person = {
name: "yjx",
talk: function() {
console.log(this);
}
}
person.talk(); // 输出的为:{name: 'yjx', talk: ƒ},函数中的 this 指此函数运行时,调用此函数的对象,调用 talk函数的是 person,this 指 person
const talk = person.talk; // 全局变量
talk(); // 输出的为:window,没有任何东西调用 talk,就是 window 调用,所有全局变量都由 window 对象调用
const talk = person.talk.bind(person); // 让第二个 talk 也指向 person 对象
箭头函数不重新绑定this的取值
// 不使用箭头函数
const person = {
talk: function() {
setTimeout(function() {
console.log(this);
}, 1000);
}
};
person.talk(); // 输出Window
使用箭头函数,想让 this
指代当前的 person
// 写法 1:不使用箭头函数需要外面绑定当前this
const person = {
talk: function() {
let outer = this;
setTimeout(function() {
console.log(outer);
}, 1000);
}
};
person.talk(); // 输出{talk:f}
// 写法 2:通过箭头函数
const person = {
talk: function() {
setTimeout(() => {
console.log(this); // 这里的 this 指代 person
}, 1000);
}
};
person.talk(); // 输出 {talk: f}
十、事件
鼠标
键盘
keydown
:按下某个键就会触发,长按会连续触发,所有键都可以识别到keyup
:某个按键是否被释放keypress
:与keydown
的实现功能类似,但keypress
按下字符键时才会触发,按下功能键不触发
十一、常用库
第一:jQuery
作用:更方便的操作 html
和 css
1. 安装
示例:选取标签
// 原生 js 写法
let main = function () {
let div = document.querySelector('div');
console.log(div);
}
export {
main
}
// jQuery 写法
let main = function () {
let $div = $('div'); // jQuery 选取的标签一般会加一个$,$div,可加可不加
console.log($div);
}
2. 选择器
- 作用:方便呢的选择 html 中的某一个标签
- 方式:
$(selector)
,可以将$()
看成是一个函数;selector
是一个参数,类型是字符串。选择时候与css
选择器写法类似,例如:$('div'); // 选取所有div $('#big-div'); // 选取所有 id 为 big-div 的标签 $('.big-div'); // 选取所有 class 为 big-div 的标签 $('div > p')
3. 事件
- 事件的绑定
let main = function () { let $div = $('div'); // 方式 1 $div.on("click", function () { console.log('click div'); }) // 方式 2 $div.click(function () { console.log('click div'); }) } export { main }
- 事件的解绑
$(selector).off(event, func)
- 当存在多个相同类型的事件触发函数时,可以通过
click.name
来区分 return fasle
4. 标签的隐藏和显示
5. 标签的添加和删除
6. ajax
就是一个函数,里面有几个输入参数,填入参数后就可以自动调用后端函数。
ajax
的优势:在不刷新页面的情况下只从服务器端获取某些数据。
GET
方法:从服务器端获取数据。
$.ajax({
url: url, // url 写后端的链接
type: "GET",
data: { // 写向后端中传的各种参数
},
dataType: "json",
success: function (resp) { // 当后端成功返回内容后,从resp众解析出来内容
},
});
POST
方法:将表单数据传给服务器端
$.ajax({
url: url,
type: "POST",
data: {
},
dataType: "json",
success: function (resp) {
},
});
第二:setTimeout与setInterval
第三:requestAnimationFrame
此函数经常用于显示动画效果
浏览器每秒会刷新 60
次,requestAnimationFrame(func)
,func
会在下次浏览器刷新页面之前执行一次,通常会用递归写法使其每秒执行 60
次 func
函数。
let main = function() {
// 调用时会传入一个参数 timestamp,表示函数调用的时刻(每帧页面刷新的时刻),单位为 ms
let step = (timestamp)=> {
$('div').width($('div').width + 1);
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
第四:Map与Set
map
-
map
类似于C++
中的哈希表。与对象的区别:map
方便统计关键字的数量,遍历的时候一定是按照插入的顺序进行遍历。关键字可以是任意值,对象的关键字绝大部分是字符串 -
定义
let map = new Map() { }
-
操作(增删改查)
map.set(key, value);
插入键值对,如果 key 已存在,则会覆盖原有的 value
get(key);
查找关键字,如果不存在,返回 undefined
size;
返回键值对数量
has(key);
返回是否包含关键字 key
delete(key)
:删除关键字 key
clear()
:删除所有元素
set
-
类似于
C++
中的set
,相对于map
来说,set
只存key
,当哈希表,用于判重 -
定义
let set = new Set() { }
-
操作(增删改查)
add()
; 添加元素
has();
返回是否包含某个元素
size();
返回元素数量
delete();
删除某个元素
clear();
删除所有元素
第五:localStorage
在用户的浏览器中存键值对
第六:JSON
用来将一个对象序列化成一个字符串,然后再将字符串转化成一个对象。
很多函数只能传字符串,但是很多内容用字符串存并不方便,一般用 MAP
存比较方便
JSON.parse()
:将字符串解析成对象
JSON.stringify()
:将对象转化为字符串
let main = function () {
let obj = {
name: "yjx",
age: 18,
};
let str = JSON.stringify(obj);
let new_obj = JSON.parse(str);
}
export {
main
}
第七、WebSocket
ajax
协议:例如 http
,前端(client
端)向后端发送一个请求,后端(server
端)接受到之后再向前端返回一个请求,完成之后就结束,后端没有办法向前端主动发送请求。
websocket
:例如:聊天工具,需要后端主动向前端发送请求,是一种全双工通信(两边都可以主动发送请求)
第八、window
第九、canvas
作用:画布,高效简介地实现在浏览器中画
学习 canvas
的方法:知道每个是干什么的即可,现用现查!
fill
开头的函数:填充
stroke
开头的函数:画边框
画路线:直线,圆等。步骤是跟正常画画一样,一步一步画