了解JavaScript
JavaScript 引入方式就是 HTML 和 JavaScript 的结合方式。JavaScript引入方式有两种:
在 HTML 中,JavaScript 代码必须位于 <script> 与 </script> 标签之间
参考代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
alert("hello js1");
</script>
</body>
</html>
第一步:定义外部 js 文件。如定义名为 demo.js的文件
demo.js 文件内容如下:
alert("hello js");
第二步:在页面中引入外部的js文件
在页面使用 script 标签中使用 src 属性指定 js 文件的 URL 路径。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../js/demo.js"></script>
</body>
</html>
<script> 标签。在js文件中直接写 js 代码即可,不要在 js文件 中写 script 标签<script> 标签不能自闭合,在页面中引入外部js文件时,不能写成 <script src="../js/demo.js" />。其实JS变量可以不使用关键字声明——(默认是类似的使用var但又有所不同)
通过 var 关键词声明的变量没有块作用域。在块 {} 内声明的变量可以从块之外进行访问。
{
var x = 10;
}
// 此处可以使用 x
通过 var 声明的变量会提升到顶端。您可以在声明变量之前就使用它
重新声明变量:
var x = 10;
// 此处 x 为 10
{
var x = 6;
// 此处 x 为 6
}
// 此处 x 为 6
HTML 中的全局变量:
使用 JavaScript 的情况下,全局作用域是 JavaScript 环境。
在 HTML 中,全局作用域是 window 对象。
通过 var 关键词定义的全局变量属于 window 对象:
var carName = "porsche";
// 此处的代码可使用 window.carName
{
let x = 10;
}
// 此处不可以使用 x
解决var重新声明变量带来的问题
var x = 10;
// 此处 x 为 10
{
let x = 6;
// 此处 x 为 6
}
// 此处 x 为 10
关键字 const 有一定的误导性。不是真正的常数.
它没有定义常量值。它定义了对值的常量引用。
因此,我们不能更改常量原始值,
const PI = 3.141592653589793;
PI = 3.14; // 会出错
PI = PI + 10; // 也会出错
// ------------------------------------
const car = {type:"porsche", model:"911", color:"Black"};
car = {type:"Volvo", model:"XC60", color:"White"}; // ERROR
// ------------------------------------
const cars = ["Audi", "BMW", "porsche"];
cars = ["Honda", "Toyota", "Volvo"]; // ERROR
但我们可以更改常量对象的属性。
// 您可以创建 const 对象:
const car = {type:"porsche", model:"911", color:"Black"};
// 您可以更改属性:
car.color = "White";
// 您可以添加属性:
car.owner = "Bill";
//----------------------------------------
// 您可以创建常量数组:
const cars = ["Audi", "BMW", "porsche"];
// 您可以更改元素:
cars[0] = "Honda";
// 您可以添加元素:
cars.push("Volvo");
所有 JavaScript 值,除了原始值,都是对象。原始值指的是没有属性或方法的值。
原始数据类型指的是拥有原始值的数据。
JavaScript 定义了 5 种原始数据类型:
typeof 运算符返回一个用来表示表达式的数据类型的字符串。
顺带一提:input中的value始终是string
[]{}其实以上,都属于Object【对象】
JavaScript 中的 JSON 序列化和反序列化是将 JavaScript 对象与 JSON 字符串相互转换的过程,通常用于数据的传输和存储。在这些过程中,涉及到 JSON 字符串的转译(转义)和反转译(反转义)。
JSON序列化(转译):
\n 表示换行符,\" 表示双引号,\\ 表示斜杠等。JSON反序列化(反转译):
\n、\"、\\ 等转义序列时,它们会被解析为换行符、双引号和斜杠等。下面是一个简单的示例,演示了 JSON 序列化和反序列化的过程:
// 定义一个 JavaScript 对象
var obj = {
name: "John",
age: 30,
city: "New York"
};
// 将 JavaScript 对象序列化为 JSON 字符串
var jsonString = JSON.stringify(obj);
console.log(jsonString); // 输出 '{"name":"John","age":30,"city":"New York"}'
// 将 JSON 字符串反序列化为 JavaScript 对象
var newObj = JSON.parse(jsonString);
console.log(newObj); // 输出 { name: 'John', age: 30, city: 'New York' }
在这个示例中,JSON.stringify() 函数将 JavaScript 对象 obj 序列化为 JSON 字符串 jsonString,而 JSON.parse() 函数将 JSON 字符串 jsonString 反序列化为 JavaScript 对象 newObj。在序列化过程中,对象的属性被转义为 JSON 格式,而在反序列化过程中,转义字符被还原为原始的对象属性。
for循环语法大差不差,主要留意增强for语法的特点
在.forEach循环中,break、continue和return这些关键字并不适用,因为.forEach内部实际上是一个匿名函数,而且.forEach不支持break和continue。
两种跳出.forEach循环的方法:
for循环:由于for循环支持break和continue,可以通过将.forEach转换为for循环来实现循环的跳出。try...catch结构抛出异常:在.forEach的回调函数中,可以在特定条件下抛出异常,然后在外部的catch块中处理跳出循环后的逻辑。js中函数声明会提前,如果有多个函数名相同的函数(不管参数个数),那么最后一个声明的函数将会有效,会覆盖前面相同函数名字的声明。 例如:
function f1(a, b){
}
function f1(a, b, c){
}
f1(a,b)将会调用最后一个f1函数。因为后面个f1覆盖了前面个f1的声明。
但是可以通过argument对象的length属性实现类似方法重载的效果
注意:argument对象每个函数调用时隐藏起来的参数对象,获取其所有参数,推荐将其转换成数组再获取
参考文档:Javascript中arguments对象的详解和使用方法 (yjbys.com)如图所示:

