JavaScript基础语法

第三部分 Number类型和String类型

原始类型和对象之间的区别:

  • 在 JavaScript 中有 7 种原始类型:string,number,bigint,boolean,symbol,null 和 undefined。
  • 对象能够存储多个值作为属性。可以使用大括号 {} 创建对象,例如:{name: “John”, age: 30}。JavaScript 中还有其他种类的对象,例如函数就是对象。
1、Number类型

代表整数和浮点数。特殊数值:Infinity-InfinityNaN也属于Number类型,Infinity表示,可通过除以0来得到; NaN由不正确或未定义的数学操作得到。Number类型只能存储±(2 的53次方 -1) 范围内的值。

//定义较大的数字时,直接写可读性比较差
//let billion = 1000000000; //10亿
//使用下划线作为分隔符
//let billion = 1_000_000_000; //下划线扮演“语法糖”的角色,JS引擎会直接忽略掉,与上述效果一样
//更方便的写法,在后面加e
let billion = 1e9; //10亿=1后面跟9个0
//表示很小的负数
let mcs = 1e-6; // 0.000001=1 的左边有 6 个 0=小数点往前移6位
十六进制、二进制、八进制表示
//十六进制前缀0x
alert( 0xff ); // 255
alert( 0xFF ); // 255(一样,大小写没影响)
//二进制前缀0b
let a = 0b11111111; // 二进制形式的 255
//八进制前缀0o
let b = 0o377; // 八进制形式的 255
alert( a == b ); // true,两边是相同的数字,都是 255

只有这3种进制支持这种写法,其他进制使用parseInt方法num.toString(base):把数值num转换为base进制下的表现形式
base值的范围是2到36,默认是10。

let num = 255;
alert( num.toString(16) );  // ff
alert( num.toString(2) );   // 11111111

//如果不想定义变量num,用数字直接调用方法的话,需要写成这种模式
alert( 255..toString(16) );  // ff
//或者
alert( (255).toString(16) );  // ff
//因为JS语法隐含了第一个点后面为小数,再加一个点的话,他就知道不是小数,该调用方法了。
舍入

Math.floor(向下舍入)

Math.ceil(向上舍入)

Math.round(向最近整数舍入)

Math.trunc(舍去小数点后数字)

3.1

3

4

3

3

3.6

3

4

4

3

-1.1

-2

-1

-1

-1

-1.6

-2

-1

-2

-1

如果要舍入到小数点后n位,如保留2位小数,可以先将数字乘以100,再调用色入函数,再,除以100。也可以用函数toFixed(n),将数字舍入小数点后n位,1⃣️字符串形式返回结果。舍入规则类似于Math.round

不精确的计算

JavaScript遵循IEEE754标准,有 64 位可以存储一个数字:其中 52 位被用于存储这些数字,其中 11 位用于存储小数点的位置,而 1 位用于符号。
如果一个数字很大,就会溢出64位存储,发生精度丢失。

alert( 0.1 + 0.2 == 0.3 ); // false
alert( 0.1 + 0.2 ); // 0.30000000000000004
//这是因为0.1和0.2在转换为二进制浮点数时是无穷的,计算时精度丢失叠加,最终造成不等于0.3

解决办法:

let sum = 0.1 + 0.2;
alert( sum.toFixed(2) ); // 0.30
//也可alert(+sum.toFixed(2) ); 将结果转换为一个数字
isNaN和isFinite

isNaN(value) 将其参数转换为数字,然后测试它是否为 NaN:

alert( isNaN(NaN) ); // true
alert( isNaN("str") ); // true
//判断一个值是否为NaN,不能用==和===,因为NaN是唯一的,它不和任何值相等
alert( NaN === NaN ); // false

isFinite(value) 将其参数转换为数字,如果是常规数字而不是 NaN/Infinity/-Infinity,则返回 true:

alert( isFinite("15") ); // true
alert( isFinite("str") ); // false,因为是一个特殊的值:NaN
alert( isFinite(Infinity) ); // false,因为是一个特殊的值:Infinity

**注:**有内容的字符串会被视作NaN,但是空字符串或者只包含空格的字符串均被视作0。

Object.is方法——一个特殊的内建方法

类似于“===”,但是对于两种边缘情况更加准确:

  1. 它适用于 NaN:Object.is(NaN, NaN) === true
  2. 值 0 和 -0 是不同的:Object.is(0, -0) === false,因为在内部,数字的符号位可能会不同,即使其他所有位均为零。
parseInt和parseFloat

使用+或者是Number()转换数字是非常严格的,如果要转换的是一个字符串,则会输出NaN,所以用parseInt和parseFloat。
它们可以从字符串中读取数字,直到无法读取为止。如果发生 error,则返回收集到的数字。函数 parseInt 返回一个整数,而 parseFloat 返回一个浮点数:

alert( parseInt('100px') ); // 100
alert( parseFloat('12.5em') ); // 12.5

alert( parseInt('12.3') ); // 12,只有整数部分被返回了
alert( parseFloat('12.3.4') ); // 12.3,在第二个点出停止了读取
//若从一开始就无数字可读时,返回NaN
alert( parseInt('a123') );// NaN,第一个符号停止了读取
其他数学函数
  1. Math.random()返回一个从0到1的随机数(不包括1)
  2. Math.max(a,b,c...)Math.min(a,b,c...)返回所给参数中的最大值和最小值,参数个数任意
  3. Math.pow(n,power)返回n的power次幂
