Files
learning/JavaScript.md
2026-07-06 21:56:17 +08:00

13 KiB
Raw Permalink Blame History

name 变量名与 window.name

// 假设你想声明一个数字类型的 name
var name = 123; 

// 你以为它是数字,但它其实变成了字符串
console.log(typeof name); // 输出: "string" ❌
console.log(name + 1);    // 输出: "1231" (字符串拼接,而不是数学加法) ❌

在浏览器中,var name = 123; 实际上等同于 window.name = 123;。而 window.name 是一个内置属性,浏览器在底层会强制调用 String(123),将其变为 "123"

参考:Window: name property - Web APIs | MDN

交互alert、prompt 和 confirm

alert("Hello");
result = prompt(title, [default]);
result = confirm(question); // true | false

类型转换

字符串转换

我们也可以显式地调用 String(value) 来将 value 转换为字符串类型:

let value = true;
alert(typeof value); // boolean

value = String(value); // 现在,值是一个字符串形式的 "true"
alert(typeof value); // string

数字型转换

在算术函数和表达式中,会自动进行 number 类型转换。

alert( "6" / "2" ); // 3, string 类型的值被自动转换成 number 类型后进行计算

显式转换。

let str = "123";
alert(typeof str); // string

let num = Number(str); // 变成 number 类型 123

alert(typeof num); // number

Number 类型的转换规则:

变成……
undefined NaN
null 0
true 和 false 1 and 0
string 去掉首尾空白字符(空格、换行符 \n、制表符 \t 等)后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为 0。否则,将会从剩余字符串中“读取”数字。当类型转换出现 error 时返回 NaN

布尔型转换

它发生在逻辑运算中,也可以通过调用 Boolean(value) 显式地进行转换。

转换规则如下:

  • 直观上为“空”的值(如 0、空字符串、nullundefinedNaN)将变为 false
  • 其他值变成 true

基础运算符,数学运算

术语:“一元运算符”,“二元运算符”,“运算元”

运算元:比如说乘法运算 5 * 2,有两个运算元:左运算元 5 和右运算元 2。有时候人们也称其为“参数”而不是“运算元”。

如果一个运算符对应的只有一个运算元,那么它是 一元运算符。比如说一元负号运算符unary negation-,它的作用是对数字进行正负转换:

let x = 1;

x = -x;
alert( x ); // -1一元负号运算符生效

如果一个运算符拥有两个运算元,那么它是 二元运算符。减号还存在二元运算符形式:

let x = 1, y = 3;
alert( y - x ); // 2二元运算符减号做减运算

数学运算

支持以下数学运算:

  • 加法 +,
  • 减法 -,
  • 乘法 *,
  • 除法 /,
  • 取余 %,
  • 求幂 **.

数字转化,一元运算符 +

加号 + 有两种形式。一种是上面我们刚刚讨论的二元运算符,还有一种是一元运算符。

一元运算符加号,或者说,加号 + 应用于单个值,对数字没有任何作用。但是如果运算元不是数字,加号 + 则会将其转化为数字。

let apples = "2";
let oranges = "3";

alert( apples + oranges ); // "23",二元运算符加号合并字符串
let apples = "2";
let oranges = "3";

// 在二元运算符加号起作用之前,所有的值都被转化为了数字
alert( +apples + +oranges ); // 5

// 更长的写法
// alert( Number(apples) + Number(oranges) ); // 5	

逗号运算符

逗号运算符能让我们处理多个表达式,使用 , 将它们分开。每个表达式都运行了,但是只有最后一个的结果会被返回。

let a = (1 + 2, 3 + 4);

alert( a ); // 73 + 4 的结果)

// 一行上有三个运算符
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}

值的比较

字符串比较

在比较字符串的大小时JavaScript 会使用 Unicode 编码顺序 顺序进行判定。

换言之,字符串是按字符(母)逐个进行比较的。

例如:

alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true

字符串的比较算法非常简单:

  1. 首先比较两个字符串的首位字符大小。
  2. 如果一方字符较大(或较小),则该字符串大于(或小于)另一个字符串。算法结束。
  3. 否则,如果两个字符串的首位字符相等,则继续取出两个字符串各自的后一位字符进行比较。
  4. 重复上述步骤进行比较,直到比较完成某字符串的所有字符为止。
  5. 如果两个字符串的字符同时用完,那么则判定它们相等,否则未结束(还有未比较的字符)的字符串更大。

不同类型间的比较

当对不同类型的值进行比较时,除了 nullundefinedJavaScript 会首先将其转化为数字number再判定大小。

alert( '2' > 1 ); // true字符串 '2' 会被转化为数字 2
alert( '01' == 1 ); // true字符串 '01' 会被转化为数字 1
alert( true == 1 ); // true
alert( false == 0 ); // true

严格相等

普通的相等性检查 == 存在一个问题,它不能区分出 0false

alert( 0 == false ); // true

也同样无法区分空字符串和 false

alert( '' == false ); // true

严格相等运算符 === 在进行比较时不会做任何的类型转换。

alert( 0 === false ); // false因为被比较值的数据类型不同

null 与 undefined 比较

它们不相等,因为它们属于不同的类型。

alert( null === undefined ); // false

JavaScript 存在一个特殊的规则,会判定它们相等。

alert( null == undefined ); // true

undefinednull 在相等性检查 == 中不会进行任何的类型转换,它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。

alert( null > 0 );  // (1) false, null => 0
alert( null == 0 ); // (2) false, null => null
alert( null >= 0 ); // (3) true, null => 0

