JavaScript学习笔记(二)

本文详细介绍了JavaScript中原始类型(如数字、字符串)的方法,包括数字的科学记数法、特殊进制、舍入运算,字符串的转义、长度计算、子串操作、转换等。此外,还深入讲解了数组的创建、常用方法如push/pop、splice/slice/concat、遍历及转换技巧,以及数组特有的find/findIndex、filter和reduce功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

15 数据类型

15.0 原始类型的方法

在JavaScript中,诸如字符串、数字等原始类型也有其方法。对原始类型调用方法时,看起来似乎是直接对原始类型调用的方法,其实不然。因为原始类型不是对象,所以并没有方法,只有对象才有方法。JavaScript引擎会先从这些原始类型中创建一个可实现的对象,然后调用对象的方法,最后销毁这个对象。这样就实现了对原始类型调用方法。

15.1 数字类型

数字中的e

在实际运用中,如果我们想令一个变量等于十亿。一般情况下,我们可以这样写:

let number = 1000000000;

但这样写我们需要连续输入好多个0,过于繁琐,。这时,JavaScript提供了一种全新的方式。

let number = 1e9;  // 也是十亿

其中,e 后面的正数代表前面数字后 0 的个数。

同理,e 也可以表示小数:

let number = 1.2e-2;  // 等价于0.012

其中,e 后面的负数代表小数点后几位。

特殊的进制数字

0x为十六进制数字的前缀,常用来表示颜色;

0b为二进制数字的前缀;

0o为八进制数字的前缀;

toString(base)方法

该方法需要传入一个参数base,用于将源数字转换为base进制的数字:

let number = 255;

alert( number.toString(16) );  // 转换成16进制 ff
alert( number.toString(2) );  // 转换成2进制 11111111

使用两个点来调试方法

alert( 255..toString(16) );

如果使用一个 . ,JavaScript会认为其是一个小数点而非方法调用操作符。因此使用需要使用两个点。第一个 . 代表小数点,后面是空的代表小数部分为0。第二个 . 为方法调用操作符,代表调用number对象的toString(base)方法。也可以写成如下形式:

alert( (255).toString(16) );

使用括号包裹同样也可以解决此问题。

舍入

Math.floor()

向下取整,

3.1 => 3;

3.7 => 3;

-1.1 => -2;

-1.6 => -2;

Math.ceil()

向上取整,

3.1 => 4;

3.7 => 4;

-1.1 => -1;

-1.6 => -1;

Math.round()

就近取整,

3.1 => 3;

3.7 => 4;

-1.1 => -1;

-1.6 => -2;

Math.trunc() IE浏览器不支持

抹去小数点后的数字

3.1 => 3;

3.7 => 3;

-1.1 => -1;

-1.6 => -2;

总结
Math.floor()Math.ceil()Math.round()Math.trunc()
3.13433
3.73443
-1.1-2-1-1-1
-1.6-2-1-2-1

将数字舍入到小数点后n位:

eg:将1.234舍入到小数点后一位

1.先给数字乘以10的幂次,再调用上面的舍入函数。

alert( Math.floor( (1.23456 * 100) ) / 100 );  // 1.23456 => 123.456 => 123 => 1.23

2.使用函数toFixed(n)将数字保留到小数点后n位,但返回的是字符串

let num = 1.23456;

alert( num.toFixed(2) );  // 1.23

toFixed(n)函数类似于Math.round()函数,为就近舍入。

不精确的计算

在JavaScript内部,数字是以 64 位格式 IEEE-754 表示的,所以正好有 64 位可以存储一个数字:其中 52 位被用于存储这些数字,其中 11 位用于存储小数点的位置(对于整数,它们为零),而 1 位用于符号。

如果一个数字太大,就会导致溢出,其值为Infinity:

alert( 1e500 );  // Infinity

但常遇到的往往是精度损失,会出现下面这样神奇的情况:

alert( 0.1 + 0.2 == 0.3 );  // false

这是因为采用二进制计数时,只有2的整数次幂才是整数,其他均为无限小数。所以

0.1 + 0.2 实质为0.30000000000000004,的确不等于 0.3。

为避免这一问题,我们最好在有浮点数参与运算时使用toFixed(n)函数设置其保留位数:

alert( +(0.1 + 0.2).toFixed(2) == 0.3 );  // true,+将其转换为数字类型

isNaN()和isFinite()

isNaN()函数可以判断被检测的对象是否是NaN,它会先将源对象转换为number类型,再进行判断。

可是我们为什么需要这个函数?用 源对象 == NaN 判断不可以吗?

