原始类型的方法
一个原始值:有 7 种原始类型:string,number,bigint,boolean,symbol,null 和 undefined。
一个对象:能够存储多个值作为属性。 {} 创建对象
对象包装器
被称为 String、Number、Boolean 和 Symbol。它们提供了不同的方法。
let str = "Hello";
alert( str.toUpperCase() ); // HELLO
- 字符串
str是一个原始值。因此,在访问其属性时,会创建一个包含字符串字面值的特殊对象,并且具有有用的方法,例如toUpperCase()。 - 该方法运行并返回一个新的字符串。
- 特殊对象被销毁,只留下原始值
str。
通过包装器,原始类型可以提供方法。
null/undefined 没有任何方法 没有包装器 注意:
- 不要用new Number(0) 方式创建,会返回对象,所有判断都是true
- 应改用没有new 的 Number(0)方法调用直接返回基本类型 例如:
alert( typeof 0 ); // "number"
alert( typeof new Number(0) ); // "object"!
let zero = new Number(0);
if (zero) { // zero 为 true,因为它是一个对象, 始终为真,
alert( "xxx" );
}
//改用 直接调用方法
let zero = Number(0);
if (zero) { // zero => false
alert( "xxxx" );
}
动态给包装类添加属性
let abc = "xxxx";
abc.name = 'jason'; // 这里包装类还在,可以赋值,但是在严格模式下会报错
alert(str.name); // 到这里 包装类已经被销毁,所以是 undefined
数字类型
number 包含两种
- 双精度浮点数
- BigInt
简写
1e3 = 1 * 1000 // "e" 把数字乘以 1 后面跟着给定数量的 0 的数字。
1.23e6 = 1.23 * 1000000
let ms = 0.000001;
let ms = 1e-6; // 1 的左边有 6 个 0 等价于 1 / 1000000
十六进制,二进制和八进制数字
//16进制
alert( 0xff ); // 255
alert( 0xFF ); // 255(一样,大小写没影响)
//二进制 8进制
let a = 0b11111111; // 二进制形式的 255
let b = 0o377; // 八进制形式的 255
alert( a == b ); // true,两边是相同的数字,都是 255
toString(base)
参数base是指用什么编码转化,最大36
let num = 255;
alert( num.toString() ); // 默认是10进制 255
alert( num.toString(16) ); // 16进制 ff
alert( num.toString(2) ); // 二进制 11111111
直接数字转化,可以把长数字转短数字,方便url传输
alert( 123456..toString(36) ); // 2n9c
//注意这里 需要使用.. 两个点。 因为一个点js以为是正常小数,两个点js能识别是特殊处理。
//等价于
(123456).toString(36)
舍入
Math.floor
向下舍入:3.1 变成 3,-1.1 变成 -2。
Math.ceil
向上舍入:3.1 变成 4,-1.1 变成 -1。
Math.round
向最近的整数舍入:3.1 变成 3,3.6 变成 4,-1.1 变成 -1。
Math.trunc(IE不支持)
都不舍入:3.1 变成 3,-1.1 变成 -1。
保留2位小数
1.2345=> `1.23
//方法1: 先变整数处理,然后再除回去
let num = 1.23456;
alert( Math.floor(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23
//方式2:toFixed 会-四舍五入
let num = 12.34;
alert( num.toFixed(1) ); // "12.3" //
//内容长会补零
let num = 12.34;
alert( num.toFixed(5) ); // "12.34000",在结尾添加了 0
长度问题
数字是以 64 位格式IEEE-754 存储一个数字:
- 52 位被用于存储这些数字,
- 11 位用于存储小数点的位置(对于整数,它们为零),
- 1 位用于符号
//长度太大
alert( 1e500 ); // Infinity
//精度问题
alert( 0.1 + 0.2 ); // 0.30000000000000004
alert( 0.1 + 0.2 == 0.3 ); // false
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
//精度解决方案
let sum = 0.1 + 0.2;
alert( sum.toFixed(2) ); // 0.30
//利用乘法放大
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
js 无法描述三分之一,在数学里,这是不可描述,是个无理数。
isNaN
NaN代表一个 error。:
alert( isNaN(NaN) ); // true
alert( isNaN("str") ); // true
//不能直接NaN与NaN比较, “NaN” 是独一无二
alert( NaN === NaN ); // false
isFinite
isFinite(value) 将其参数转换为数字,是否为常规数
alert( isFinite("15") ); // true
alert( isFinite("str") ); // false,因为是一个特殊的值:NaN
alert( isFinite(Infinity) ); // false,因为是一个特殊的值:Infinity
Object.is
Object.is(NaN,NaN) === true //true
Object.is(0,-0)=== false //false //因为数字的符号位可能会不同
parseInt 和 parseFloat
alert( parseInt('100px') ); // 100
alert( parseFloat('12.5em') ); // 12.5
alert( parseInt('12.3') ); // 12,只有整数部分被返回了
alert( parseFloat('12.3.4') ); // 12.3,在第二个点出停止了读取
//读不到的情况
alert( parseInt('a123') ); // NaN,第一个符号停止了读取
//第二个参数是 以什么进制读取
alert( parseInt('0xff', 16) ); // 16进制读取, 255
其他 Math函数
alert( Math.random() ); // 0.1234567894322
alert( Math.random() ); // 0.5435252343232
alert( Math.random() ); // ... (任何随机数)
Math.max(a, b, c...)` / `Math.min(a, b, c...)
alert( Math.max(3, 5, -10, 0, 1) ); // 5
alert( Math.min(1, 2) ); // 1
Math.pow(n, power)
alert( Math.pow(2, 10) ); // 2 的 10 次幂 = 1024
蛋疼的 精度问题
alert( 1.35.toFixed(1) ); // 1.4
//实际结果
alert( 1.35.toFixed(20) ); // 1.35000000000000008882
alert( 6.35.toFixed(1) ); // 6.3
//实际结果
alert( 6.35.toFixed(20) ); // 6.34999999999999964473
//解决方案
alert( Math.round(6.35 * 10) / 10); // 6.35 -> 63.5 -> 64(rounded) -> 6.4
// 小数部分 0.5 实际上是 1/2,2 的整数次幂为分母的小数在二进制数字系统中可以被精确地表示
min 到 max 的随机数
alert( random(1, 5) ); // 1.2345623452
alert( random(1, 5) ); // 3.7894332423
alert( random(1, 5) ); // 4.3435234525
function random(min,max) {
return min + Math.random() * (min+max)
}
//方法
function randomInteger(min, max) {
// 现在范围是从 (min-0.5) 到 (max+0.5)
let rand = min - 0.5 + Math.random() * (max - min + 1);
return Math.round(rand);
}
alert( randomInteger(1, 3) );
//方法2
function randomInteger(min, max) {
// here rand is from min to (max+1)
let rand = min + Math.random() * (max + 1 - min);
return Math.floor(rand);
}
alert( randomInteger(1, 3) );
字符串
- 文本数据被以字符串形式存储,单个字符没有单独的类型。
- 字符串的内部格式始终是utf-16
特殊字符
特殊字符都以反斜杠字符 `` 开始。它也被称为“转义字符”。
let list = "aaa:\n * bbb\n * ccc\n * ddd";
alert(list); // 多个换行显示
| 字符 | 描述 |
|---|---|
\n | 换行 |
\r | 回车:不单独使用。Windows 文本文件使用两个字符 \r\n 的组合来表示换行。 |
', " | 引号 |
\ | 反斜线 |
\t | 制表符 |
\b, \f, \v | 退格,换页,垂直标签 —— 为了兼容性,现在已经不使用了。 |
\xXX | 具有给定十六进制 Unicode XX 的 Unicode 字符,例如:'\x7A' 和 'z' 相同。 |
\uXXXX | 以 UTF-16 编码的十六进制代码 XXXX 的 unicode 字符,例如 \u00A9 —— 是版权符号 © 的 unicode。它必须正好是 4 个十六进制数字。 |
\u{X…XXXXXX}(1 到 6 个十六进制字符) | 具有给定 UTF-32 编码的 unicode 符号。一些罕见的字符用两个 unicode 符号编码,占用 4 个字节。这样我们就可以插入长代码了。 |
alert( "\u00A9" ); // ©
//字符长度
alert( `My\n`.length ); // 3 ,\n算一个字符
访问字符
let str = `Hello`;
alert( str[0] ); // H
//等价于
alert( str.charAt(0) ); // H
//没有找到
alert( str[1000] ); // undefined
alert( str.charAt(1000) ); // '' 日常开发建议用charAt
字符串是不可变的
let str = 'Hi';
str[0] = 'h'; // 不报错
alert( str[0] ); // 但还是H
//可以整个重新赋值解决
str = 'hi';
查找子字符串
- str.indexOf(substr, pos) //pos 默认为0
- str.lastIndexOf(substr, pos) //相反查询
let str = 'Widget with id';
alert( str.indexOf('Widget') ); // 0,因为 'Widget' 一开始就被找到
alert( str.indexOf('widget') ); // -1,没有找到,检索是大小写敏感的
alert( str.indexOf("id") ); // 1,"id" 在位置 1 处(……idget 和 id)
//从第二个id开始查找
let str = 'Widget with id';
alert( str.indexOf('id', 2) ) // 12
//判断是否包括应该使用
if (str.indexOf("Widget") != -1) {
alert("xxxx");
}
按位(bitwise)NOT 技巧
它将数字转换为 32-bit 整数(如果存在小数部分,则删除小数部分),然后对其二进制表示形式中的所有位均取反
alert( ~2 ); // -3,和 -(2+1) 相同
alert( ~1 ); // -2,和 -(1+1) 相同
alert( ~0 ); // -1,和 -(0+1) 相同
alert( ~-1 ); // 0,和 -(-1+1) 相同
let str = "Widget";
if (~str.indexOf("Widget")) {
alert( 'xxxx' ); //ok
}
includes,startsWith,endsWith
alert( "Widget with id".includes("Widget") ); // true
alert( "Hello".includes("Bye") ); // false
alert( "Widget".startsWith("Wid") ); // true,"Widget" 以 "Wid" 开始
alert( "Widget".endsWith("get") ); // true,"Widget" 以 "get" 结束
获取子字符串
substring、substr 和 slice
str.slice(start [, end])
返回字符串从 start 到(但不包括)end 的部分。注意游标从0开始
let str = "stringify";
alert( str.slice(0, 5) ); // 'strin',从 0 到 5 的子字符串(不包括 5)
alert( str.slice(2) ); // ringify 从第二个位置直到结束
//start/end 也有可能是负值。它们的意思是起始位置从字符串结尾计算:
alert( str.slice(-4, -1) ); // 'gif' // 从右边的第四个位置开始,在右边的第一个位置结束
str.substring(start [, end])
与str.slice 区别在于允许 start 大于 end。相当于不用考虑谁是头谁是尾
let str = "stringify";
// 这些对于 substring 是相同的
alert( str.substring(2, 6) ); // "ring"
alert( str.substring(6, 2) ); // "ring"
// ……但对 slice 是不同的:
alert( str.slice(2, 6) ); // "ring"(一样)
alert( str.slice(6, 2) ); // ""(空字符串)
str.substr(start [, length])
区别允许我们指定 length 而不是具体结束位置
let str = "stringify";
alert( str.substr(2, 4) ); // 'ring',从位置 2 开始,获取 4 个字符
第一个参数可能是负数,从结尾算起:(注意负数是从-1开始计算)
let str = "stringify";
alert( str.substr(-4, 2) ); // 'gi',从第 4 位获取 2 个字符
开发中优先选择slice
| 方法 | 选择方式…… | 负值参数 |
|---|---|---|
slice(start, end) | 从 start 到 end(不含 end) | 允许 |
substring(start, end) | start 与 end 之间(包括 start,但不包括 end) | 负值代表 0 |
substr(start, length) | 从 start 开始获取长为 length 的字符串 | 允许 start 为负数 |
比较字符串
str.codePointAt(pos) //返回在 pos 位置的字符代码 :
alert( 'a' > 'Z' ); // true
// 不同的字母有不同的代码,最终比较的是 UTF-16 编码
alert( "z".codePointAt(0) ); // 122
alert( "Z".codePointAt(0) ); // 90
//把代码转为文本
alert( String.fromCodePoint(90) ); //
总结
- 有 3 种类型的引号。反引号允许字符串跨越多行并可以使用
${…}在字符串中嵌入表达式。 - JavaScript 中的字符串使用的是 UTF-16 编码。
- 我们可以使用像
\n这样的特殊字符或通过使用\u...来操作它们的 unicode 进行字符插入。 - 获取字符时,使用
[]。 - 获取子字符串,使用
slice或substring。 - 字符串的大/小写转换,使用:
toLowerCase/toUpperCase。 - 查找子字符串时,使用
indexOf或includes/startsWith/endsWith进行简单检查。 - 根据语言比较字符串时使用
localeCompare,否则将按字符代码进行比较。