undefined 与其他值比较

undefined 不应该被与其他值进行比较:

alert( undefined > 0 ); // false
alert( undefined < 0 ); // false
alert( undefined == 0 ); // false

条件分支if 和 '?'

布尔转换

  • 数字 0、空字符串 ""nullundefinedNaN 都会被转换成 false。因为它们被称为“假值falsy”。
  • 其他值被转换为 true所以它们被称为“真值truthy”。

逻辑运算符

JavaScript 中有四个逻辑运算符:||(或),&&(与),!(非),??(空值合并运算符)。

或运算

或运算:寻找第一个真值最后一个假值

一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。

alert( 1 || 0 ); // 11 是真值)

alert( null || 1 ); // 11 是第一个真值)
alert( null || 0 || 1 ); // 1第一个真值

alert( undefined || null || 0 ); // 0都是假值返回最后一个值

有趣的用法:

let firstName = "";
let lastName = "";
let nickName = "SuperCoder";

alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder

true || alert("not printed");
false || alert("printed");

与运算

与运算:寻找第一个假值或最后一个真值

// 如果第一个操作数是真值,
// 与运算返回第二个操作数:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5

// 如果第一个操作数是假值,
// 与运算将直接返回它。第二个操作数会被忽略
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0

alert( 1 && 2 && null && 3 ); // null
alert( 1 && 2 && 3 ); // 3最后一个值

与运算 && 在或运算 || 之前进行

与运算 && 的优先级比或运算 || 要高。

所以代码 a && b || c && d&& 表达式加了括号完全一样:(a && b) || (c && d)

!(非)

两个非运算 !! 有时候用来将某个值转化为布尔类型:

alert( !!"non-empty string" ); // true
alert( !!null ); // false
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false

也就是,第一个非运算将该值转化为布尔类型并取反,第二个非运算再次取反。最后我们就得到了一个任意值到布尔值的转化。

非运算符 ! 的优先级在所有逻辑运算符里面最高,所以它总是在 &&|| 之前执行。

空值合并运算符 '??'

由于它对待 nullundefined 的方式类似,所以在本文中我们将使用一个特殊的术语对其进行表示。为简洁起见,当一个值既不是 null 也不是 undefined我们将其称为“已定义的defined”。

a ?? b 的结果是:

  • 如果 a 是已定义的,则结果为 a
  • 如果 a 不是已定义的,则结果为 b

我们可以使用我们已知的运算符重写 result = a ?? b,像这样:

result = (a !== null && a !== undefined) ? a : b;

|| 比较

它们之间重要的区别是:

  • || 返回第一个 值。
  • ?? 返回第一个 已定义的 值。
let height = 0;

alert(height || 100); // 100
alert(height ?? 100); // 0

"switch" 语句

类型很关键

强调一下,这里的相等是严格相等。被比较的值必须是相同的类型才能进行匹配。

比如,我们来看下面的代码:

let arg = prompt("Enter a value?")
switch (arg) {
  case '0':
  case '1':
    alert( 'One or zero' );
    break;

  case '2':
    alert( 'Two' );
    break;

  case 3:
    alert( 'Never executes!' );
    break;
  default:
    alert( 'An unknown value' )
}
  1. prompt 对话框输入 01,第一个 alert 弹出。
  2. 输入 2,第二个 alert 弹出。
  3. 但是输入 3,因为 prompt 的结果是字符串类型的 "3",不严格相等 === 于数字类型的 3,所以 case 3 不会执行!因此 case 3 部分是一段无效代码。所以会执行 default 分支。

函数

function name(parameter1, parameter2, ... parameterN) {
  ...body...
}
  
name();

参数默认值

function showMessage(from, text = "no text given") {
  alert( from + ": " + text );
}

showMessage("Ann"); // Ann: no text given
function showMessage(from, text = anotherFunction()) {
  // anotherFunction() 仅在没有给定 text 时执行
  // 其运行结果将成为 text 的值
}

后备的默认参数

有些时候,将参数默认值的设置放在函数执行(相较更后期)而不是函数声明时,也行得通。

我们可以通过将参数与 undefined 进行比较,来检查该参数是否在函数执行期间被传递进来:

function showCount(count) {
  // 如果 count 为 undefined 或 null则提示 "unknown"
  alert(count ?? "unknown");
}

showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown

返回值

空值的 return 或没有 return 的函数返回值为 undefined

function doNothing() { /* 没有代码 */ }

function doNothing() {
  return;
  // return undefined;
}

alert( doNothing() === undefined ); // true

函数表达式

在 JavaScript 中,函数不是“神奇的语言结构”,而是一种特殊的值。

函数声明语法:

function sayHi() {
  alert( "Hello" );
}

alert(sayHi); // 显示函数代码

函数表达式语法:

let sayHi = function() {
  alert( "Hello" );
};

alert(sayHi); // 显示函数代码

回调函数

function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

function showOk() {
  alert( "You agreed." );
}

function showCancel() {
  alert( "You canceled the execution." );
}

// 用法:函数 showOk 和 showCancel 被作为参数传入到 ask
ask("Do you agree?", showOk, showCancel);

与函数声明区别

函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用。

函数声明则不同,在函数声明被定义之前,它就可以被调用。这是内部算法的缘故。当 JavaScript 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数。

箭头函数

let func = (arg1, arg2, ..., argN) => expression;


let func = function(arg1, arg2, ..., argN) {
  return expression;
};