因为本人经常使用QML,而由于QML与JS之间的关系,本人经常使用到JS相关语法,所以在此系统性对JS基础知识进行总结、记录。
1. 入门
JavaScript(简称 JS)是一种广泛应用于Web开发的脚本语言,它是构建现代Web应用的核心技术之一。
1.1 JS与Web三大件
JavaScript是全球流行的Web编程语言,是Web开发者必学的三大技术之一:
- HTML:定义网页的内容,如文本、图片、链接等。
- CSS:规定网页的布局和样式,使网页具备美观的外观。
- JavaScript:负责网页的行为与交互,为网页添加动态效果和响应用户操作的能力。
JS的作用就是通过对HTML元素的控制,使网页具备交互功能,比如点击按钮时执行某些操作,或者通过网络请求动态加载数据。
1.2 JS与QML
QML(Qt Modeling Language)是一种声明式语言,主要用于Qt Quick中进行界面设计。QML与JavaScript紧密集成,JavaScript负责处理QML中的逻辑部分。通过在QML中使用JavaScript,可以实现复杂的事件处理、数据绑定等功能。
QML中的JavaScript语法基本遵循ECMAScript标准,因此QML开发者常常需要掌握JavaScript的基础知识。QML支持在组件内嵌入JavaScript代码,处理各种界面交互和计算任务。
2. 基础语法
2.1 JS在Web中的使用
JS可以改变HTML内容,比如使用getElementById()
方法找到指定HTML元素并对其进行修改,也能通过这个方法找到HTML样式(CSS)并对其进行修改。
// 找到 id==demo 的HTML元素, 并将元素内容 (innerHTML) 更改为 “Hello JavaScript”
document.getElementById("demo").innerHTML = "Hello JavaScript";
JavaScript在Web中主要通过<script>
标签引入,需要使用<script> </script>
对代码块首尾进行标识。JS可以插入在<head>
或<body>
中,并运行在浏览器中。JS可以在HTML中直接编写,或者通过外部JS文件进行引入。例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple JS Example</title>
</head>
<body>
<h1>Welcome to JavaScript!</h1>
<script>
// 插入JS
console.log('Hello, World!');
</script>
</body>
</html>
2.2 代码格式
JS程序是一系列计算机“指令”语句组成
基本每一个语句的结构与其他编程语言如C/C++类似,这里不再赘述。
JS使用在HTML中是需要使用分号;
分割语句的;
但是因为QML可以不使用分号区分语句,而使用换行进行区分,所以在QML中使用JS函数等都可以不用分号,注意好换行即可。
2.3 注释
与C/C++类似,JavaScript支持如下两种类型的注释:
-
单行注释:使用
//
,适用于注释一行代码。// 这是一个单行注释 let a = 5;
-
多行注释:使用
/* */
,适用于注释多行代码。/* 这是一个 多行注释 */ let b = 10;
2.4 输出输入
JavaScript通过 alert()
、prompt()
、console.log()
等方法与用户交互。
其中使用console.log()
向控制台输出消息是JS用在QML中最多的。
-
alert():弹出警告框。
alert('Hello, World!');
-
prompt():弹出输入框,获取用户输入。
let name = prompt('What is your name?');
-
console.log():打印信息到浏览器控制台,用于调试。
在浏览器中需要使用F12打开Console控制台才能看到输出,在QML中可以直接使用Qt通道输出。
可以用其输出各种变量,如同C中的
print()
方法。输出多个数据使用逗号
,
隔开。console.log('Debug message'); let a = 1; let b = 2; console.log(" a: ", a, " b: ", b);
3. 变量
在JavaScript中,变量不需要指定数据类型,但需要关键字进行声明变量,计算机能自动识别数据类型,关键字有let
、const
和 var
。
let
:(2015年新引入的关键字,更符合使用逻辑)定义一个可变的局部变量。const
:直接定义一个常量(不是修饰作用),值不能修改。var
:(旧式变量声明,现在应避免使用)定义具有函数作用域,尽量避免使用。
let x = 10; // 可变变量
const y = 20; // 常量
var z = 30; // 旧式变量声明
let x += z;
注意事项:
-
支持使用一个关键字声明多个变量
let person = "John Doe", carName = "Volvo", price = 200;
-
为定义的值将被赋予
undefined
-
对于
var
,在同一作用域中二次声明不会重置值。对let
和const
不适用,不支持二次声明。var carName = "Volvo"; var carName; // 依然等于 "Volvo"
let
和var
的根本区别:
在JS中,有一个称为“变量提升”的机制,只要在代码中使用var
声明了变量,无论位置,解释器都会将这个变量的声明其提升到最初调用的位置,如下。这种情况让变量的作用域变得不再符合逻辑,一些情况下也容易出现难以排查的错误。
console.log(a); // 输出undefined,说明被正常声明了,只是没有赋值
var a = 1;
而使用let
和const
就不会,编译器对变量会使用局部作用域,符合使用逻辑。
console.log(a); // 报错,未声明变量
let a = 1;
4. 数据类型简述
JavaScript的数据类型包括原始类型和引用类型。
使用typeof
操作符查看变量的类型,可以后接()
,再加入变量,同C,也可直接接变量如下。
typeof "John" // 返回 string
typeof 3.14 // 返回 number
typeof false // 返回 boolean
typeof [1,2,3,4] // 返回 object
typeof {name:'John', age:34} // 返回 object
4.1 原始类型(基本数据类型)
支持使用对于方法名进行显式指定声明类型或类型转换,注意首字母大写
- Number:数值类型,包括整数和浮动点数。
- String:字符串类型。
- Boolean:布尔值,
true
或false
。 - Undefined:未定义,表示变量声明但没有赋值。
- Null:空值,表示无值。
- Symbol:ES6新增的唯一标识符,表示独一无二的值。
- BigInt:表示大整数。
let a = BigInt(1);
console.log(typeof a, a); // bigint 1n
4.2 引用类型(复杂数据类型)
-
Object:对象,用来存储键值对。声明时使用大括号
{}
指定类型。 -
Array:数组,是一种特殊类型的对象。声明时使用中括号
[]
指定类型。注意,使用
typeof
获取类型时,也会输出object
。 -
Function:函数,是可以执行的代码块。
-
RegExp:正则表达式。
-
Date:日期。
5. 深入数据类型
5.1 Number方法
方法 | 描述 |
---|---|
toString() |
以字符串形式返回一个数字 |
toExponential(n) |
返回一个字符串,其中数字四舍五入并使用指数表示法写入。参数n指定小数点后面的字符数。 |
toFixed(n) |
返回一个字符串,其中包含写入指定数量n的小数 |
toPrecision(n) |
返回一个字符串,其中的数字用 指定长度n |
valueOf() |
以数字形式返回一个数字 |
Number也有一些方法,但要注意的是这些方法不能对变量使用:
方法 | 描述 |
---|---|
Number.isInteger(number) |
判断参数number是否是整数 |
Number.isSafeInteger(number) |
判断参数number是否是安全整数(安全整数是可以精确表示为双精度数字的整数) |
Number.parseFloat(str) |
解析字符串并返回一个浮点数。允许字符串有空格,但仅返回第一个数字。 |
Number.parseInt(str) |
解析字符串并返回一个整数。允许字符串有空格,但仅返回第一个数字。 |
Number.parseInt("years 10"); // 10
5.2 String方法
方法 | 描述 |
---|---|
length |
返回字符串长度 |
at(index) |
返回指定索引位置的字符的新方法,等同[] |
charAt(index) |
返回指定索引位置的字符 |
charCodeAt(index) |
返回指定索引字符的 Unicode 编码 |
concat(str1, str2, …) |
连接两个或多个字符串 |
includes(substring) |
检查字符串是否包含子字符串,返回 true 或 false |
indexOf(substring) |
返回子字符串第一次出现的索引,找不到返回 -1 |
lastIndexOf(substring) |
返回子字符串最后一次出现的索引 |
slice(start, end) |
截取字符串的一部分,返回新字符串 |
substring(start, end) |
提取两个索引之间的子字符串 |
substr(start, length) |
从起始索引提取指定长度的子字符串(已废弃) |
toUpperCase() |
转换为大写字母 |
toLowerCase() |
转换为小写字母 |
trim() |
去除字符串两端的空格 |
trimStart() /trimEnd() |
仅去除字符串开头/结尾的空格 |
padStart(len, char) /padEnd(len,char) |
从头/尾使用字符char填充字符串,直到给定的长度len |
replace(search, replaceWith) |
用新字符串替换匹配的部分 |
replaceAll(search, replaceWith) |
替换所有匹配的部分(ES2021+) |
split(separator) |
按指定分隔符拆分字符串为数组 |
repeat(n) |
返回重复 n 次的新字符串 |
let str = " Hello World! ";
console.log(str.trim()); // "Hello World!"
console.log(str.toUpperCase()); // " HELLO WORLD! "
console.log(str.slice(1, 5)); // "Hell"
let words = "apple,banana,orange".split(','); // ["apple", "banana", "orange"]
5.3 Object方法
方法 | 描述 |
---|---|
Object.keys(obj) |
返回对象的所有键(属性名)组成的数组 |
Object.values(obj) |
返回对象的所有值组成的数组 |
Object.entries(obj) |
返回对象的键值对数组 |
Object.assign(target, source) |
复制对象的属性到目标对象 |
Object.freeze(obj) |
冻结对象,防止修改属性 |
Object.seal(obj) |
允许修改现有属性,但不能添加或删除 |
Object.hasOwnProperty(prop) |
检查对象是否包含指定的属性 |
Object.getOwnPropertyNames(obj) |
返回对象所有可枚举和不可枚举属性的名称 |
Object.getPrototypeOf(obj) |
获取对象的原型 |
Object.setPrototypeOf(obj, proto) |
设置对象的原型 |
Object.create(proto, propertiesObject) |
创建具有指定原型的新对象 |
JSON.stringify(obj) |
JSON的方法,将对象转换为 JSON 字符串 |
JSON.parse(jsonString) |
JSON的方法,解析 JSON 字符串为对象 |
let person = { name: "Alice", age: 25, city: "New York" };
console.log(Object.keys(person)); // ["name", "age", "city"]
console.log(Object.values(person)); // ["Alice", 25, "New York"]
console.log(Object.entries(person)); // [["name", "Alice"], ["age", 25], ["city", "New York"]]
let newPerson = Object.assign({}, person, { age: 30 });
console.log(newPerson); // { name: "Alice", age: 30, city: "New York" }
let jsonString = JSON.stringify(person);
console.log(jsonString); // '{"name":"Alice","age":25,"city":"New York"}'
let parsedObject = JSON.parse(jsonString);
console.log(parsedObject); // { name: "Alice", age: 25, city: "New York" }
5.4 Array方法
方法 | 描述 |
---|---|
at(index) |
获取编号为index的元素的新方法,与[] 相同作用 |
length |
获取数组中元素个数 |
toString() |
将数组转换为逗号分隔数组各值的字符串 |
join(separator) |
转换为指定分隔符的字符串,通过参数separator来替换默认的逗号 |
push(item1, item2, ...) |
在数组末尾添加一个或多个元素 |
pop() |
删除数组的最后一个元素并返回该元素 |
unshift(item1, item2, ...) |
在数组开头添加一个或多个元素 |
shift() |
删除数组的第一个元素并返回该元素 |
concat(arr2, arr3, ...) |
合并两个或多个数组,返回新数组 |
copyWithin(index1, index2, index3) |
将索引index1的元素复制到索引index2到index3。也可以不写index3,即只复制给index2。(该方法只是覆盖现有元素,不会增加新元素) |
flat() |
平展数组,将多维度数组平展到一维。 |
flatMap() |
首先映射数组的所有元素 然后通过展平数组来创建新数组。 |
indexOf(item) |
返回元素第一次出现的索引,找不到返回 -1 |
lastIndexOf(item) |
返回元素最后一次出现的索引 |
includes(item) |
检查数组是否包含某个元素,返回 true 或 false |
find(callback) |
返回符合条件的第一个元素,参数是一个回调函数 |
findLast(callback) |
从数组末尾开始执行find() |
findIndex(callback) |
返回符合条件的第一个元素的索引 |
filter(callback) |
返回符合条件的所有元素组成的新数组 |
map(callback) |
遍历数组并对每个元素执行回调,返回新数组 |
forEach(callback) |
遍历数组并对每个元素执行回调,无返回值 |
reduce(callback, initialValue) |
通过回调函数累积数组元素,返回单个值 |
reverse() |
反转数组顺序 |
sort(compareFunction) |
按指定规则对数组排序(默认按字符编码顺序) |
slice(start, end) |
截取数组的一部分,返回新数组,不修改原数组 |
splice(start, deleteCount, item1, item2, …) |
从指定索引位置删除或插入元素,修改原数组 |
const fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.join(" * "); // Banana * Orange * Apple * Mango
let arr = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4]
arr.pop(); // [1, 2, 3]
arr.unshift(0); // [0, 1, 2, 3]
arr.shift(); // [1, 2, 3]
let newArr = arr.concat([4, 5]); // [1, 2, 3, 4, 5]
const myArr = [[1,2],[3,4],[5,6]];
const newArr = myArr.flat(); // [1, 2, 3, 4, 5, 6]
const myArr2 = [1, 2, 3, 4];
const newArr2 = myArr.flatMap(x => [x, x * 10]);
// [1, 10, 2, 20, 3, 30, 4, 40]
arr.reverse(); // [3, 2, 1]
arr.sort(); // 默认按字符编码顺序排序
const numbers = [4, 9, 16, 25, 29];
let first = numbers.find(myFunction); // 25
function myFunction(value, index, array) {
return value > 18;
}
6. 运算符
JavaScript支持常见的运算符,包括算术运算符、比较运算符、逻辑运算符等。
基本与C/C++一样,要注意比较运算符的严格等于/严格不等于
-
算术运算符
也支持缩写:
x += 2
加法:
+
;减法:-
;乘法:*
;除法:/
;取余:%
;自增:++
;自减:--
。 -
比较运算符
- 等于:
==
。只会比较值是否一致 - 不等于:
!=
- 严格等于:
===
。会比较数据类型是否一致。 - *严格不等于:
!==
** - 大于:
>
- 小于:
<
- 大于等于:
>=
- 小于等于:
<=
let a = 11; let b = "11"; console.log(a == b); // 输出 true console.log(a === b); // 输出 false
- 等于:
-
逻辑运算符
与:
&&
;或:||
;非:!
。 -
位运算符
与:
&
;或:|
;取反:~
;左移:<<
;右移:>>
;无符号右移:>>>
。
7. 流程控制
JavaScript提供了多种控制结构来实现条件判断和循环。
7.1 条件语句
-
if
:条件判断。if (x > 10) { console.log('x is greater than 10'); } else { console.log('x is less than or equal to 10'); }
-
switch
:多条件判断。switch (day) { case 1: console.log('Monday'); break; case 2: console.log('Tuesday'); break; default: console.log('Unknown day'); }
7.2 循环
-
for
:常规循环。for (let i = 0; i < 5; i++) { console.log(i); }
-
while
:条件为true
时继续循环。let i = 0; while (i < 5) { console.log(i); i++; }
-
do...while
:至少执行一次循环。let i = 0; do { console.log(i); i++; } while (i < 5);
8. 函数
格式类似Python格式,JavaScript通过function
关键字来定义函数。
8.1 函数定义
function add(a, b) {
return a + b;
}
let result = add(5, 10); // 15
8.2 匿名函数和箭头函数
JavaScript支持匿名函数和箭头函数,它们可以作为值传递给其他函数或事件处理器。
// 匿名函数
let multiply = function(a, b) {
return a * b;
};
// 箭头函数
let divide = (a, b) => a / b;
9. 类
JavaScript是面向对象的编程语言,支持类(class)和对象(object)。格式也比较类似Python。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
let person1 = new Person('John', 30);
person1.greet(); // "Hello, my name is John and I am 30 years old."
10. 异常处理
10.1 try...catch
JavaScript 提供 try...catch
语句来处理可能出现的错误:
try
代码块:放置可能会抛出异常的代码。catch
代码块:当try
代码块中发生异常时,catch
代码块会被执行,并获取错误信息。
try {
// 可能会发生错误的代码
} catch (error) {
// 处理错误的代码
console.log(error.message);
}
10.2 try...catch...finally
finally
代码块:无论是否发生异常,都会执行。finally
常用于关闭资源(如数据库连接)或清理操作。
try {
// 可能会发生错误的代码
} catch (error) {
// 处理错误的代码
} finally {
// 无论是否发生错误,都会执行
}
10.3 throw
关键字
- JavaScript 允许使用
throw
关键字主动抛出异常,可以抛出 任意类型(字符串、对象、Error 实例等)。 - 抛出异常后,代码执行会立即停止,并跳转到
catch
代码块。
throw "错误信息"; // 抛出字符串
throw 100; // 抛出数字
throw new Error("自定义错误"); // 抛出 Error 实例
function divide(a, b) {
if (b === 0) {
throw new Error("除数不能为 0");
}
return a / b;
}
try {
console.log(divide(10, 2)); // 正常执行
console.log(divide(5, 0)); // 抛出异常
} catch (error) {
console.log("捕获错误:" + error.message); //输出:捕获错误:除数不能为 0
}
10.4 Error
对象
JavaScript 提供 Error
构造函数来创建错误对象:
new Error(message); // 创建一个通用错误对象
new TypeError(message); // 类型错误
new ReferenceError(message); // 引用错误
new SyntaxError(message); // 语法错误
try {
throw new TypeError("变量类型错误!");
} catch (error) {
console.log(error.name); // TypeError
console.log(error.message); // 变量类型错误!
}
10.5 常见错误类型
错误类型 | 说明 | 示例 |
---|---|---|
Error |
通用错误 | throw new Error("普通错误"); |
ReferenceError |
引用了不存在的变量 | console.log(x); // x is not defined |
TypeError |
变量或参数不是期望的类型 | null.toString(); |
SyntaxError |
语法错误 | eval("console.log(123"); |
RangeError |
数值超出范围 | new Array(-1); |