事实上,NaN与其他任何东西都不相等,包括其自身:

alert( NaN == NaN );  // false

因此,判断源对象是否为NaN类型,只能使用isNaN()函数。

isFinite()函数可以判断源对象是否为正常的数字,它会先将源对象转换为number类型,再进行判断。

如果是普通的数字,则返回true;如果是Infinity,NaN,undefined等特殊的形式,则返回false。

正如前文中所提到的,空字符和只带有空格的字符会被转换为0,因此会返回true。 

parseInt()和parseFloat()

对于普通的字符串,使用 + 或Number()可以将其强制转换为number类型,但如果字符串中带有字符,则会出现错误。

在实际运用过程中,常常有这样的形式:CSS中常见的"100px",商品价格常见的“100元”。

这时,就需要用到parseInt()和parseFloat()

它们可以将字符串转换为number类型的数字,如果遇到错误,则返回之前转换的结果。

parseInt()返回整数,而parseFloat()返回浮点数:

alert( parseInt("100px") );  // 100,遇到"p"时发生错误,停止转换并返回100
alert( parseFloat("200元") );  // 200,遇到"元"时发生错误,停止转换并返回200

alert( parseFloat("8.5元") );  // 8 遇到"."时发生错误,停止转换并返回8
alert( parseFloat("8.5元") );  // 8.5 遇到"元"是发生错误,停止转换并返回8.5

其他数学函数

JavaScript中有一个Math对象,里面存放了一些常用的数学函数和常量,例如:

Math.random( )可以返回一个在 [0, 1) 区间内的随机数

Math.max( ) /Math.min( ) 可以返回序列中的最大值/最小值

Math.pow(x, n) 可以计算 x 的 n 次幂

需要时可以翻阅Math对象的说明查看

15.2 字符串类型

反引号允许字符串跨行,单引号和双引号不允许。

let test = `
This
is
a
test.
`;

字符串长度

字符串对象的length属性表示字符串的长度:

alert( "test".length );  // 4

特别注意length为字符串的属性,而不是函数,所以后面没有 ()

访问字符

类似Python,要访问位于 pos 的字符,可以使用方括号 [ ]

let test = 'test';

alert( test[0] );  // t

如果下标越界,则返回undefined

let test = 'test';

alert( test[4] );  // undefined

字符串是不可变的

通常的解决方法是将改变后的字符串赋值给新的变量。

大小写转换

字符串对象方法:toLowercase() 和 toUppercase()可以将字符串变为小写或大写。

let test1 = 'test';
let test2 = 'TEST';

alert( test1.toUpperCase() );  // TEST
alert(test2.toLowerCase() );  // test

查找字符串

字符串对象方法:str.indexOf(target, position)

target为要查找的字符串对象,position是可选的起始位置,不传入默认从头开始。如果找到该字符串,则返回该字符串第一次出现的位置;如果未找到该字符串,则返回-1。

let test = 'This is a test.';

alert( test.indexOf("is") );  // 2 查找到"This"中的"is",返回2
alert( test.indexOf("is", 4) );  // 5 从" "开始,查找到"is",返回5
alert( test.indexOf("no") );  // -1 未找到,返回-1

由于未找到字符串时返回-1,在配合if语句使用时可以进行简写:

let test = "This is a test.";

if( test.indexOf("is") != -1 ) {
    alert("Found it!");
}

可以简写为:

let test = "This is a test.";

if(~test.indexOf("is")) {
    alert("Found it!");
}

这是因为 ~ 是按位取反运算符,它将数字转换为32bit整数,然后按位取反。

最终效果为:~n = -(n+1)

因此,当结果为 -1 时,按位取反结果为 -(-1+1) = 0 刚好为 false。

但不建议这样使用。

现代方法

现代字符串方法:str.includes(substr, pos)

可以根据字符串中有无包含substr字符串来相应的返回true和false。同样,pos可以指定开始匹配位置。

let test = "This is a test.";

alert(test.includes("te"));  // true

现代字符串方法:str.starsWith(substr)

可以根据字符串开头有无包含substr字符串来返回true和false。

let test = "This is a test.";

alert(test.startsWith("Th"));  // true

现代字符串方法:str.endsWith(substr)

可以根据字符串结尾有无包含substr字符串来返回true和false。

let test = "This is a test.";

alert(test.endsWith("st."));  // true

获取子字符串

str.slice(star[, end]) 方法

同Python的字符串切片,返回star和end之间的字符串。同样为左闭右开区间,即[star, end)。

如果没有传入end参数,则会返回从star到字符串结尾的字符串。

