JavaScript语法(一)

news2024/12/23 4:44:44

一、什么是JavaScript

1、DOM

文档对象模型(Document Object Model)是一个应用编程接口(API),用于在HTML中使用扩展的XML,DOM 将整个页面抽象为一组分层节点。HTML 或 XML 页面的每个组成部分都是一种节点,包含不同的数据。比如下面的 HTML 页面:

<html>
  <head>
    <title>Sample Page</title>
  </head>
  <body>
    <p> Hello World!</p>
  </body>
</html>

这些代码通过 DOM 可以表示为一组分层节点,如图 1-2 所示。
image.png
DOM 通过创建表示文档的树,让开发者可以随心所欲地控制网页的内容和结构。使用 DOM API,
可以轻松地删除、添加、替换、修改节点。

2、BOM

浏览器对象模型(Browser Object Model)API。提供与浏览器交互的方法和接口。

  • 弹出新浏览器窗口的能力;
  • 移动、缩放和关闭浏览器窗口的能力;
  • navigator 对象,提供关于浏览器的详尽信息;
  • location 对象,提供浏览器加载页面的详尽信息;
  • screen 对象,提供关于用户屏幕分辨率的详尽信息;
  • performance 对象,提供浏览器内存占用、导航行为和时间统计的详尽信息

二、HTML中的JavaScript

1、<script>元素

常用属性:

  • async 表示应该立即开始下载脚本,但不能阻止其他页面动作,比如下载资源或等待其他脚本加载。只对外部脚本文件有效。(并不保证能按照它们出现的次序执行)
  • defer 表示应该立即开始下载脚本,但延迟执行。
  • crossorigin 配置相关请求的CORS(跨源资源共享)设置。默认不使用CORS
  • src 表示包含要执行的代码的外部文件
  • type 代替 language ,表示代码块中脚本语言的内容类型,按照惯例,这个值始终都是“text/javascript”,如果这个值是module,则代码会被当成ES6模块,而且只有这时候代码中才能出现import和export关键字

在使用行内 JavaScript 代码时,要注意代码中不能出现字符串 ,想避免这个问题,只需要转义字符“\”即可。

三、语言基础

1、语法

标识符:使用驼峰形式,关键字、保留字、true、false、null不可作为标识符
语句以分号结尾
关键字:
break do in typeof
case else instanceof var
catch export new void
class extends return while
const finally super with
continue for switch yield
debugger function this
default if throw
delete import try
这些词汇不能用作标识符。

2、变量

2.1 var关键字

作用域:函数作用域

if (true) {
	var name = 'Matt';
	console.log(name); // Matt
}
console.log(name); // Matt

2.2 let声明

作用域:块作用域,块作用域是函数作用域的子集,因此适用于 var 的作用域限制同样也适用于 let。