参考文章:
JavaScript 中的 eval() 函数是一个强大而灵活的功能,它可以将字符串作为 JavaScript 代码来执行。虽然 eval() 具有强大的功能,但也存在一些潜在的安全风险和性能问题,因此在使用时需要谨慎考虑。
下面是 eval() 函数的一些特点和用法:
执行字符串中的 JavaScript 代码:
eval() 函数接受一个字符串参数,将这个字符串作为 JavaScript 代码来执行,并返回执行结果。动态执行代码:
eval() 可以接受任意字符串作为参数,因此可以用来动态执行代码,包括动态生成函数、对象、表达式等。访问局部变量和全局变量:
eval() 在执行字符串中的代码时,可以访问包含它所在的函数作用域中的局部变量,以及全局作用域中的全局变量。引入潜在的安全风险:
eval() 可以执行任意字符串作为代码,所以可能会被用于执行恶意代码或者导致安全漏洞。性能问题:
eval() 需要在运行时解析和执行字符串中的代码,所以会比直接执行预先定义好的函数或代码块更慢,可能会影响性能。用于动态生成代码:
eval() 可以用于动态生成代码,例如动态创建函数、动态生成对象属性等。虽然 eval() 具有强大的功能,但是由于潜在的安全风险和性能问题,通常建议尽量避免使用 eval(),特别是在处理用户输入或者动态生成的代码时。如果确实需要使用 eval(),应该谨慎验证和过滤输入,并尽量避免在生产环境中使用。
1、使用相等运算符“==”和“===”:
- ==(双等号)是比较两个值是否相等,它会进行类型转换后再比较。
- ===(三等号)是比较两个值是否严格相等,不会进行类型转换。
2、利用数组的toString()方法:
- 将数组转换为字符串,然后进行比较。这种方法适用于一维数组,但对于二维数组或包含特殊值(如null、undefined、对象、函数等)的数组可能会出错。
3、使用ES6中的Object.is()方法:
-Object.is()用于比较两个值是否相等,它在处理+0和-0、NaN等特殊情况时与===有所不同。
4、使用JSON.stringify()将对象或数组转换为字符串:
- 这种方法可以弥补===无法准确比较对象的局限,但同样有局限性,比如在遇到symbol值时会忽略。
小结:隐性类型转换可能会带来便利,但也可能导致不易发现的bug。因此,推荐在比较时使用严格比较运算符===。在比较引用类型时,===会比较变量的引用是否相同,而不是值本身。如果引用不同,即使值相同也会返回false。
Number、parseInt、parseFloat都会自动过滤字符串前导和后缀的空格
四舍五入:数值类型.toFixed(n)——返回结果是字符串,n是位数
var num =2.446242342;
num = num.toFixed(2); // 输出结果为 2.45
巧用正则匹配-当作字符串,使用正则匹配:
Number(15.7784514000.toString().match(/^\d+(?:\.\d{0,2})?/))
// 输出结果为 15.77,不能用于整数如 10 必须写为10.0000
问题很明显:使用正则匹配保留两位数的前提是有足够多的位数
substr():第一个参数表示元素索引可以为负数, 第二个参数表示截取的字符串长度。substring():两个参数都不接受负数,都表示元素索引,如果 第一个参数 比 第二个参数大,那么该方法在提取子串之前会先交换这两个参数。slice(): 两个参数都接受负数,都表示元素索引, 如果 第一个参数 比 第二个参数大,返回空字符串。typeof value == 'number'
返回的是数字类型的字符串表现形式,最终还是要通过字符串比较来判断字符串
在JavaScript中,格式化输出通常指的是将数据以一种易于阅读的方式展示出来。这可以通过多种方式实现,包括使用模板字符串、console.log()函数的不同参数,以及一些库如util.format()(在Node.js中)等。以下是一些常见的格式化输出的例子:
使用模板字符串(Template Literals):
const name = 'World';
const greeting = `Hello, ${name}!`;
console.log(greeting); // 输出:Hello, World!
\n)const multiLine = `This is a string
that spans multiple
lines without needing to use
escape characters like \n`;
console.log(multiLine);
2. **使用`console.log()`输出多个值**:
- `console.log()`可以用来输出一个或多个值,它们会以空格分隔。
```javascript
const a = 1;
const b = 'text';
console.log(a, b); // 输出:1 text
使用console.dir()列出对象的属性:
console.dir()用于列出对象的所有可枚举属性。const obj = { a: 1, b: 2 };
console.dir(obj); // 输出对象的所有属性
使用JSON.stringify()将对象转换为字符串:
JSON.stringify()可以将对象转换为JSON格式的字符串,这对于调试复杂对象非常有用。const obj = { a: 1, b: { c: 3 } };
console.log(JSON.stringify(obj, null, 2)); // 输出格式化的JSON字符串
使用util.format()(Node.js):
util.format()提供了一种格式化字符串的方法,类似于C语言的printf。const util = require('util');
const formatted = util.format('Hello %s! The value of pi is approximately %d.', 'World', 3.14159);
console.log(formatted); // 输出:Hello World! The value of pi is approximately 3.
在JavaScript中,字符串是不可变的,这意味着一旦创建了字符串,就不能直接修改它的内容。字符串的方法如 substring() 返回的是一个新的字符串,而不是对原始字符串进行修改。
str.subString():var str="aabbccdd";
console.info(str.substring(4)); //得到ccdd,需要用变量接收
string.replace(regexp, newSubstr|function),只要newSubstr为空字符串,那么就能达到删除字符的效果,当然正则更多用来匹配替换而不仅仅是删除字符如果 newSubstr 是一个函数,则会为每个匹配的部分调用该函数,并将其返回值作为替换字符串。例如:
var str = "Hello World";
var newStr = str.replace(/(\w+)\s(\w+)/, function(match, p1, p2) {
return p2 + ', ' + p1;
});
console.log(newStr); // 输出 "World, Hello"
在这个示例中,正则表达式 /\w+\s\w+/ 匹配了 "Hello World" 中的 "Hello" 和 "World",然后通过一个函数来交换它们的位置,并返回新的字符串。
参考文档:js json数组去重_小疯子丫的博客-CSDN博客_js json数组去重
注意事项:演示代码中的key参数其实不是很合适,因为什么点key的key可能替换取值上有问题,如果确切知道key的字符串形式是什么,推荐直接写~
参考文档:
if (danmu[i].v2_color) {
color = (danmu[i].v2_color.color_left.r << 16) + (danmu[i].v2_color.color_left.g << 8) + (danmu[i].v2_color.color_left.b);
}
JavaScript 能够以不同方式“显示”数据:
window.alert() 弹出警告框document.write() 写入 HTML 输出innerHTML 修改 HTML 元素
console.log() 写入浏览器控制台function functionName(parameters) {
要执行的代码
}
var x = function (a, b) {return a * b};
var z = x(4, 3);
上面的函数实际上是一个匿名函数(没有名称的函数)。
存放在变量中的函数不需要函数名。他们总是使用变量名调用。
上面的函数使用分号结尾,因为它是可执行语句的一部分。
函数表达式可以作为“自调用”。
自调用表达式是自动被调用(开始)的,在不进行调用的情况下。
()。(function () {
var x = "Hello!!"; // 我会调用我自己
})();
// ES5
var x = function(x, y) {
return x * y;
}
// ES6
const x = (x, y) => x * y;
箭头函数未被提升。它们必须在使用前进行定义。
使用 const 比使用 var 更安全,因为函数表达式始终是常量值。
const obj = {
method: () => {
console.log(this); // 这里的this指向的是箭头函数创建时的上下文,而不是obj
}
};
// 正确的做法是使用传统的function关键字定义方法
const obj = {
method: function() {
console.log(this); // 这里的this指向obj
}
};
JavaScript 函数都有属性和方法。
arguments.length 会返回函数被调用时收到的参数数目:
function myFunction(a, b) {
return arguments.length;
}
toString() 方法以字符串返回函数:
function myFunction(a, b) {
return a * b;
}
var txt = myFunction.toString();
call() 方法是预定义的 JavaScript 方法。
它可以用来调用所有者对象作为参数的方法。
通过 call(),您能够使用属于另一个对象的属性作为参数值的方法。而且call() 方法可接受参数
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
person.fullName.call(person1, "Seattle", "USA");
上述代码中如果只是调用person.fullName()那么this指代的就是person的实例对象,获取调用对象本身的属性值,而使用了call()并传递person1对象作为参数,那么this指代的就是person1的实例对象
类似call(),区别在于
call() 方法分别接受参数。
apply() 方法接受数组形式的参数。
如果要使用数组而不是参数列表,则 apply() 方法非常方便。
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
person.fullName.apply(person1, ["Oslo", "Norway"]);
所有函数都有权访问全局作用域。
事实上,在 JavaScript 中,所有函数都有权访问它们“上面”的作用域。
在本例中,内部函数 plus() 可以访问父函数中的 counter 计数器变量:
function add() {
var counter = 0;
function plus() {counter += 1;}
plus();
return counter;
}
变量 add 的赋值是自调用函数的返回值。
这个自调用函数只运行一次。它设置计数器为零(0),并返回函数表达式。
这样 add 成为了函数。最“精彩的”部分是它能够访问父作用域中的计数器。
这被称为 JavaScript 闭包。它使函数拥有“私有”变量成为可能。
计数器被这个匿名函数的作用域保护,并且只能使用 add 函数来修改。
闭包指的是有权访问父作用域的函数,即使在父函数关闭之后。
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// 计数器目前是 3
回调和异步往往同时出现
"I will call back later!"
回调 (callback) 是作为参数传递给另一个函数的函数
这种技术允许函数调用另一个函数
回调函数可以在另一个函数完成后运行(等我干完这件事再回头调用你)
"I will finish later!"
与其他函数并行运行的函数称为异步(asynchronous)
一个很好的例子是 JavaScript setTimeout()——>每一次超时执行一次设定好的回调函数
如果您创建函数来加载外部资源(如脚本或文件),则在内容完全加载之前无法使用这些内容。
这是使用回调的最佳时机。
此例加载一个 HTML 文件 (mycar.html),并在文件完全加载后在网页中显示该 HTML 文件:
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);
在上面的示例中,myDisplayer 用作回调。函数(函数名)作为参数传递给 getFile()。
——>执行完getFile()后就会去回调myDisplayer<——
对象(Object):
类(Class):
extends 关键字来实现类的继承。类是对象的模板,通过类来new出对象,类有类属性、类方法,对象有对象属性、对象方法
——>而类中还始终添加 constructor() 方法,默认空参构造<——
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
age(x) {
return x - this.year;
}
}
let date = new Date();
let year = date.getFullYear();
let myCar = new Car("Ford", 2014);
document.getElementById("demo").innerHTML=
"My car is " + myCar.age(year) + " years old.";
注意事项:
在ES6(ECMAScript2015)新的标准中使用了class关键字来直接定义类;
可以class理解为语法糖,其流程本质是:
通过new关键字操作类的时候,会调用这个constructor函数,并且执行如下操作:
类声明不会被提升。
这意味着您必须先声明类,然后才能使用它
对于其他声明,如函数,在声明之前尝试使用它时不会出错,因为 JavaScript 声明的默认行为是提升(将声明移到顶部)。
如需创建类继承,请使用 extends 关键字。super() 方法引用父类。
使用类继承创建的类继承了另一个类的所有方法:
class Car {
constructor(brand) {
this.carname = brand;
}
present() {
return 'I have a ' + this.carname;
}
}
class Model extends Car {
constructor(brand, mod) {
super(brand);
this.model = mod;
}
show() {
return this.present() + ', it is a ' + this.model;
}
}
let myCar = new Model("Ford", "Mustang");
document.getElementById("demo").innerHTML = myCar.show();
类中添加 getter 和 setter,请使用 get 和 set 关键字。
即使 getter 是一个方法,当你想要获取属性值时也不要使用括号。
getter/setter 方法的名称不能与属性名称相同——>可以在属性名称前使用下划线字符 _ 将 getter/setter 与实际属性分开
getter与setter:
class Car {
constructor(brand) {
this._carname = brand;
}
get carname() {
return this._carname;
}
set carname(x) {
this._carname = x;
}
}
let myCar = new Car("Ford");
myCar.carname = "Volvo";
document.getElementById("demo").innerHTML = myCar.carname;
static 类方法是在类本身上定义的。
您不能在对象上调用 static 方法,只能在对象类上调用。
如果要在 static 方法中使用 实例类对象,可以将其作为参数发送:
class Car {
constructor(name) {
this.name = name;
}
static hello(x) {
return "Hello " + x.name;
}
}
let myCar = new Car("Ford");
document.getElementById("demo").innerHTML = Car.hello(myCar);
那如何不通过类这一模板而直接创建一个对象呢,如下:
var myObject = {
firstName:"Bill",
lastName: "Gates",
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
函数形式调用
function myFunction(a, b) {
return a * b;
}
myFunction(10, 2); // 将返回 20
作为方法调用函数: 在 JavaScript 中,您可以把函数定义为对象方法。
下面的例子创建了一个对象(myObject),带有两个属性(firstName 和 lastName),以及一个方法(fullName):
var myObject = {
firstName:"Bill",
lastName: "Gates",
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
myObject.fullName(); // 将返回 "Bill Gates"