2、String类型

在 JavaScript 中,文本数据被以字符串形式存储,单个字符没有单独的类型。
字符串的内部格式始终是 UTF-16,它不依赖于页面编码。

引号

单引号、双引号功能一样
反引号支持向字符串中嵌入表达式,并且反引号允许字符串换行。
单引号双引号如果想换行的话,需配合换行符\n使用

访问字符串中的字符

获取某一位置的字符:

let str = `Hello`;

// 第一个字符
alert( str[0] ); // H
alert( str.charAt(0) ); // H
//上述两种方法的区别在于,如果没有找到字符时,[]返回undefined,charAt()返回空字符串
// 最后一个字符
alert( str[str.length - 1] ); // o

使用for...of遍历

for (let char of "Hello") {
  alert(char); // H,e,l,l,o(
}

字符串是不可变的

let str = 'Hi';
str[0] = 'h'; // error
alert( str[0] ); // TypeError: Cannot assign to read only property '0' of string 'Hi'
改变大小写
alert( 'Interface'.toUpperCase() ); // INTERFACE
alert( 'Interface'.toLowerCase() ); // interface
//只改变单个字符
alert( 'Interface'[0].toLowerCase() ); // 'i'
查找子字符串
  1. str.indexOf(substr,pos)从pos位置开始查找,返回匹配substr的第一个字符的位置,找不到返回-1,第2个参数可选,默认从开头找
let str = 'Widget with id';

alert( str.indexOf('Widget') ); // 0
alert( str.indexOf('widget') ); // -1,没有找到,检索是大小写敏感的
alert( str.indexOf("id") ); // 1
alert( str.indexOf('id', 2) ) // 12
  1. 遍历所有位置:
let str = "As sly as a fox, as strong as an ox";
let target = "as";

//let pos = 0;
//while (true) {
//  let foundPos = str.indexOf(target, pos);
//  if (foundPos == -1) break;
//  alert( `Found at ${foundPos}` );
//  pos = foundPos + 1; // 继续从下一个位置查找
//}
//简单写法:
let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
  alert( pos );
}
//更简单
let pos = -1;
while (~(pos = str.indexOf(target, pos + 1))) {
  alert( pos );
}
//~是按位取反,~n 等于 -(n+1)
alert( ~1 ); // -2,和 -(1+1) 相同
alert( ~0 ); // -1,和 -(0+1) 相同
alert( ~-1 ); // 0,和 -(-1+1) 相同
//即当n为-1时,~-1为0,上面的案例中,while循环中pos!=-1时条件成立,假使pos==-1,也就是~pos==0,则pos!=-1可写成~pos!=0,因为0转换为布尔值是false,~pos的值不能为false,即~pos的值为true可循环,所以循环条件可改为while(~pos)
  1. str.lastIndexOf(substr, pos)以相反的顺序查找
  2. str.includes(substr, pos)根据 str 中是否包含 substr 来返回 true/false,第2个参数(开始搜索的位置)可选
  3. str.startsWith str.endsWith 同上,是否以指定字符串开头或结尾,返回值布尔类型
获取子字符串
  1. str.slice(start [, end])返回字符串从 start 到(但不包括)end 的部分。
let str = "stringify";
alert( str.slice(0, 5) ); // 'strin',从 0 到 5 的子字符串(不包括 5)
alert( str.slice(0, 1) ); // 's',从 0 到 1,但不包括 1,所以只有在 0 处的字符
alert( str.slice(2) ); // 从第二个位置直到结束
alert( str.slice(-4, -1) ); // 'gif' 从右边的第四个位置开始,在右边的第一个位置结束
  1. str.substring(start [, end])与slice的区别是,substring允许start大于end;substring不支持负参数,负参数被视作0。
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) ); // ""(空字符串)
  1. str.substr(start [, length]) 同slice和substring相比,substr指定从开始位置的具体长度,而不是指定结束位置,第一个参数是负数的话,从结尾算起。
let str = "stringify";
alert( str.substr(-4, 2) ); // 'gi',从第 4 位获取 2 个字符
比较字符串

JS中字符串都使用 UTF-16 编码,字符串的比较是根据字符在编码中对应的代码大小进行比较的。即:每个字符都有对应的数字代码。有特殊的方法可以获取代码表示的字符,以及字符对应的代码。

  1. str.codePointAt(pos)返回str中在pos位置的字符的代码
alert( "z".codePointAt(0) ); // 122
alert( "Z".codePointAt(0) ); // 90
  1. String.fromCodePoint(code)通过代码code查找对应的字符
alert( String.fromCodePoint(90) ); // Z
  1. str.localeCompare(str2) 会根据语言规则返回一个整数,这个整数能指示字符串 str 在排序顺序中排在字符串 str2 前面、后面、还是相同:
    - 如果 str 排在 str2 前面,则返回负数。
    - 如果 str 排在 str2 后面,则返回正数。
    - 如果它们在相同位置,则返回 0。