JavaScript的原始类型并非对象类型,所以从理论上来说,它们是没有办法获取属性或者调用方法的。
但是,在开发中会看到,我们会经常这样操作:
var message = "hello world";
var words = message.split(" ");
var length = message.length;
var num = 2.5333;
num = num.toFixed(2)
那么,为什么会出现这样奇怪的现象呢?(悖论)
简单的值,默认并不能调用属性和方法;封装了对应的包装类型;常见的包装类型有:String、Number、Boolean、Symbol、BigInt类型
默认情况,当我们调用一个原始类型的属性或者方法时,会进行如下操作:
我们也可以自己来创建一个包装类的对象:
var name1 = "code!mq";
var name2 = new String("code!mq");
console.log(typeof name1);// string
console.log(typeof name2);// object
console.log(name1 === name2);// false
注意事项:null、undefined没有任何的方法,也没有对应的“对象包装类”;
前面我们已经学习了Number类型,它有一个对应的数字包装类型Number,我们来对它的方法做一些补充。
Number属性补充:
Number.MAX_SAFE_INTEGER:JavaScript 中最大的安全整数 (2^53 - 1);Number.MIN_SAFE_INTEGER:JavaScript 中最小的安全整数 -(2^53 - 1)Number实例方法补充:
toString(base),将数字转成字符串,并且按照base进制进行转化
// 对象的方法
// toString(base)
var num = 1000
console.log(num.toString(), typeof num.toString())
console.log(num.toString(2))
console.log(num.toString(8))
console.log(num.toString(16))
// console.log(123..toString(2))
toFixed(digits),格式化一个数字,保留digits位的小数;
// toFixed的使用(重要)
var pi = 3.1415926
console.log(pi.toFixed(3))
Number类方法补充:
Number.parseInt(string[, radix]),将字符串解析成整数,也有对应的全局方法parseInt;Number.parseFloat(string),将字符串解析成浮点数,也有对应的全局方法parseFloat;更多Number的知识,可以查看MDN文档:
// 类的方法
// parseInt
// parseFloat
// 整数: 123
// 浮点数: 小数 123.321
var num1 = "123.521"
console.log(Number(num1).toFixed(0))
console.log(Number.parseInt(num1))
console.log(Number.parseFloat(num1))
// window对象上面
console.log(parseInt(num1))
console.log(parseFloat(num1))
console.log(parseInt === Number.parseInt)// true
在除了Number类可以对数字进行处理之外,JavaScript还提供了一个Math对象。
内置对象(不是一个构造函数),它拥有一些数学常数属性和数学函数方法;Math常见的属性:
Math.PI:圆周率,约等于 3.14159;Math常见的方法:
//Math对象的属性
console.log(Math.PI)
//Math对象的方法
var num = 3.55
console.log(Math.floor(num)) // 3
console.log(Math.ceil(num)) // 4
console.log(Math.round(num)) // 4
// 另外方法
// random: 随机生成 [0, 1)
console.log(Math.random())
// 需求: [5~50)的随机数
// [a, b)
// y = a
// x = b - a
// Math.floor(Math.random() * x) + y
// Math.pow(x, y)
console.log(Math.pow(2, 4))
Math中还有很多其他数学相关的方法,可以查看MDN文档:
在开发中,我们经常需要对字符串进行各种各样的操作,String类提供给了我们对应的属性和方法。
String常见的属性:
length:获取字符串的长度;String也有很多常见的方法和操作,我们来进行学习。
var a = "hello world";
a.length;//11
操作一:访问字符串的字符
索引 str[0]str.charAt(pos)方法undefined,而charAt没有找到会返回空字符串;练习:字符串的遍历
// for普通遍历
for (var i = 0; i < message.length; i++) {
console.log(message[i])
}
// for..of的遍历 -> 迭代器
// 目前可迭代对象: 字符串/数组
// 对象是不支持for..of
// String对象内部是将字符串变成了一个可迭代对象
for (var char of message) {
console.log(char)
}
字符串的不可变性:
var message = "hello world";
message[1] = "a";
console.log(message);//hello world
所以,在我们改变很多字符串的操作中,都是生成了一个新的字符串;
toLowerCase():将所有的字符转成小写;toUpperCase() :将所有的字符转成大写;var message = "Hello World";
message[2] = "c";
console.log(message);
var upper = message.toUpperCase();
console.log(upper);
var lower = message.toLowerCase();
console.log(lower);
在开发中我们经常会在一个字符串中查找或者获取另外一个字符串,String提供了如下方法:
方法一:查找字符串位置 str.indexOf(searchValue [, fromIndex])
lastIndexOf,从最后开始查找(用的较少)var message = "Hello World";
var index = message.indexOf('o');
console.log(index);
console.log(message.indexOf("o", 6));
方法二:是否包含字符串 str.includes(searchString[, position])
console.log(message.includes("or"));
方法三:以xxx开头 str.startsWith(searchString[, position])
方法四:以xxx结尾 str.endsWith(searchString[, length])
方法五:替换字符串 str.replace(regexp|substr, newSubstr|function)
正则表达式来查找,也可以传入一个函数来替换;// 3.startsWith: 是否以xxx开头
// if (message.startsWith("my")) {
// console.log("message以my开头")
// }
// 4.endsWith: 是否以xxx结束
// if (message.endsWith("why")) {
// console.log("message以why结尾")
// }
// 5.replace 替换字符串
// var newMessage = message.replace("why", "kobe")
// console.log(message)
// console.log(newMessage)
var newName = "kobe"
var newMessage = message.replace("why", function() {
return newName.toUpperCase()
})
console.log(newMessage)
方法八:获取子字符串