star和end参数同样也可以为负值。

let test = "This is a test.";

alert(test.slice(0, 4));  // "This"

str.substring(star[, end]) 方法

与slice几乎相同,但支持star > end,不支持star和end为负值。

let test = "This is a test.";

alert(test.substring(0, 4)); // "This"
alert(test.substring(4, 0)); // "This"

str.substr(star[, length]) 方法

返回从star开始,长度为length的字符串

let test = "This is a test.";

alert(test.substr(0, 7));  // "This is"
总结
str.slice(star[, end])返回从star到end之间的字符串,star和end可以为负值
str.substring(star[, end])返回从star到end之间的字符串,star可以大于end,但star和end不能为负值
str.substr(star[, length])返回从star开始,长度为length的字符串

字符串转换

字符串对象方法:str.codePointAt(pos)可以返回pos位置字符的unicode编码

let test = "This is a test.";

alert(test.codePointAt(0) );  // "T" 84

函数:String.fromCodepoint(code)可以将unicode编码转化为字符:

alert( String.fromCodePoint(84) );  // T

15.3 数组

JavaScript中的数组可以存储任何类型的变量,可以是数字类型、字符串类型、甚至函数,其本质是一种对象。

创建数组非常简单:

let array = new Array();  // 从构造器创建
let array = [];  // 绝大多数情况下采用此方法创建

数组方法

JavaScript中的数组既可以当做队列使用,也可以当做栈来使用。

push() 方法

向数组末尾添加一个元素

let array = [];

array.push("test");

alert(array);  // test

pop() 方法

取出数组末尾最后一个元素

let array = [1, 2, 3, 4];

alert(array.pop());  // 4
alert(array);  // 1, 2, 3

shift() 方法

取出数组首段第一个元素

let array = [1, 2, 3, 4];

alert(array.shift());  // 1
alert(array);  // 2, 3, 4

unshift() 方法

在数组首段添加元素

let array = [];

array.unshift(0);

alert(array);  // 0 

值得注意的是,push() 和 unshift() 方法都可以一次性添加多个元素:

let array = [];

array.unshift(0, 1, 2);

alert(array);  // 0, 1, 2

array = [];

array.push(0, 1, 2);

alert(array);  // 0, 1, 2

在性能上,push() 和 pop() 方法运行的速度比较快,而shift() 和 unshift() 方法运行的比较慢

因为在首端进行操作需要对数组进行重新编号,大大减慢了运行速度。

splice() 方法

splice()方法的泛用性较强,可以用来删除、添加和替换元素,其语法规则如下:

arr.splice(start[, deleteCount, elem1, ..., elemN])

 表示:从数组的start下标的元素开始计数,将其后deleteCount个元素替换为eleme1, ..., elemN

因此,将deleteCount设置为1,eleme1, ..., elemeN设置为空即可实现删除操作。

let array = ["This", "is", "a", "test"];

array.splice(0, 0, "test")  // 在下标为0处添加test元素

alert( array );  // test,This,is,a,test

 被添加的元素个数大于deleteCount即可实现添加操作。

let array = ["This", "is", "a", "test"];

array.splice(0, 0, "test")  // 在下标为0处添加test元素

alert( array );  // test,This,is,a,test

只需要使替换元素的个数大于deleteCount即可实现添加元素: 

let array = ["This", "is", "a", "test"];

array.splice(0, 1)  // 从下标为0处开始计数,将一个元素替换为空,等价于删除下标为0的元素

alert( array );  // is,a,test

该方法同样支持负向索引。

slice() 方法

slice() 方法是splice的简化版,语法如下:

arr.slice([start], [end])

表示将该数组的start到end之间的元素复制到一个新数组中并返回该数组,注意为左闭右开区间

let array = ["This", "is", "a", "test"];

let new_array = array.slice(1, 4);  // 左闭右开区间

alert( new_array );  // is,a,test

 该方法同样支持负向索引。

concat() 方法

concat() 方法可以进行数组的复制,其语法如下:

arr.concat(arg1, arg2...)

 该方法会按先后顺序复制括号内的参数,将其连接到源数组的后方,最后返回新数组:

let array = ["This", "is"];

let new_array = array.concat(["a", "test"]);  // 将a, test连接到array后方

alert( new_array );  // This,is,a,test

forEach() 方法

该方法可以为数组中的每一个元素执行一个函数操作,其语法如下:

arr.forEach(function(item, index, array) {
  // ... do something with item
});

例如:

// 对每个元素调用 alert
["Bilbo", "Gandalf", "Nazgul"].forEach(alert);

