对象和原始类型的区别
- 原始类型的值
- 是原始类型中的一种值。
- 在 JavaScript 中有 7 种原始类型:
string
,number
,bigint
,boolean
,symbol
,null
和undefined
。
- 对象
- 能够存储多个值作为属性。
- 可以使用大括号
{}
创建对象,例如:{name: "John", age: 30}
。JavaScript 中还有其他种类的对象,例如函数就是对象。
1 2 3 4 5 6 7 8 |
let john = { name: "John", sayHi: function() { alert("Hi buddy!"); } }; john.sayHi(); // Hi buddy! |
当作对象的原始类型
- 原始类型仍然是原始的。与预期相同,提供单个值
- JavaScript 允许访问字符串,数字,布尔值和 symbol 的方法和属性。
- 为了使它们起作用,创建了提供额外功能的特殊“对象包装器”,使用后即被销毁。
- “对象包装器”对于每种原始类型都是不同的,它们被称为
String
、Number
、Boolean
和Symbol
。因此,它们提供了不同的方法。
1 2 3 |
let str = "Hello"; alert( str.toUpperCase() ); // HELLO |
上述代码中实际发生的情况:
- 字符串
str
是一个原始值。因此,在访问其属性时,会创建一个包含字符串字面值的特殊对象,并且具有有用的方法,例如toUpperCase()
。 - 该方法运行并返回一个新的字符串(由
alert
显示)。 - 特殊对象被销毁,只留下原始值
str
。 - JavaScript 引擎高度优化了这个过程。它甚至可能跳过创建额外的对象。但是它仍然必须遵守规范,并且表现得好像它创建了一样。
1 2 3 4 5 |
// 数字有其自己的方法 let n = 1.23456; alert( n.toFixed(2) ); // 1.23 |
数字类型
- JavaScript 中的常规数字以 64 位的格式 IEEE-754 存储,也被称为“双精度浮点数”。
- BigInt 数字,用于表示任意长度的整数。有时会需要它们,因为常规数字不能超过
2^53
或小于-2^53
。
1 2 3 |
let billion = 1e9; // 10 亿,字面意思:数字 1 后面跟 9 个 0 alert( 7.3e9 ); // 73 亿(7,300,000,000) |
1 |
let ms = 1e-6; // 1 的左边有 6 个 0 |
1 2 |
alert( 0xff ); // 255 alert( 0xFF ); // 255(一样,大小写没影响) |
1 2 3 4 |
let a = 0b11111111; // 二进制形式的 255 let b = 0o377; // 八进制形式的 255 alert( a == b ); // true,两边是相同的数字,都是 255 |
toString
- 方法
num.toString(base)
返回在给定base
进制数字系统中num
的字符串表示形式。
1 2 3 4 |
let num = 255; alert( num.toString(16) ); // ff alert( num.toString(2) ); // 11111111 |
- 可以使用两个点在数字上调用方法
1 |
123456..toString(36) //进制转换 |
舍入
- Math.floor
- 向下舍入
- Math.ceil
- 向上舍入
- Math.round
- 就近整数舍入
- Math.trunc
- 移除小数点后的所有内容而没有舍入
- IE浏览器不支持这个方法
- toFixed(n)
- 将数字舍入到小数点后
n
位,并以字符串形式返回结果。
- 将数字舍入到小数点后
不精确的计算
在内部,数字是以 64 位格式 IEEE-754 表示的,所以正好有 64 位可以存储一个数字:其中 52 位被用于存储这些数字,其中 11 位用于存储小数点的位置(对于整数,它们为零),而 1 位用于符号。
1 2 3 4 5 |
alert( 1e500 ); // Infinity alert( 0.1 + 0.2 == 0.3 ); // false alert( 0.1 + 0.2 ); // 0.30000000000000004 |
但为什么会这样呢?
一个数字以其二进制的形式存储在内存中,一个 1 和 0 的序列。但是在十进制数字系统中看起来很简单的 0.1
,0.2
这样的小数,实际上在二进制形式中是无限循环小数。
换句话说,什么是 0.1
?0.1
就是 1
除以 10
,1/10
,即十分之一。在十进制数字系统中,这样的数字表示起来很容易。将其与三分之一进行比较:1/3
。三分之一变成了无限循环小数 0.33333(3)
。
isFinite和isNaN
Infinity
(和-Infinity
)是一个特殊的数值,比任何数值都大(小)。NaN
代表一个 error。- 它们属于
number
类型,但不是“普通”数字 isFinite(value)
将其参数转换为数字,如果是常规数字,则返回true
,而不是NaN/Infinity/-Infinity
1 2 3 4 5 6 7 8 |
alert( isNaN(NaN) ); // true alert( isNaN("str") ); // true alert( NaN === NaN ); // false alert( isFinite("15") ); // true alert( isFinite("str") ); // false,因为是一个特殊的值:NaN alert( isFinite(Infinity) ); // false,因为是一个特殊的值:Infinity |
parseInt和parseFloat
使用加号 +
或 Number()
的数字转换是严格的。如果一个值不完全是一个数字,就会失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
alert( +"100px" ); // NaN 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) ); // 255 alert( parseInt('ff', 16) ); // 255,没有 0x 仍然有效 alert( parseInt('2n9c', 36) ); // 123456 |
数学函数
- Math.random()
- 返回一个从 0 到 1 的随机数(不包括 1)
- Math.max(a, b, c...) / Math.min(a, b, c...)
- 从任意数量的参数中返回最大/最小值
- Math.pow(n, power)
- 返回
n
的给定(power)次幂
- 返回
字符串
- 字符串可以包含在单引号、双引号或反引号中
1 2 3 4 |
let single = 'single-quoted'; let double = "double-quoted"; let backticks = `backticks`; |
- 单引号和双引号基本相同。但是,反引号允许我们通过
\${…}
将任何表达式嵌入到字符串中
1 2 3 4 5 |
function sum(a, b) { return a + b; } alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3. |
- 使用反引号的另一个优点是它们允许字符串跨行
1 2 3 4 5 6 7 |
let guestList = `Guests: * John * Pete * Mary `; alert(guestList); // 客人清单,多行 |
- 字符串长度
1 |
alert( `My\n`.length ); // 3 |
- 访问字符
1 2 3 4 5 6 7 8 |
let str = `Hello`; // 第一个字符 alert( str[0] ); // H alert( str.charAt(0) ); // H // 最后一个字符 alert( str[str.length - 1] ); // o |
- 在 JavaScript 中,字符串不可更改。改变字符是不可能的
- 大小写
1 2 3 4 |
alert( 'Interface'.toUpperCase() ); // INTERFACE alert( 'Interface'.toLowerCase() ); // interface alert( 'Interface'[0].toLowerCase() ); // 'i' |
- 查找子字符串
1 2 3 4 5 6 7 8 9 10 |
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) let str = 'Widget with id'; alert( str.indexOf('id', 2) ) // 12 |
- includes,startsWith,endsWith
1 2 3 4 5 6 7 8 9 |
alert( "Widget with id".includes("Widget") ); // true alert( "Hello".includes("Bye") ); // false alert( "Midget".includes("id") ); // true alert( "Midget".includes("id", 3) ); // false, 从位置 3 开始没有 "id" alert( "Widget".startsWith("Wid") ); // true,"Widget" 以 "Wid" 开始 alert( "Widget".endsWith("get") ); // true,"Widget" 以 "get" 结束 |
- JavaScript 中有三种获取字符串的方法:
substring
、substr
和slice
。
1 2 3 4 5 6 7 8 9 10 11 |
let str = "stringify"; alert( str.slice(0, 5) ); // 'strin',从 0 到 5 的子字符串(不包括 5) alert( str.slice(0, 1) ); // 's',从 0 到 1,但不包括 1,所以只有在 0 处的字符 let str = "stringify"; alert( str.slice(2) ); // 从第二个位置直到结束 let str = "stringify"; // 从右边的第四个位置开始,在右边的第一个位置结束 alert( str.slice(-4, -1) ); // 'gif' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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) ); // ""(空字符串) ```javascript let str = "stringify"; alert( str.substr(2, 4) ); // 'ring',从位置 2 开始,获取 4 个字符 let str = "stringify"; alert( str.substr(-4, 2) ); // 'gi',从第 4 位获取 2 个字符 |
- 比较字符串
1 2 3 |
alert( 'a' > 'Z' ); // true alert( 'Österreich' > 'Zealand' ); // true |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 不同的字母有不同的代码 alert( "z".codePointAt(0) ); // 122 alert( "Z".codePointAt(0) ); // 90 alert( String.fromCodePoint(90) ); // Z // 在十六进制系统中 90 为 5a alert( '\u005a' ); // Z let str = ''; for (let i = 65; i <= 220; i++) { str += String.fromCodePoint(i); } alert( str ); // ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ // ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ |
数组
声明
1 2 |
let arr = new Array(); let arr = []; |
1 |
let fruits = ["Apple", "Orange", "Plum"]; |
1 2 3 4 5 6 7 8 9 |
let fruits = ["Apple", "Orange", "Plum"]; alert( fruits[0] ); // Apple alert( fruits[1] ); // Orange alert( fruits[2] ); // Plum fruits[2] = 'Pear'; // 现在变成了 ["Apple", "Orange", "Pear"] fruits[3] = 'Lemon'; // 现在变成 ["Apple", "Orange", "Pear", "Lemon"] |
1 2 3 |
let fruits = ["Apple", "Orange", "Plum"]; alert( fruits.length ); // 3 |
1 2 3 4 5 6 7 8 |
// 混合值 let arr = [ 'Apple', { name: 'John' }, true, function() { alert('hello'); } ]; // 获取索引为 1 的对象然后显示它的 name alert( arr[1].name ); // John // 获取索引为 3 的函数并执行 arr[3](); // hello |
at
1 2 3 4 |
let fruits = ["Apple", "Orange", "Plum"]; // 与 fruits[fruits.length-1] 相同 alert( fruits.at(-1) ); // Plum |
pop
1 2 3 4 5 |
let fruits = ["Apple", "Orange", "Pear"]; alert( fruits.pop() ); // 移除 "Pear" 然后 alert 显示出来 alert( fruits ); // Apple, Orange |
push
- 可以一次添加多个元素
1 2 3 4 5 |
let fruits = ["Apple", "Orange"]; fruits.push("Pear"); alert( fruits ); // Apple, Orange, Pear |
shift
1 2 3 4 5 |
let fruits = ["Apple", "Orange", "Pear"]; alert( fruits.shift() ); // 移除 Apple 然后 alert 显示出来 alert( fruits ); // Orange, Pear |
unshift
- 可以一次添加多个元素
1 2 3 4 5 |
let fruits = ["Orange", "Pear"]; fruits.unshift('Apple'); alert( fruits ); // Apple, Orange, Pear |
性能
push/pop
方法运行的比较快,而shift/unshift
比较慢
遍历
1 2 3 4 5 |
let arr = ["Apple", "Orange", "Pear"]; for (let i = 0; i < arr.length; i++) { alert( arr[i] ); } |
1 2 3 4 5 6 |
let fruits = ["Apple", "Orange", "Plum"]; // 遍历数组元素 for (let fruit of fruits) { alert( fruit ); } |
1 2 3 4 5 |
let arr = ["Apple", "Orange", "Pear"]; for (let key in arr) { alert( arr[key] ); // Apple, Orange, Pear } |
for .. in
遍历数组,会有潜在问题- 会遍历 所有属性,不仅仅是这些数字属性
- 循环适用于普通对象,并且做了对应的优化
length
- 实际上不是数组里元素的个数,而是最大的数字索引值加一
splice
- 删除元素
1 2 3 4 5 |
let arr = ["I", "study", "JavaScript"]; arr.splice(1, 1); // 从索引 1 开始删除 1 个元素 alert( arr ); // ["I", "JavaScript"] |
1 2 3 4 5 6 |
let arr = ["I", "study", "JavaScript", "right", "now"]; // 删除数组的前三项,并使用其他内容代替它们 arr.splice(0, 3, "Let's", "dance"); alert( arr ) // 现在 ["Let's", "dance", "right", "now"] |
slice
- 将所有从索引
start
到end
(不包括end
)的数组项复制到一个新的数组
1 2 3 4 5 |
let arr = ["t", "e", "s", "t"]; alert( arr.slice(1, 3) ); // e,s(复制从位置 1 到位置 3 的元素) alert( arr.slice(-2) ); // s,t(复制从位置 -2 到尾端的元素) |
concat
- 创建一个新数组,其中包含来自于其他数组和其他项的值
1 2 3 4 5 6 7 8 9 10 |
let arr = [1, 2]; // 从 arr 和 [3,4] 创建一个新数组 alert( arr.concat([3, 4]) ); // 1,2,3,4 // 从 arr、[3,4] 和 [5,6] 创建一个新数组 alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 // 从 arr、[3,4]、5 和 6 创建一个新数组 alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6 |
forEach
1 2 3 |
["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => { alert(<code>${item} is at index ${index} in ${array}</code>); }); |
indexOf
indexOf lastIndexOf includes
1 2 3 4 5 6 7 |
let arr = [1, 0, false]; alert( arr.indexOf(0) ); // 1 alert( arr.indexOf(false) ); // 2 alert( arr.indexOf(null) ); // -1 alert( arr.includes(1) ); // true |
1 2 3 4 |
let fruits = ['Apple', 'Orange', 'Apple']; alert( fruits.indexOf('Apple') ); // 0(第一个 Apple) alert( fruits.lastIndexOf('Apple') ); // 2(最后一个 Apple) |
1 2 3 |
const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1(错,应该为 0) alert( arr.includes(NaN) );// true(正确) |
find
find findIndex findLastIndex
1 2 3 4 5 6 7 8 9 |
let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"} ]; let user = users.find(item => item.id == 1); alert(user.name); // John |
1 2 3 4 5 6 7 8 9 10 11 12 |
let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"}, {id: 4, name: "John"} ]; // 寻找第一个 John 的索引 alert(users.findIndex(user => user.name == 'John')); // 0 // 寻找最后一个 John 的索引 alert(users.findLastIndex(user => user.name == 'John')); // 3 |
filter
1 2 3 4 5 6 7 8 9 10 |
let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"} ]; // 返回前两个用户的数组 let someUsers = users.filter(item => item.id < 3); alert(someUsers.length); // 2 |
map
- 对数组的每个元素都调用函数,并返回结果数组
1 2 |
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length); alert(lengths); // 5,7,6 |
sort
- 默认情况下按字符串排序
1 2 3 4 5 6 |
let arr = [ 1, 2, 15 ]; // 该方法重新排列 arr 的内容 arr.sort(); alert( arr ); // 1, 15, 2 |
reverse
1 2 3 4 |
let arr = [1, 2, 3, 4, 5]; arr.reverse(); alert( arr ); // 5,4,3,2,1 |
split join
1 2 3 4 5 6 7 |
let names = 'Bilbo, Gandalf, Nazgul'; let arr = names.split(', '); for (let name of arr) { alert( <code>A message to ${name}.</code> ); // A message to Bilbo(和其他名字) } |
1 2 3 |
let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2); alert(arr); // Bilbo, Gandalf |
1 2 3 |
let str = "test"; alert( str.split('') ); // t,e,s,t |
1 2 3 4 5 |
let arr = ['Bilbo', 'Gandalf', 'Nazgul']; let str = arr.join(';'); // 使用分号 ; 将数组粘合成字符串 alert( str ); // Bilbo;Gandalf;Nazgul |
1 2 3 4 5 |
let arr = [1, 2, 3, 4, 5]; let result = arr.reduce((sum, current) => sum + current, 0); alert(result); // 15 |
isArray
1 2 |
alert(typeof {}); // object alert(typeof []); // object(相同) |
1 2 3 |
alert(Array.isArray({})); // false alert(Array.isArray([])); // true |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!