本文将深入探讨几个重要的 JavaScript 特性,包括位运算、数据类型及其转换规则,以及强大的正则表达式用法。
位运算
位运算是直接对二进制数的每一位进行计算的操作,常用于性能优化、加密算法等领域。JavaScript 提供了以下几种位运算符:
-
按位与 (
&
):- 比较两个操作数对应的二进制位,只有当两个相应的二进制位都为1时,结果才为1,否则为0。
console.log(5 & 3); // 输出: 1 (二进制: 101 & 011 = 001)
-
按位或 (
|
):- 比较两个操作数对应的二进制位,只要有一个相应的二进制位为1,结果就为1。
console.log(5 | 3); // 输出: 7 (二进制: 101 | 011 = 111)
-
按位异或 (
^
):- 比较两个操作数对应的二进制位,如果两个相应的二进制位不同,则结果为1;相同则为0。
console.log(5 ^ 3); // 输出: 6 (二进制: 101 ^ 011 = 110)
-
按位非 (
~
):- 反转操作数的所有二进制位,即把0变为1,1变为0。
console.log(~5); // 输出: -6 (二进制: ~000...0101 = 111...1010)
-
左移 (
<<
):- 将第一个操作数的二进制表示向左移动指定的数量,并在右侧填充零。
console.log(5 << 1); // 输出: 10 (二进制: 101 << 1 = 1010)
-
右移 (
>>
):- 将第一个操作数的二进制表示向右移动指定的数量,并在左侧填充符号位(对于负数是1,对于正数是0)。
console.log(-5 >> 1); // 输出: -3 (二进制: ...11111011 >> 1 = ...11111101)
-
无符号右移 (
>>>
):- 类似于右移运算符,但它总是使用0来填充左侧空缺的位置,即使操作数是负数。
console.log(-5 >>> 1); // 输出: 2147483646 (二进制: ...11111011 >>> 1 = 01011111111111111111111111111110)
应用场景举例:
-
计算机图形学中的颜色混合:
let color = 0x123456; // 十六进制表示的颜色值 let red = (color >> 16) & 0xFF; let green = (color >> 8) & 0xFF; let blue = color & 0xFF; console.log(`Red: ${red}, Green: ${green}, Blue: ${blue}`); // 输出: Red: 18, Green: 52, Blue: 86
-
数据压缩与解压:
// 示例:假设我们有两个小整数a和b,范围都在0-15之间(各占4位) let a = 10, b = 5; let combined = (a << 4) | b; // 将两个数合并到一个字节内 console.log(combined.toString(16)); // 输出: "aa" let extractedA = (combined >> 4) & 0xF; let extractedB = combined & 0xF; console.log(`Extracted A: ${extractedA}, Extracted B: ${extractedB}`); // 输出: Extracted A: 10, Extracted B: 5
正则表达式
正则表达式(Regular Expression),通常简称为 regex 或 regexp,是一种用于匹配字符串中字符组合的模式。它不仅功能强大,而且非常灵活,广泛应用于文本处理任务
中,如查找、替换、分割等操作。值得注意的是,在 JavaScript 中,正则表达式通过 RegExp
对象实现,提供了丰富的接口来处理各种文本数据。
(一)创建正则表达式的方法
创建正则表达式有多种方式,主要分为两种:
-
通过 RegExp 构造函数: 这种方法允许动态构建正则表达式,适用于需要根据程序逻辑变化而变化的情况。
.test()
方法:这里的用法与上面的例子相同,用于检测字符串是否包含与正则表达式匹配的内容const pattern1 = new RegExp("e"); console.log(pattern1.test("The best things in life are free")); // 输出: true
-
利用字面量语法: 字面量形式更加简洁明了,适合于已知固定模式的情况下使用。
const pattern2 = /e/; console.log(pattern2.test("The best things in life are free")); // 输出: true
(二)常见正则表达式构成元素及其用法
1. 字符类
字符类用于指定一组字符中的任意一个。
-
匹配单个字符:
-
[abc]
:匹配 'a'、'b' 或 'c' 中的任何一个字符。const pattern = /[abc]/; console.log(pattern.test('apple')); // 输出: true (因为 'apple' 中含有 'a') console.log(pattern.test('banana')); // 输出: true (因为 'banana' 中含有 'b') console.log(pattern.test('cherry')); // 输出: true (因为 'cherry' 中含有 'c') console.log(pattern.test('grape')); // 输出: false (因为 'grape' 不含 'a', 'b', 或 'c')
-
-
排除特定字符:
-
[^abc]
:匹配不是 'a'、'b' 或 'c' 的任何字符。const pattern = /[^abc]/; console.log(pattern.test('apple')); // 输出: true (因为 'apple' 中含有 'p', 'p', 'l', 'e') console.log(pattern.test('abc')); // 输出: false (因为 'abc' 中只含有 'a', 'b', 'c')
-
-
范围匹配:
-
[a-z]
:匹配从 'a' 到 'z' 的任意一个小写字母。 -
[0-9]
:匹配从 '0' 到 '9' 的任意一个数字。const letterPattern = /[a-z]/; console.log(letterPattern.test('Hello')); // 输出: true (因为 'Hello' 中含有小写字母 'e') const digitPattern = /[0-9]/; console.log(digitPattern.test('12345')); // 输出: true (因为 '12345' 全部都是数字)
-
2. 预定义字符类
预定义字符类提供了一些常用的字符集。
-
.
:匹配除换行符外的任何单个字符。const pattern = /./; console.log(pattern.test('x')); // 输出: true (匹配任何字符) console.log(pattern.test('\n')); // 输出: false (不匹配换行符)
-
\d
:匹配一个数字字符,等同于[0-9]
。const pattern = /\d/; console.log(pattern.test('123')); // 输出: true (因为 '123' 含有数字) console.log(pattern.test('abc')); // 输出: false (因为 'abc' 不含数字)
-
\D
:匹配非数字字符,等同于[^0-9]
。const pattern = /\D/; console.log(pattern.test('123')); // 输出: false (因为 '123' 全部都是数字) console.log(pattern.test('abc')); // 输出: true (因为 'abc' 含有非数字字符)
-
\w
:匹配单词字符,包括下划线,等同于[A-Za-z0-9_]
。const pattern = /\w/; console.log(pattern.test('Hello_World')); // 输出: true (因为 'Hello_World' 含有单词字符) console.log(pattern.test('@!')); // 输出: false (因为 '@!' 不含单词字符)
-
\W
:匹配非单词字符,等同于[^A-Za-z0-9_]
。const pattern = /\W/; console.log(pattern.test('Hello_World')); // 输出: false (因为 'Hello_World' 全部都是单词字符) console.log(pattern.test('@!')); // 输出: true (因为 '@!' 含有非单词字符)
-
\s
:匹配空白字符,包括空格、制表符、换页符等。const pattern = /\s/; console.log(pattern.test('Hello World')); // 输出: true (因为 'Hello World' 中间有一个空格) console.log(pattern.test('HelloWorld')); // 输出: false (因为 'HelloWorld' 没有空白字符)
-
\S
:匹配非空白字符。const pattern = /\S/; console.log(pattern.test('Hello World')); // 输出: true (因为 'Hello World' 含有非空白字符) console.log(pattern.test(' ')); // 输出: false (因为 ' ' 全部都是空白字符)
3. 量词
量词用于指定某个元素出现的次数。
-
*
:匹配前面的子表达式零次或多次。const pattern = /a*/; console.log(pattern.test('')); // 输出: true (空字符串也符合条件,因为 'a' 出现了零次) console.log(pattern.test('aaa')); // 输出: true (因为 'aaa' 中 'a' 出现了多次)
-
+
:匹配前面的子表达式一次或多次。const pattern = /a+/; console.log(pattern.test('a')); // 输出: true (因为 'a' 至少出现了一次) console.log(pattern.test('aa')); // 输出: true (因为 'aa' 中 'a' 出现了多次) console.log(pattern.test('')); // 输出: false (因为 'a' 没有出现)
-
?
:匹配前面的子表达式零次或一次。const pattern = /a?/; console.log(pattern.test('')); // 输出: true (因为 'a' 没有出现也可以) console.log(pattern.test('a')); // 输出: true (因为 'a' 出现了一次) console.log(pattern.test('aa')); // 输出: true (因为 'aa' 第一个 'a' 符合条件)
-
{n}
:精确匹配 n 次。const pattern = /a{3}/; console.log(pattern.test('aaa')); // 输出: true (因为 'aaa' 中 'a' 出现了三次) console.log(pattern.test('aa')); // 输出: false (因为 'aa' 中 'a' 只出现了两次)
-
{n,}
:至少匹配 n 次。const pattern = /a{2,}/; console.log(pattern.test('aa')); // 输出: true (因为 'aa' 中 'a' 至少出现了两次) console.log(pattern.test('a')); // 输出: false (因为 'a' 只出现了一次)
-
{n,m}
:最少匹配 n 次,最多匹配 m 次。const pattern = /a{1,3}/; console.log(pattern.test('a')); // 输出: true (因为 'a' 出现了一次) console.log(pattern.test('aaaa')); // 输出: true (虽然 'aaaa' 中 'a' 出现了四次,但只要前三次符合即可)
4. 边界匹配器
边界匹配器用于匹配字符串的开头或结尾,以及单词边界。
-
^
:匹配输入字符串的开始位置。const pattern = /^Hello/; console.log(pattern.test('Hello World')); // 输出: true (因为 'Hello' 在字符串的开头) console.log(pattern.test('Hi Hello')); // 输出: false (因为 'Hello' 不在字符串的开头)
-
$
:匹配输入字符串的结束位置。const pattern = /World$/; console.log(pattern.test('Hello World')); // 输出: true (因为 'World' 在字符串的末尾) console.log(pattern.test('Hello World!')); // 输出: false (因为 'World' 不在字符串的末尾)
-
\b
:匹配单词边界。const pattern = /\bWorld\b/; console.log(pattern.test('Hello World')); // 输出: true (因为 'World' 是一个独立的单词) console.log(pattern.test('HelloWorld')); // 输出: false (因为 'World' 不是一个独立的单词)
-
\B
:匹配非单词边界。const pattern = /\BWorld\B/; console.log(pattern.test('HelloWorld')); // 输出: true (因为 'World' 不是一个独立的单词) console.log(pattern.test('Hello World')); // 输出: false (因为 'World' 是一个独立的单词)
5. 组和选择
组和选择用于定义多个可选的匹配模式。
-
(ab)
:将括号内的内容视为一个整体,可以用于分组。const pattern = /(ab)+/; console.log(pattern.test('abab')); // 输出: true (因为 'abab' 中 'ab' 出现了两次) console.log(pattern.test('aba')); // 输出: false (因为 'aba' 不符合 '(ab)+' 的模式)
-
|
:表示选择关系,匹配左边或右边的模式,。const pattern = /cat|dog/; //选择cat或是dog console.log(pattern.test('I have a cat')); // 输出: true (因为 'cat' 存在于字符串中) console.log(pattern.test('I have a bird')); // 输出: false (因为既没有 'cat' 也没有 'dog')
数据类型及其特点
我的主页有篇文章讲了剖析JS底层数据类型和堆栈内存,可以看完下面的转到这篇文章。 下面简单介绍JavaScript里面数据类型。总共有七种内置的数据类型:原始类型(Primitive Types)和对象类型(Object Types)。其中,原始类型包括 Number、String、Boolean、Null、Undefined 和 Symbol(ES6新增),而对象类型仅有一种——Object。
-
Number 类型:
- 用于表示整数和浮点数,在内部以双精度64位IEEE 754格式存储。
- 整数:范围从 -(2^53 - 1) 到 +(2^53 - 1),超过此范围可能导致精度丢失。
- 浮点数:支持科学计数法表示大数或小数。
- 特殊数值:Infinity 表示无穷大,-Infinity 表示负无穷大,NaN 表示“不是一个数字”。
- 注意:NaN 的数据类型是 number。
typeof NaN === 'number'; // true isNaN(NaN); // true isNaN('Hello'); // true (因为尝试将其转换为数字失败) Number.isNaN(NaN); // true (推荐方式,避免全局作用域下的 isNaN 函数带来的问题)
-
String 类型:
- 用于表示文本数据,可以通过单引号、双引号或模板字符串定义。
- 不可变性:字符串一旦创建就不能更改,所有修改操作都会生成新的字符串实例。
- 常用方法:.length 获取长度,.charAt(index) 获取指定位置字符,.concat(str) 连接字符串,.indexOf(substring) 查找子串位置等。
let greeting = "Hello"; greeting += ", world!"; console.log(greeting.length); // 输出: 13 console.log(greeting.charAt(0)); // 输出: H console.log(greeting.indexOf("world")); // 输出: 7
-
Boolean 类型:
- 只有两个可能的值:true 或 false,用于逻辑判断。
let isValid = true; if (!isValid) { console.log("Invalid"); } else { console.log("Valid"); // 输出: Valid }
-
Null 类型:
- 只有一个值 null,表示空值或不存在的对象引用。
- 注意:null 的数据类型是 object,这被认为是一个历史遗留错误。
typeof null === 'object'; // true let emptyValue = null; console.log(emptyValue); // 输出: null
-
Undefined 类型:
- 只有一个值 undefined,表示变量声明但未赋值。
- 注意:未定义变量的数据类型为 undefined。
let uninitializedVar; console.log(uninitializedVar); // 输出: undefined console.log(typeof uninitializedVar); // 输出: undefined
-
Object 类型:
- 最复杂的类型之一,用于存储键值对集合,可以模拟类的概念。常见的对象有数组(Array)、日期(Date)、函数(Function)等。
- 数组(Array):
let fruits = ["apple", "banana", "cherry"]; console.log(fruits[0]); // 输出: apple console.log(fruits.length); // 输出: 3 // 注意: 数组(Array)的数据类型是 object。
- 日期(Date):
let now = new Date(); console.log(now.getFullYear()); // 输出当前年份 console.log(now.getMonth() + 1); // 输出当前月份 (0-11 -> 1-12) // 注意: 日期(Date)的数据类型为 object。
- 函数(Function):
function greet(name) { return `Hello, ${name}!`; } console.log(greet("Alice")); // 输出: Hello, Alice!
-
Symbol 类型 (ES6 新增):
- 引入了一个全新的原始类型,表示唯一的标识符。每次调用 Symbol() 都会返回一个新的唯一值。
- 用途:主要用于作为对象属性名,防止命名冲突。
let id = Symbol("id"); let user = {}; user[id] = 12345; console.log(user[id]); // 输出: 12345
内容有点长,适合收藏后面继续阅读学习~~