if (true) {
	let age = 26;
	console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义

let 也不允许同一个块作用域中出现冗余声明

var name;
var name;

let age;
let age; //SyntaxError;标识符 age 已经声明过了

let声明的变量不会在作用域中被提升。

// name 会被提升
console.log(name); // undefined
var name = 'Matt';
// age 不会被提升
console.log(age); // ReferenceError:age 没有定义
let age = 26;

使用let在全局作用域声明的变量不会成为window对象的属性。

var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined

for循环迭代变量使用var会渗透到循环体外部,let则不会

for (var i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // 5

for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义

2.3 const声明

const行为与let基本相同,唯一一个重要的区别是用const声明的变量必须同时初始化变量。且变量不可被修改。

const age = 26;
age = 36; //TypeError: 给常量赋值

// const 声明的作用域也是块
const name = 'Matt';
if (true) {
const name = 'Nicholas';
}
console.log(name); // Matt

2.4 声明风格及最佳实践

  • 不使用var
  • const优先,let次之

3、数据类型

3.1 typeof操作符

返回变量的数据类型

  • “undefined” 表示值未定义;
  • “boolean” 表示值为布尔值;
  • “string” 表示值为字符串;
  • “number” 表示值为数值;
  • “object” 表示值为对象(而不是函数)或 null ;
  • “function” 表示值为函数;
  • “symbol” 表示值为符号。
let message = "some string";
console.log(typeof message); // "string"
console.log(typeof(message)); // "string"
console.log(typeof 95); // "number"
console.log(typeof null); // "object"

3.2 Undefined类型

就是一个特殊值:Undefined,当使用var或let声明了变量但没有初始化时,就相当于给变量赋了Undefined值。

let message;
console.log(message == undefined); // true

3.3 Null类型

Null类型同样只有一个值:null,从逻辑上讲,null值表示一个空对象指针。

let car = null;
console.log(typeof car); // "object"

undefined 值是由 null 值派生而来的,因此 ECMA-262 将它们定义为表面上相等。

console.log(null == undefined); // true

3.4 Boolean类型

要将一个其他类型的值转换为布尔值,可以调用特定的 Boolean() 转型函数:

let message = "Hello world!";
let messageAsBoolean = Boolean(message);

if 等流控制语句会自动执行其他类型值到布尔值的转换:

let message = "Hello world!";
if (message) {
	console.log("Value is true");
}

3.5 Number类型

let floatNum = 3.125e7; // 等于 31250000

有一个特殊的数值叫 NaN ,意思是“不是数值”,用 0 除任意数值在其他语言中通常都会导致错误,从而中止代码执行.

console.log(0/0); // NaN
console.log(-0/+0); // NaN

如果分子是非 0 值,分母是有符号 0 或无符号 0,则会返回 Infinity 或 -Infinity :

console.log(5/0); // Infinity
console.log(5/-0); // -Infinity

数值转换:

  • Number()
    • 布尔值, true 转换为 1, false 转换为 0。
    • 数值,直接返回。
    • null ,返回 0。
    • undefined ,返回 NaN 。
    • 字符串,如果包含数值,则转换为一个十进制数值。
    • 对象,调用 valueOf() 方法,并按照上述规则转换返回的值。如果转换结果是 NaN ,则调用toString() 方法,再按照转换字符串的规则转换。
let num1 = Number("Hello world!"); // NaN
let num2 = Number(""); // 0
let num3 = Number("000011"); // 11
let num4 = Number(true); // 1

可以看到,字符串 “Hello world” 转换之后是 NaN ,因为它找不到对应的数值。空字符串转换后是 0。字符串 000011 转换后是 11,因为前面的零被忽略了。最后, true 转换为 1。

let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000

3.6 String类型

字面量含义
\n换行
\t制表
\b退格
\r回车
\f换页
\\反斜杠(\)
\’单引号(')
\"双引号(")
\`反引号(`)
\xnn以十六进制编码 nn 表示的字符(其中 n 是十六进制数字 0~F),例如 \x41 等于 “A”
\unnnn以十六进制编码 nnnn 表示的 Unicode 字符(其中 n 是十六进制数字 0~F),例如 \u03a3 等于希腊字符 “Σ”

toString()

把一个值转换为字符串

let age = 11;
let ageAsString = age.toString(); // 字符串"11"
let found = true;
let foundAsString = found.toString(); // 字符串"true"

模板字面量

模板字面量保留换行字符,可以跨行定义字符串。
模板字面量在定义模板时特别有用,比如下面这个 HTML 模板:

let pageHTML = `
<div>
	<a href="#">
		<span>Jake</span>
	</a>
</div>`;

字符串插值

字符串插值通过在 ${} 中使用一个 JavaScript 表达式实现:

let value = 5;
let exponent = 'second';
// 以前,字符串插值是这样实现的:
let interpolatedString =
value + ' to the ' + exponent + ' power is ' + (value * value);
// 现在,可以用模板字面量这样实现:
let interpolatedTemplateLiteral =
`${ value } to the ${ exponent } power is ${ value * value }`;
console.log(interpolatedString); // 5 to the second power is 25
console.log(interpolatedTemplateLiteral); // 5 to the second power is 25

将表达式转换为字符串时会调用 toString() .

3.7 Symbol类型

Symbol(符号)是ES6新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。

3.8 Object类型

4、操作符

4.1 一元操作符

  • ++a和a++的区别

++a:先加再赋值,等价于:a = a+1

let num1 = 2;
let num2 = 20;
let num3 = ++num1 + num2;
let num4 = num1 + num2;
console.log(num3); // 23
console.log(num4); // 23

a++:先赋值再加,等价于:a = a;b = a + 1

let num1 = 2;
let num2 = 20;
let num3 = num1++ + num2;
let num4 = num1 + num2;
console.log(num3); // 22
console.log(num4); // 23

4.2 位操作符

  • 按位非 ~
let num1 = 25; // 二进制 00000000000000000000000000011001
let num2 = ~num1; // 二进制 11111111111111111111111111100110
console.log(num2); // -26
  • 按位与 &
let result = 25 & 3;
console.log(result); // 1  规则:有0为0,全1为1
//25 = 0000 0000 0000 0000 0000 0000 0001 1001
// 3 = 0000 0000 0000 0000 0000 0000 0000 0011
//---------------------------------------------
//AND= 0000 0000 0000 0000 0000 0000 0000 0001
  • 按位或 |
let result = 25 | 3;
console.log(result); // 27  规则:有1为1,全0为0
//25 = 0000 0000 0000 0000 0000 0000 0001 1001
// 3 = 0000 0000 0000 0000 0000 0000 0000 0011
//---------------------------------------------
//OR = 0000 0000 0000 0000 0000 0000 0001 1011
  • 按位异或 ^
let result = 25 ^ 3;
console.log(result); // 26  规则:相同为0,不同为1
//25 = 0000 0000 0000 0000 0000 0000 0001 1001
// 3 = 0000 0000 0000 0000 0000 0000 0000 0011
//---------------------------------------------
//XOR= 0000 0000 0000 0000 0000 0000 0001 1010
  • 左移 <<
let oldValue = 2; // 等于二进制 10
let newValue = oldValue << 5; // 等于二进制 1000000,即十进制 64

注意:左移会保留它所操作数值的符号。比如,如果-2 左移 5 位,将得到-64,而不是正 64。

  • 有符号右移 >>
let oldValue = 64; // 等于二进制 1000000
let newValue = oldValue >> 5; // 等于二进制 10,即十进制 2
  • 无符号右移 >>>
let oldValue = 64; // 等于二进制 1000000
let newValue = oldValue >>> 5; // 等于二进制 10,即十进制 2
let oldValue = -64; // 等于二进制 11111111111111111111111111000000
let newValue = oldValue >>> 5; // 等于十进制 134217726

在对-64 无符号右移 5 位后,结果是 134 217 726。这是因为-64 的二进制表示是 11111111111111111111111111000000,无符号右移却将它当成正值,也就是 4 294 967 232。把这个值右移 5 位后,结果是00000111111111111111111111111110,即 134 217 726。

4.3 布尔操作符

  • 逻辑非 !
  • 逻辑与 &&
  • 逻辑或 ||

4.4 乘性操作符

  • 乘法操作符 *
  • 除法操作符 /
  • 取模(余数)操作符 %

4.5 指数操作符

ES7新增了指数操作符,Math.pow()现在有了自己的操作符**

console.log(Math.pow(3, 2)); // 9
console.log(3 ** 2); // 9
console.log(Math.pow(16, 0.5)); // 4
console.log(16** 0.5); // 4

指数赋值操作符 **=

let squared = 3;
squared **= 2;
console.log(squared); // 9
let sqrt = 16;
sqrt **= 0.5;
console.log(sqrt); // 4

4.6 加性操作符

  • 加法操作符 +
  • 减法操作符 -

4.7 关系操作符

  • 小于 <
  • 大于 >
  • 小于等于 <=
  • 大于等于 >=

这里需要注意的就是:字符串比较时,会逐个比较每个字符的字符编码。

4.8 相等操作符

  • 等于 == 和不等于 !=

这两个操作符都会先进行类型转换(通常称为强制类型转换)再确定操作数是否相等。

  • 全等 === 和不全等 !==

全等和不全等操作符与相等和不相等操作符类似,只不过它们在比较相等时不转换操作数。
注意: 由于相等和不相等操作符存在类型转换问题,因此推荐使用全等和不全等操作符。这样有助于在代码中保持数据类型的完整性。

4.9 条件操作符

let max = (num1 > num2) ? num1 : num2;

4.10 赋值操作符

简单赋值用等于号( = )表示。

4.11 逗号操作符

逗号操作符可以用来在一条语句中执行多个操作,如下所示:
let num1 = 1, num2 = 2, num3 = 3;

5、语句

5.1 if语句

if (i > 25) {
	console.log("Greater than 25.");
} else if (i < 0) {
	console.log("Less than 0.");
} else {
	console.log("Between 0 and 25, inclusive.");
}

5.2 do-while语句

先执行循环体,再判断语句,因此,循环体内代码在退出前至少要执行一次。

let i = 0;
do {
	i += 2;
} while (i < 10);

5.3 while语句

先判断语句,再执行循环体。

let i = 0;
while (i < 10) {
	i += 2;
}

5.4 for语句

for 语句也是先判断语句,只不过增加了进入循环之前的初始化代码,以及循环执行后要执行的表达式。

let count = 10;
for (let i = 0; i < count; i++) {
	console.log(i);
}

for (;;) { // 无穷循环
	doSomething();
}

// 以下for循环等价while循环
let count = 10;
let i = 0;
for (; i < count; ) {
	console.log(i);
	i++;
}

5.5 for-in语句

for-in 语句是一种严格的迭代语句,用于枚举对象中的非符号键属性。

for (const propName in window) {
	document.write(propName);
}

这个例子使用 for-in 循环显示了 BOM 对象 window 的所有属性。每次执行循环,都会给变量propName 赋予一个 window 对象的属性作为值,直到 window 的所有属性都被枚举一遍。与 for 循环一样,这里控制语句中的const 也不是必需的。但为了确保这个局部变量不被修改,推荐使用 const 。

5.6 for-of语句

for-of 语句是一种严格的迭代语句,用于遍历可迭代对象的元素。

for (const el of [2,4,6,8]) {
	document.write(el);
}

for-of 循环会按照可迭代对象的 next() 方法产生值的顺序迭代元素。

5.7 标签语句

标签语句用于给语句加标签。

start: for (let i = 0; i < count; i++) {
	console.log(i);
}

start 是一个标签,可以在后面通过 break 或 continue 语句引用。标签语句的典型应用场景是嵌套循环

5.8 break 和 continue 语句

break 语句用于立即退出循环,强制执行循环后的下一条语句。

let num = 0;
for (let i = 1; i < 10; i++) {
	if (i % 5 == 0) {
		break;
  }
	num++;
}
console.log(num); // 4

continue 语句也用于立即退出循环,但会再次从循环顶部开始执行。

let num = 0;
for (let i = 1; i < 10; i++) {
	if (i % 5 == 0) {
		continue;
	}
	num++;
}
console.log(num); // 8

break 和 continue 都可以与标签语句一起使用,返回代码中特定的位置。这通常是在嵌套循环中,

let num = 0;
outermost:
for (let i = 0; i < 10; i++) {
	for (let j = 0; j < 10; j++) {
		if (i == 5 && j == 5) {
			break outermost;
		}
		num++;
	}
}
console.log(num); // 55

添加标签不仅让 break 退出(使用变量 j 的)内部循环,也会退出(使用变量 i 的)外部循环。

let num = 0;
outermost:
for (let i = 0; i < 10; i++) {
	for (let j = 0; j < 10; j++) {
  	if (i == 5 && j == 5) {
			continue outermost;
		}
		num++;
	}
}
console.log(num); // 95

continue 语句会强制循环继续执行,但不是继续执行内部循环,而是继续执行外部循环。

5.9 with语句

使用 with 语句的主要场景是针对一个对象反复操作,这时候将代码作用域设置为该对象能提供便利。

let qs = location.search.substring(1);
let hostName = location.hostname;
let url = location.href;

上面代码中的每一行都用到了location对象,如果使用 with 语句,就可以少写一些代码:

with(location) {
  let qs = search.substring(1);
	let hostName = hostname;
	let url = href;
}

警告: 由于 with 语句影响性能且难于调试其中的代码,通常不推荐在产品代码中使用 with 语句。

5.10 switch语句

注意: switch 语句在比较每个条件的值时会使用全等操作符,因此不会强制转换数据类型(比如,字符串 “10” 不等于数值 10)。

6、函数

函数使用 function 关键字声明,后跟一组参数,然后是函数体。

function sayHi(name, message) {
	console.log("Hello " + name + ", " + message);
}

ECMAScript 中的函数不需要指定是否返回值。任何函数在任何时间都可以使用 return 语句来返回函数的值,用法是后跟要返回的值。比如:

function sum(num1, num2) {
	return num1 + num2;
}

注意: 最佳实践是函数要么返回值,要么不返回值。只在某个条件下返回值的函数会带来麻烦,尤其是调试时。

四、变量、作用域与内存

1、原始值与引用值

原始值就是最简单的数据,引用值则是由多个值构成的对象。
保存原始值的变量是按值(by value)访问的;保存引用值的变量是按引用(by reference)访问的。

1.1 动态属性

对于引用值而言,可以随时添加、修改和删除其属性和方法。只有引用值可以动态添加后面可以使用的属性。

let person = new Object();
person.name = "Nicholas";
console.log(person.name); // "Nicholas"

1.2 复制值

把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置。区别在于,这里复制的值实际上是一个指针,它指向存储在堆内存中的对象。操作完成后,两个变量实际上指向同一个对象。

let obj1 = new Object();
let obj2 = obj1;
obj1.name = "Nicholas";
console.log(obj2.name); // "Nicholas"

image.png

1.3 传递参数

ECMAScript 中所有函数的参数都是按值传递的。

function addTen(num) {
	num += 10;
	return num;
}
let count = 20;
let result = addTen(count);
console.log(count); // 20,没有变化  如果 num 是按引用传递的,那么 count 的值也会被修改为 30。
console.log(result); // 30

但是,如果变量中传递的是对象,就没那么清楚了,例如:

function setName(obj) {
	obj.name = "Nicholas";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"

这里很多人会误认为对象是按引用传递的,其实不是,即使对象是按值传进函数的, obj 也会通过引用访问对象。因为 obj 指向的对象保存在全局作用域的堆内存上。为证明对象是按值传递的,我们再来看看下面这个修改后的例子:

function setName(obj) {
	obj.name = "Nicholas";
	obj = new Object();
	obj.name = "Greg";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"

这个例子前后唯一的变化就是 setName() 中多了两行代码,将 obj 重新定义为一个有着不同 name的新对象。当 person 传入 setName() 时,其 name 属性被设置为 “Nicholas” 。然后变量 obj 被设置为一个新对象且 name 属性被设置为 “Greg” 。如果 person 是按引用传递的,那么 person 应该自动将指针改为指向 name 为 “Greg” 的对象。可是,当我们再次访问 person.name 时,它的值是 “Nicholas” ,这表明函数中参数的值改变之后,原始的引用仍然没变。当 obj 在函数内部被重写时,它变成了一个指向本地对象的指针。而那个本地对象在函数执行结束时就被销毁了。

1.4 确定类型

ECMAScript 提供了 instanceof 操作符。

console.log(person instanceof Object); // 变量 person 是 Object 吗?
console.log(colors instanceof Array); // 变量 colors 是 Array 吗?
console.log(pattern instanceof RegExp); // 变量 pattern 是 RegExp 吗?

如果变量是给定引用类型,则instanceof 操作符返回true

2、执行上下文与作用域

变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。每个上下文都有一个关联的变量对象(variable object),而这个上下文中定义的所有变量和函数都存在于这个对象上。
全局上下文是最外层的上下文。在浏览器中,全局上下文就是我们常说的window对象,因此所有通过 var 定
义的全局变量和函数都会成为 window 对象的属性和方法。
每个函数调用都有自己的上下文。当代码执行流进入函数时,函数的上下文被推到一个上下文栈上。在函数执行完之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文。
此外,局部作用域中定义的变量可用于在局部上下文中替换全局变量。看一看下面这个例子:

var color = "blue";
function changeColor() {
	let anotherColor = "red";
	function swapColors() {
		let tempColor = anotherColor;
		anotherColor = color;
		color = tempColor;
		// 这里可以访问 color、anotherColor 和 tempColor
	}
	// 这里可以访问 color 和 anotherColor,但访问不到 tempColor
	swapColors();
}
// 这里只能访问 color
changeColor();

2.1 作用域链增强

  • try / catch 语句的 catch 块
  • with 语句

这两种情况下,都会在作用域链前端添加一个变量对象。对 with 语句来说,会向作用域链前端添加指定的对象;对 catch 语句而言,则会创建一个新的变量对象,这个变量对象会包含要抛出的错误对象的声明。看下面的例子:

function buildUrl() {
	let qs = "?debug=true";
	with(location) {
		let url = href + qs;
	}
	return url;
}

当 with 语句中的代码引用变量 href 时,实际上引用的是location.href ,也就是自己变量对象的属性。

2.2 变量声明

let 和 const成为首选

2.2.1 使用 var 的函数作用域声明
function add(num1, num2) {
	var sum = num1 + num2;
	return sum;
}
let result = add(10, 20); // 30
console.log(sum); // 报错:sum 在这里不是有效变量

如果省略上面例子中的关键字 var ,那么 sum 在 add() 被调用之后就变成可以访问的了。

function add(num1, num2) {
	sum = num1 + num2;
	return sum;
}
let result = add(10, 20); // 30
console.log(sum); // 30

这一次sum没有使用var声明,在调用 add() 之后, sum被添加到了全局上下文,在函数退出之后依然存在,从而在后面可以访问到。

2.2.2 使用 let 的块级作用域声明

let的作用域是块级,块级作用域由最近的一对包含花括号{}界定。
let 与 var 的另一个不同之处是在同一作用域内不能声明两次。
let 的行为非常适合在循环中声明迭代变量。

for (var i = 0; i < 10; ++i) {}
console.log(i); // 10
for (let j = 0; j < 10; ++j) {}
console.log(j); // ReferenceError: j 没有定义

2.2.3 使用const的常量声明

使用 const 声明的变量必须同时初始化为某个值。

2.2.4 标识符查找

如果局部上下文中有一个同名的标识符,那就不能在该上下文中引用父上下文中的同名标识符,例如:

var color = 'blue';
function getColor() {
	let color = 'red';
	return color;
}
console.log(getColor()); // 'red'

使用块级作用域声明并不会改变搜索流程,但可以给词法层级添加额外的层次:

var color = 'blue';
function getColor() {
	let color = 'red';
	{
		let color = 'green';
		return color;
	}
}
console.log(getColor()); // 'green'

3、垃圾回收

3.1 标记清理

JavaScript中最常用的垃圾回收策略是标记清理
原理:当变量进入上下文,比如在函数内部声明一个变量时,这个变量会被加上存在于上下文中的标记。而在上下文中的变量,逻辑上讲,永远不应该释放它们的内存,因为只要上下文中的代码在运行,就有可能用到它们。当变量离开上下文时,也会被加上离开上下文的标记。
垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存。

3.2 引用计数

另一种没那么常用的垃圾回收策略是引用计数
原理:对每个值都记录它被引用的次数。声明变量并给它赋一个引用值时,这个值的引用数为 1。如果同一个值又被赋给另一个变量,那么引用数加 1。类似地,如果保存对该值引用的变量被其他值给覆盖了,那么引用数减 1。当一个值的引用数为 0 时,就说明没办法再访问到这个值了,因此可以安全地收回其内存了。垃圾回收程序下次运行的时候就会释放引用数为 0 的值的内存。
注意: 引用计数在代码中存在循环引用时会出现问题。

未完待续…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1072639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线程安全问题 --- 死锁

文章目录 线程安全产生线程安全问题的原因上锁synchronized使用方法1. 修饰方法2. 修饰代码块synchronized的可重入性死锁什么是死锁死锁的三个典型情况:死锁的四个必要条件如何破除(避免)死锁线程安全类线程安全 由于多个线程之间是抢占式执行的, 这就给调度执行顺序带来了随…

Redis(三)

文章目录 一、单节点Redis的问题&#xff08;一&#xff09;数据丢失&#xff08;二&#xff09;并发能力问题&#xff08;三&#xff09;存储能力问题&#xff08;四&#xff09;故障恢复问题 二、Redis持久化&#xff08;一&#xff09;RDB1、RDB是什么2、rdb配置3、手动触发…

Java基于SpringBoot的高校招生系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 简介系统设计思路1 数据库设计2 系统整体设计 系统详细设计1系统功能模块2. 管理员功能模块3学生…

时序预测 | MATLAB实现ICEEMDAN-IMPA-LSTM时间序列预测

时序预测 | MATLAB实现ICEEMDAN-IMPA-LSTM时间序列预测 目录 时序预测 | MATLAB实现ICEEMDAN-IMPA-LSTM时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 ICEEMDAN-IMPA-LSTM功率/风速预测 基于改进的自适应经验模态分解改进海洋捕食者算法长短期记忆网络时间序…

MQTT协议入门介绍

前言 物联网曾被认为是继计算机、互联网之后&#xff0c;信息技术行业的第三次浪潮。随着基础通讯设施的不断完善&#xff0c;尤其是 5G 的出现&#xff0c;进一步降低了万物互联的门槛和成本。物联网本身也是 AI 和区块链应用很好的落地场景之一&#xff0c;各大云服务商也在…

【漏洞复现】某 NVR 视频存储管理设备远程命令执行

漏洞描述 NUUO NVR是中国台湾NUUO公司旗下的一款网络视频记录器&#xff0c;该设备存在远程命令执行漏洞&#xff0c;攻击者可利用该漏洞执行任意命令&#xff0c;进而获取服务器的权限。 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&am…

简单对比一下 C 与 Go 两种语言

使用一个简单的计数程序将古老的 C 语言与现代 Go 进行比较。 Go 是一种现代编程语言&#xff0c;追溯其历史大部分源自编程语言 C。所以&#xff0c;任何熟悉 C 语言的开发者都可能会觉得 Go 很熟悉。C 程序员使用 Go 编写新程序变得容易&#xff0c;同时避免了 C 编程语言的…

安全典型配置(一)使用ACL限制FTP访问权限案例

【微|信|公|众|号&#xff1a;厦门微思网络】 使用ACL限制FTP访问权限案例 ACL简介 访问控制列表ACL&#xff08;Access Control List&#xff09;是由一条或多条规则组成的集合。所谓规则&#xff0c;是指描述报文匹配条件的判断语句&#xff0c;这些条件可以是报文的源地址…

申请免费 SSL 证书为您的小程序加密通信

在今天的网络环境中&#xff0c;数据安全和隐私保护变得尤为重要。无论是网站还是应用程序&#xff0c;为其提供安全的通信渠道都是至关重要的。对于小程序开发者来说&#xff0c;使用 SSL&#xff08;Secure Sockets Layer&#xff09;证书可以有效地保障用户数据的安全&#…

[架构之路-235]:目标系统 - 纵向分层 - 数据库 - 数据库系统基础与概述(快速入门、了解核心概念):概念模型、逻辑模型、物理模型

目录 一、核心概念 1.1 什么是数据与信息 1.2 数据与数据库的关系 1.3 什么是数据库 1.4 数据库中的数据的特点 1.5 数据库与数据结构的关系 1.6 什么是数据库管理系统 1.7 什么是数据库系统 1.8 数据库的主要功能 1.9 Excel表格是数据库吗&#xff1f; 1.10 Excel表…

Asymmetric channel bandwidths(非对称信道带宽)

一人问&#xff1a;“你知道非对称信道带宽&#xff0c;XXX支持吗&#xff1f;”一人答&#xff1a;“我打开XXX的RF应答表看看”。 我默默打开了38.306搜了一下&#xff0c;简单研究了下。 在R15 中&#xff0c;为某些NR band引入了asymmetric Bandwidth UL/DL&#xff0c;以优…

Python机器学习实战-特征重要性分析方法(9):卡方检验(附源码和实现效果)

实现功能 使用chi2()获得每个特征的卡方统计信息。得分越高的特征越有可能独立于目标。 实现代码 from sklearn.feature_selection import chi2 import pandas as pd from sklearn.datasets import load_breast_cancer import matplotlib.pyplot as pltX, y load_breast_ca…

深入浅出的介绍一下虚拟机VMware Workstation——part2(详细安装与使用)

目录 虚拟机概念虚拟机软件安装准备点击创建新的虚拟机&#xff1a;选择要安装的系统镜像文件&#xff08;.iso文件&#xff0c;自己网上找&#xff0c;比如win10的win11的或者mac的系统镜像&#xff09;选择与iso文件对应的系统设置虚拟机名称和位置设置虚拟机基础信息 VMware…

计算机组成与设计的一些概念扫盲

一、术语 超标量架构 早期的单发射架构微处理器的流水线设计目标是做到平均每个时钟周期能执行一条指令&#xff0c;但这一目标不能满足提高处理器性能的要求。为了提高处理器的性能&#xff0c;处理器要具有每个时钟周期发射执行多条指令的能力。超标量体系结构可描述一种微处…

discuz封面设置失败的解决办法(centos系统+windows系统)

discuz封面设置失败的解决办法(centos系统windows系统&#xff09; centos系统&#xff1a;1、开启/var/www/html 这个目录的读写权限chmod -R 777 /var/www/html然后重启httpd&#xff1a;service httpd restart如果discuz论坛发布帖子&#xff0c;还是显示封面设置失败的话…

整理笔记——射频基础知识

一、什么是射频 射频&#xff08;RF&#xff09;&#xff0c;表示可以辐射到空间的电磁频率&#xff0c;频率范围从300kHz&#xff5e;300GHz之间。每秒变化小于1000次的交流电称为低频电流&#xff0c;大于10000次的交流电称为高频电流&#xff0c;射频就是高频交流变化的电磁…

vue,mixins混入

痛点&#xff1a;当我们的项目越来越庞大&#xff0c;项目中的某些组件之间可能会存在一些相似的功能&#xff0c;这就导致了在各个组件中需要编写功能相同的代码段&#xff0c;重复地定义这些相同的属性和方法&#xff0c;导致代码地冗余&#xff0c;还不利于后期代码的维护。…

【芯片设计- RTL 数字逻辑设计入门 5 -- RTL 全加器实现及验证】

文章目录 1.11.1.1 DUT Code1.1.2 Testbench1.1.3 自动化编译:Makefile1.1.4 Debug 方法 1.2 逻辑综合工具 - Design Compile1.2.1 逻辑综合流程1.2.2 逻辑综合方法 1.1 1.1.1 DUT Code 以实现一个全加器为例子, 功能 真值表 验证 功能完整性穷举法代码覆盖率 lab01 编译仿…

哈希应用 : 位图和布隆过滤器

位图 在这里我们可以用一种哈希的新方法 -- 又快又节省内存&#xff08;位图&#xff09; -------------------------------------------------------------------------------------------------------------------------------- 对我们的位进行标记 位图的应用 1.给定100亿…

SVV,PPV算法开发记录

定义 刘大为-血液动力学 Getinge 链接&#xff1a;高级监测参数: SVV, PPV 数据集 计算SVV和PPV使用的动脉血压曲线&#xff0c;在此选用了Kaggle上的Cuff-Less Blood Pressure Estimation数据集&#xff0c;该数据集包含PPG&#xff0c;ABP&#xff0c;ECG三条曲线&…