循环

因为数组是一种特殊的对象,所以从理论上来说可以使用对象的for...in...循环,但一般不在数组中使用,因为for...in...不仅仅会遍历到数组中的元素,还会遍历到其属性。

因此,数组一般使用类似的for...of...循环:

let fruits = ["Apple", "Banana", "Orange"];

for (let fruit of fruits) {
    alert(fruit);  // 依次显示Apple, Banana, Orange
}

当然,类似C语言式的遍历也是可行的。 

关于length

数组的length属性是可以被修改的。手动增加length的数值,什么都不会发什么。

但手动减小length的数值,数组会被截断。所以,清空数组最简单的方法就是array.length = 0。

多维数组也同样适用

不要使用==比较数组

如果使用==来比较数组,其过程和==比较对象的过程相同。

搜索

和字符串一样,数组也能使用arr.indexOf/lastindexOf和arr.includes方法,作用也同字符串相同。

需要注意的是,这些方法使用的比较为严格比较,即 === ,在比较时不进行类型转换。

find和findindex

在实际使用中,数组中可能存储对象,这是就需要用到find函数,其语法规则如下:

let result = arr.find(function(item, index, array) {
  // 如果返回 true,则返回 item 并停止迭代
  // 对于假值(falsy)的情况,则返回 undefined
});

例如,我们想要找到 id==1 的用户:

let users = [{
        id: 1,
        name: 'LiMing'
    },
    {
        id: 2,
        name: 'XiaoGang'
    },
    {
        id: 3,
        name: 'LiHua'
    },
]

let user = users.find(item => item.id == 2);

alert(user.name); // XiaoGang

arr.findIndex方法和arr.find方法基本相同,但它返回被找到元素的索引,未找到时返回 -1

filter方法

与arr.find方法类似,但它返回所有满足条件的对象所组成的数组,其语法规则如下:

let results = arr.filter(function(item, index, array) {
  // 如果 true item 被 push 到 results,迭代继续
  // 如果什么都没找到,则返回空数组
});

例如:

let users = [{
        id: 1,
        name: 'LiMing'
    },
    {
        id: 2,
        name: 'XiaoGang'
    },
    {
        id: 3,
        name: 'LiHua'
    },
]

let some_users = users.filter(item => item.id < 3);  // 找到所有id小于3的对象

alert(some_users.length); // 2

转换数组

map

它会对数组中的每一个元素都执行一个函数,其语法规则如下:

let result = arr.map(function(item, index, array) {
  // 返回新值而不是当前元素
})

例如:

let users = ['LiMing', 'LiHua', 'XiaoGang'];

let lengths = users.map(item => item.length);  // 将数组中的元素转换为其长度

alert(lengths);  // 6 5 8

sort

sort函数可以对数组进行原地排序,它会改变原来的数组。默认情况下,其按字符串顺序排序,但可以传入函数,按照函数返回值的大小来进行排序。这样就可以实现自定义排序内容。

let numbers = [2, 15, 3];

numbers.sort();  // 默认按字符串顺序排序

alert(numbers);  // 15 2 3
let numbers = [2, 15, 3];

function compareNumberic(a, b) {
    if (a > b) return 1;
    if (a == b) return 0;
    if (a < b) return -1;
}

numbers.sort(compareNumberic);  // 按数字大小进行比较

alert(numbers); // 2 3 15

比较函数还可以进行简写:

let numbers = [2, 15, 3];

numbers.sort((a, b) => a - b);

alert(numbers); // 2 3 15

reverse

reverse方法可以颠倒数组中元素的顺序:

let numbers = [2, 15, 3];

numbers.reverse();

alert(numbers); // 3 15 2

spilt和join

同Python,这里不再赘述。

reduce

reduce方法也可以遍历数组,不同与for...of的是,它可以使用数组前一位调用的结果,其语法规则如下:

let value = arr.reduce(function(accumulator, item, index, array) {
  // ...
}, [initial]);

其中,accumulator为上一次的调用后的值,item, index, array的意思同之前,initial代表初始值。

例如:

let numbers = [1, 2, 3];

let result = numbers.reduce((sum, item) => sum + item, 0); // 实现数组的累加

alert(result);  // 6

建议总是设定初始值,否则在数组为空时会出现错误。

判断是否是数组

数组是基于对象的,因此使用typeof运算符或typeof()函数均不能将数组和对象区分开:

alert(typeof {});  // object
alert(typeof []);  // object

使用Array.isArray()方法可以判断:

alert(Array.isArray([]));  // true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值