var s1 = "Hello World";
var s2 = s1.slice(1, 5);
console.log(s1, s2);
方法六:拼接字符串 str.concat(str2, [, ...strN])
console.log("Hello".concat("World"));
方法七:删除首位空格 str.trim()
console.log(" coder!mq ".trim());
方法九:字符串分割 str.split([separator[, limit]])
正则表达式;var message = "my name is coder!mq";
console.log(message.split(" ", 3));// ['my', 'name', 'is']
更多的字符串的补充内容,可以查看MDN的文档:
什么是数组(Array)呢?
存储键值集合,但是在某些情况下使用键值对来访问并不方便;数组和对象都是一种保存多个数据的数据结构,在后续的数据结构中我们还会学习其他结构;
我们可以通过[]来创建一个数组:
对象类型;var letters = ['a', 'b', 'c'];
创建一个数组有两种语法:
// 方式一
var arr1 = [];
// 方式二
var arr2 = new Array();
下面的方法是在创建一个数组时,设置数组的长度(很少用)
var arr3 = new Array(5);
console.log(arr3);
数组元素从 0 开始编号(索引index)。
并不支持这种写法;我们先来学习一下数组的基本操作:
访问数组中的元素:
[]访问arr.at(i):
var arr = [2,5,3,1];
arr[0];
arr.at(-1);
修改数组中的元素
arr[0] = "coder!mq";
删除和添加元素虽然也可以通过索引来直接操作,但是开发中很少这样操作。
在数组的尾端添加或删除元素:
push 在末端添加元素.pop 从末端取出一个元素.arr.push("abc", "edf");
arr.pop();
在数组的首端添加或删除元素
shift 取出队列首端的一个元素,整个数组元素向前移动;unshift 在首端添加元素,整个其他数组元素向后移动;push/pop 方法运行的比较快,而 shift/unshift 比较慢。
如果我们希望在中间某个位置添加或者删除元素应该如何操作呢?
arr.splice 方法可以说是处理数组的利器,它可以做所有事情:添加,删除和替换元素。
arr.splice的语法结构如下:
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
var arr = [3, 4, 5, 1];
// 删除2个元素
arr.splice(1, 2);
console.log(arr);//[3, 1]
var arr2 = [5, 2, 1, 5, 6];
// 替换2个元素
arr2.splice(1, 2, 1, 2);
console.log(arr2);// [5, 1, 2, 5, 6]
// 新增2个元素
var arr3 = [3, 5, 8, 0];
arr3.splice(2, 0, 1, 3);//[3, 5, 1, 3, 8, 0]
console.log(arr3);
注意:这个方法会修改原数组
length属性用于获取数组的长度:
length 属性的另一个有意思的点是它是可写的。
var arr = [2, 5, 1];
arr.length = 1;
console.log(arr);//[2]
所以,清空数组最简单的方法就是:arr.length = 0;。
普通for循环遍历:
var arr = [5, 6, 8, 2, 5];
for (var index = 0; index < arr.length; index++) {
console.log(arr[index]);
}
for…in 遍历,获取到索引值:
for (var index in arr) {
console.log(arr[index]);
}
for…of 遍历,获取到每一个元素:
for (var value of arr) {
console.log(value);
}
arr.slice 方法:用于对数组进行截取(类似于字符串的slice方法)。
arr.slice([begin[,end]])
arr.slice(2, 3);
arr.concat方法:创建一个新数组,其中包含来自于其他数组和其他项的值。
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
var newArr = arr.concat(["abc", "edv"], "bdc");
arr.join方法: 将一个数组的所有元素连接成一个字符串并返回这个字符串。
arr.join([separator])
arr.join("-");
arr.indexOf方法: 查找某个元素的索引
arr.indexOf(searchElement[, fromIndex])
lastIndexOf 方法arr.includes方法:判断数组是否包含某个元素
arr.includes(valueToFind[, fromIndex])
find 和 findIndex 直接查找元素或者元素的索引(ES6之后新增的语法)
var students = [
{ id: 100, name: "why", age: 18 },
{ id: 101, name: "kobe", age: 30 },
{ id: 102, name: "james", age: 25 },
{ id: 103, name: "why", age: 22 }
]
var stu = students.find(functon(value, index, arr) {
if (value.age > 18) return true;
})
sort方法也是一个高阶函数,用于对数组进行排序,并且生成一个排序后的新数组:
arr.sort([compareFunction])
var newStus = students.sort(function(item1, item2) {
return item2.age - item1.age;
})
console.log(newStus);
等到后续讲解数据结构与算法时,我们会编写自己的排序算法:
reverse() 方法将数组中元素的位置颠倒,并返回该数组。
arr.forEach
arr.map
arr.filter
filter() 方法创建一个新数组;
新数组中只包含每个元素调用函数返回为true的元素;
arr.reduce
reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值;// 1.forEach函数
var names = ["abc", "cba", "nba", "mba"]
// 三种方式, 新增一种方式
names.forEach(function(item) {
console.log(item, this)
}, { name: "why" })
// 2.filter函数: 过滤
// var nums = [11, 20, 55, 100, 88, 32]
// 2.1. for循环实现
// var newNums = []
// for (var item of nums) {
// if (item % 2 === 0) {
// newNums.push(item)
// }
// }
// 2.2. filter实现
// var newNums = nums.filter(function(item) {
// return item % 2 === 0
// })
// console.log(newNums)
// 3.map函数: 映射
// var nums = [11, 20, 55, 100, 88, 32]
// var newNums = nums.map(function(item) {
// return item * item
// })
// console.log(newNums)
// 4.reduce
// var nums = [11, 20, 55, 100, 88, 32]
// var result = 0
// for (var item of nums) {
// result += item
// }
// console.log(result)
// 第一次执行: preValue->0 item->11
// 第二次执行: preValue->11 item->20
// 第三次执行: preValue->31 item->55
// 第四次执行: preValue->86 item->100
// 第五次执行: preValue->186 item->88
// 第六次执行: preValue->274 item->32
// 最后一次执行的时候 preValue + item, 它会作为reduce的返回值
// initialValue: 初始化值, 第一次执行的时候, 对应的preValue
// 如果initialValue没有传呢?
// var result = nums.reduce(function(preValue, item) {
// console.log(`preValue:${preValue} item:${item}`)
// return preValue + item
// }, 0)
// console.log(result)
// reduce练习
// var products = [
// { name: "鼠标", price: 88, count: 3 },
// { name: "键盘", price: 200, count: 2 },
// { name: "耳机", price: 9.9, count: 10 },
// ]
// var totalPrice = products.reduce(function(preValue, item) {
// return preValue + item.price * item.count
// }, 0)
// console.log(totalPrice)
// 综合练习:
var nums = [11, 20, 55, 100, 88, 32]
// 过滤所有的偶数, 映射所有偶数的平方, 并且计算他们的和
// var total = nums.filter(function(item) {
// return item % 2 === 0
// }).map(function(item) {
// return item * item
// }).reduce(function(preValue, item) {
// return preValue + item
// }, 0)
// console.log(total)
// var total = nums.filter(item => item % 2 === 0)
// .map(item => item * item)
// .reduce((preValue, item) => preValue + item, 0)
// console.log(total)
关于《时间》,有很多话题可以讨论:
《时间简史:从大爆炸到黑洞》,讲述的是关于宇宙的起源、命运;《记念刘和珍君》:时间永是流驶,街市依旧太平;《时间都去哪儿了》:时间都去哪儿了,还没好好感受年轻就老了;我们先来了解一下时间表示的基本概念:
最初,人们是通过观察太阳的位置来决定时间的,但是这种方式有一个最大的弊端就是不同区域位置大家使用的时间是不一致的。
之后,人们开始制定的标准时间是英国伦敦的皇家格林威治( Greenwich )天文台的标准时间(刚好在本初子午线经过的地方),这个时 间也称之为GMT(Greenwich Mean Time)。
但是,根据公转有一定的误差,也会造成GMT的时间会造成一定的误差,于是就提出了根据原子钟计算的标准时间UTC(Coordinated Universal Time)
目前GMT依然在使用,主要表示的是某个时区中的时间,而UTC是标准的时间。
在JavaScript中我们使用Date来表示和处理时间。
new Date();
new Date(value);
new Date(dateString);
new Date(year, monthIndex[, day [ hours [, minutes [, seconds [,milliseconds]]]]);
// 创建Date对象的方式
// 1.没有传入任何的参数, 获取到当前时间
var date1 = new Date()
console.log(date1)
// 2.传入参数: 时间字符串
var date2 = new Date("2022-08-08")
console.log(date2)
// 3.传入具体的年月日时分秒毫秒
var date3 = new Date(2033, 10, 10, 09, 08, 07, 333)
console.log(date3)
// 4.传入一个Unix时间戳
// 1s -> 1000ms
var date4 = new Date(10004343433)
console.log(date4)
这个格式是什么意思呢?
日期的表示方式有两种:RFC 2822 标准 或者 ISO 8601 标准。
默认打印的时间格式是RFC 2822标准的:

我们也可以将其转化成ISO 8601标准的:
YYYY:年份,0000 ~ 9999MM:月份,01 ~ 12DD:日,01 ~ 31T:分隔日期和时间,没有特殊含义,可以省略HH:小时,00 ~ 24mm:分钟,00 ~ 59ss:秒,00 ~ 59.sss:毫秒Z:时区console.log(date)
console.log(date.toDateString())
console.log(date.toISOString())
我们可以从Date对象中获取各种详细的信息:
getFullYear():获取年份(4 位数);getMonth():获取月份,从 0 到 11;getDate():获取当月的具体日期,从 1 到 31(方法名字有点迷);getHours():获取小时;getMinutes():获取分钟;getSeconds():获取秒钟;getMilliseconds():获取毫秒;获取某周中的星期几:
getDay():获取一周中的第几天,从 0(星期日)到 6(星期六);Date也有对应的设置方法:
了解:我们可以设置超范围的数值,它会自动校准。
// 也可以给date设置时间(了解)
date.setFullYear(2033)
// 自动校验
date.setDate(32)
console.log(date)
Unix 时间戳:它是一个整数值,表示自1970年1月1日00:00:00 UTC以来的毫秒数。
在JavaScript中,我们有多种方法可以获取这个时间戳:
获取到Unix时间戳之后,我们可以利用它来测试代码的性能:
// 计算这个操作所花费的时间
var startTime = Date.now()
for (var i = 0; i < 100000; i++) {
console.log(i)
}
var endTime = Date.now()
console.log("执行100000次for循环的打印所消耗的时间:", endTime - startTime)
// 封装一个简单函数
function testPerformance(fn) {
var startTime = Date.now()
fn()
var endTime = Date.now()
}
Date.parse(str) 方法可以从一个字符串中读取日期,并且输出对应的Unix时间戳。
Date.parse(str) :
NaN;var time1 = Date.parse("2022-08-08T08:08:08.666Z");
console.log(time1);
详见【JavaScript高级】