为了便于操作基本类型值,ECMAScript还提供了三个特殊的引用类型:Boolean、Number、String。实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。
const s1 = 'some text'
const s2 = s1.substring(2)
// 其实,为了让我们实现这种直观的操作,后台已经自动完成了一些列的处理
/*
1. 创建String类型的一个实例
let s1 = new String('some text')
2. 在实例上调用指定的方法
let s2 = s1.substring(2)
3. 销毁这个实例
s1 = null
*/
经过此番处理,基本的字符串就变得和对象一样了。而且,上面着三个步骤也分别适用与Boolean和Number类型对应的布尔值和数字值
引用类型与基本类型的主要区别就是对象的生存期。基本包装类型的生命只存在于一行代码的执行瞬间,然后就会被销毁。这就意味着我们不能在运行时为基本类型值添加属性和方法。
let s1 = 'some text'
s1.color = 'cyan'
console.log(s1.color) // undefined
Object 构造函数也会项工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。
const obj = new Object('some text')
console.log(obj instanceof String) // true
需要注意的是,适用 new 基本调用包装类型的构造函数, 与直接调用同名的转型函数是不一样的。
let value = '25'
let number = Number(value) // 转型函数
console.log(typeof number) // 'number'
let obj = new Number(value) // 构造函数
console.log(typeof obj) // 'Object'
Boolean 类型
Boolean 类型是布尔值对应的引用类型。要创建Boolean对象,适用构造函数或者在布尔表达式中使用Boolean对象。
let falseObject = new Boolean(false)
console.log(falseObject && true) // true
let falseValue = false
console.log(falseValue && true) // false
如上,在布尔表达式中所有对象都会被转换为true,因此falseObject对象在布尔表达式中代表的是 true。结果, true && true = true
此外,他们之间还有两个区别
// 通过构造函数创建的实例,typeof是object,instanceof指向构造函数
console.log(typeof falseObject) // object
console.log(typeof falseValue) // boolean
console.log(falseObject instanceof Boolean) // true
console.log(falseValue instanceof Boolean) // false
Number类型
Number是与数字对应的引用类型,要创建Number对象,可以在调用Number构造函数时向其中传递相应的数值。
let numberObject = new Number(10)
与Boolean类型一样。,Number类型也重写了valueOf() 、toLocaleString() 和 toString() 方法。重写后的 valueOf() 返回对象表示的基本类型的数值。另外两个方法返回字符串形式的数值。此外,可以为toString() 方法传递一个表示基数的参数,告诉它返回几进制的数值
let num = 10
console.log(num.valueOf()) // 10
console.log(num.toString(2)) // '1010'
console.log(num.toString(8)) // '12'
console.log(num.toString(10)) // '10'
console.log(num.toString(16)) // 'a'
- toFixed()
这是Number类型中,很实用的一个方法。他按照指定的小数位返回数值的字符串
let num1 = 10
let num2 = 10.004
let num3 = 10.005
console.log(num1.toFixed(2)) // '10.00'
console.log(num2.toFixed(2)) // '10.00'
console.log(num3.toFixed(2)) // '10.01'
// 能够自动舍入的特性,使得 toFixed()方法很适合处理货币值。
// 但是需要注意的时,不同浏览器给这个方法设定的舍入规则可能不同。
另外可用于格式化数值的方法还有 toExponential(),改方法返回指数表示法(也称e表示法)。此外还有toPrecision()
与Boolean对象类似,Number对象也以后台方式为数值提供了重要的功能。但与此同时,我们仍然不建议直接实例化Number类型,原因与显式创建Boolean 对象一样
let numberObject = new Number(10)
let numberValue = 10
console.log(typeof numberObject ) // object
console.log(typeof numberValue ) // number
console.log(numberObject instanceof Number) // true
console.log(numberValue instanceof Number) // false
String类型
String类型是字符串的对象包装类型,可以使用下面这样使用String构造函数来创建
let stringObjject = new String('hello world')
String对象的方法也可以在所有基本的字符串中访问到。其中,继承的valueOf() 和 toLocaleString() 和 toString()方法,都返回对象所表示的字符串值。String类型的每个实例都包含length属性,表示字符串包含多少字符,即使字符串中包含多节字符(不是占一个字节的ASCII字符),每个字符也仍然算一个字符。
let str1 = 'Hello World'
let str2 = '你好!'
console.log(str1.length) // 11
console.log(str2.length) // 3
字符串方法
- 字符方法
- charAt() - 接收数值参数,返回字符串中对应位置的字符
- charCodeAt() - 接收数值参数,返回字符串中对应位置字符的编码
- 字符串操作方法
- concat() - 接收一个或多个字符串,将他们拼接起来,与数组concat类似
- slice() / subString() - 接受一或两个参数,返回被操纵后的字符串子串(包含指定开始,不包含结束)。
- 字符串位置方法
- indexOf() - 从当前字符串搜索给定的子字符串,然后返回子字符串的位置(没有则返回 -1)。
- lastIndexOf() - 与上面类型,唯一区别是从字符串的末尾开开始查找。
- trim() - 删除当前字符串 两边的空格。创建返回字符串副本
- 字符串大小写转换方法
- toLowerCase() - 转小写
- toLocaleLowerCase() - 转小写(对特定地区少数语言需要使用这个)
- toUpperCase() - 转大写
- toLocaleUpperCase() - 转大写 (对特定地区少数语言需要使用这个)
- 字符串的模式匹配方法
- match() - 接受一个正则表达式,或一个RegExp对象。与RegExp的exec()方法类似。
- search() - 接受正则或字符串,返回匹配到的索引,无匹配则返回-1
- replace() - 接受两个参数,第一个参数与search()一样,第二个参数为匹配后需要替换的字符串(或一个函数)。
- 如果是字符串,那么可以使用一些特殊的字符序列($$、$&...)
- 如果是函数
- 在只有一个匹配项的情况下接受三个参数:模式的匹配项、匹配项在字符串中的位置、原始字符串
- 在定义多个捕获组的情况下,接收:模式的匹配项、第一个捕获组的匹配项、第二个...、最后两个参数仍然分别是模式匹配项在字符串中的位置、原始字符串。
- split() - 接收一个指定的分隔符,将一个字符串分割成多个子字符串,并将结果存放在数组中(支持正则.低版本浏览器有差异)。
- localeCompare() - 比较两个字符串
- 如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多情况下是 -1, 具体的值要视实现而定)
- 如果字符串等于字符串参数,返回0
- 如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是1,具体的值同样要视实现而定)。
- fromCharCode()
- String的静态方法,与实例的charCodeAt相反,接收多个字符编码,返回一个对应的字符串。
- HTML方法
- 比如:link(url) - <a href=url>String</a>
- 避免使用,一是因为他们大多被废弃。其二即是他们创建的标记通常无法表达语义。
Global 对象
Global(全局)对象可以说是ECMAScript中最特别的一个对象了。可以说,不属于任何其他对象的属性和方法,最终都是它的属性和方法;所有在全局作用域中定义的属性和函数,都是Global对象的属性。诸如isNaN()、parseInt()...,除此之外,Global对象还包含其他一些方法。
URI编码方法 encodeURI()、encodeURIComponent()
Global 对象的 encodeURI() 和 encodeURIComponent()方法可以对URI(Uniform Resource Identifiers,通用资源标识符)进行编码,一边发送给浏览器。它们可以使用特殊的UTF-8编码替换所有无效的字符(比如空格),从而让浏览器能够接受理解。
const uri = 'http://www.wrox.com/illegal value.htm#start'
// http://www.wrox.com/illegal%20value.htm#start
console.log(encodeURI(uri))
//http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start
console.log(encodeURIComponent(uri))
两者的区别在于,encodeURI() 不会对本身属于URI的特殊字符进行编码,例如冒号、正斜杠、? 和 #;而encodeURIComponent() 则会对它发现的任何非标准字符进行编码。
解码 decodeURI() 、decodeURIComponent()
与上面两个方法对应的分别是,decodeURI() 和 decodeURIComponent()。其中decodeURI()只能对使用encodeURI()的字符进行解码。因为encodeURI()无法替换 # ? 等,所有对应的encodeURI也无法解析。如下:
const uri = 'http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start'
// http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start
console.log(decodeURI(uri))
// http://www.wrox.com/illegal value.htm#start
console.log(decodeURIComponent(uri))
- eval() 方法
eval() 大概是ECMAScript语言中最强大的一个方法了。eval()方法就相当于是一个完整的ECMAScript解析器,它只接受一个参数,即要执行的ECMAScript字符串
eval('alert("Hello World")')
// 等价于
alert("Hello World")
eval()执行的代码被认为是包含该次调用的执行环境的一部分,因此在被执行的代码具有与该环境相同的作用域链。这意味着通过eval()执行的代码可以引用在包含环境中定义的变量。
const msg = "today"
eval('console.log(msg)')
// 定义函数
eval(`
function sayHi() {
console.log('Hello World')
}
`)
// 调用函数
sayHi()
在eval()中创建的任何变量或函数都不会被提升。在严格模式下,外部访问不到eval()中创建的任何变量或函数,为eval() 赋值也会导致错误
'use strict'
eval = 'hi' // causes errpr
window对象
ECMAScript 虽然没有指出如何直接访问 Global 对象,但Web浏览器都是将这个全局对象作为window对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就成为了window对象的属性
var color = 'red'
function getColor() {
console.log(window.color)
}
window.getColor()
这里需要注意的是let、const声明的变量不会挂载在 window下
刚才查阅的过程中发现了一道有意思的面试题
let len = 10;
function fn() {
console.info(this.len)
}
fn(); // this执行window。 undefined
let Person = {
len: 5,
say: function() {
// 再次调用fn,this依然是window。
fn(); undefined
// 这里将 fn作为参数传入,变成了arguments的属性
// 但是arguments没有定义len这个属性,所有依然是 undefined
arguments[0](); // undefined
}
}
Person.say(fn);
Math对象
ECMAScript还未保存数学公式和信息提供了一个公共位置,即Math对象。与在JavaScript中直接编写的计算功能相比,Math对象提供的计算功能执行起来要快得多。Math对象中还提供了辅助完成这些计算数学和方法
Math对象的属性
Math对象包含的属性大都是数学计算中可能会用到的一些特殊值。
- Math.E - 自然对数的底数,即常量e的值
- Math.LN10 - 10的自然对数
- Math.LN2 - 2的自然对数
- Math.LOG2E - 以2为底e的对数
- Math.LOG10E - 以10为底e的对数
- Math.PI - π的值
- Math.SQRT1_2 - 1/2的平方根(即2的平方根的倒数)
- Math.SQRT2 - 2的平方根
min() 和 max() 方法
用于返回一组数中的最大值和最小值
let max = Math.max(3, 12, 9) // 12
let min = Math.min(2, 3, 5) // 2
// 找到数组中的最大(最小)值,可以这样使用
let arr = [1, 3, 5, 7, 9]
let arrMax = Math.max.apply(Math, arr)
console.log(arrMax ) // 9
舍入方法
- Math.ceil():向上取整
- Math.floor():向下取整
- Math.round():四舍五入取整
random() 方法
方法返回大于等于0小于1的一个随机数。套用下面的公式,就可以利用Math.random()从某个范围内随机选择一个值。
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能值)
let num = Math.floor(Math.random() * 10 + 1) // 1-10之间的整数
let num2 = Math.floor(Math.random() * 200 - 100) // -100 - 100
Math对象中还包含其他一些与完成各种简单或复杂计算有关的方法。
其他方法
小结:
- 引用类型与传统面向对象程序设计中的类相似,但实现不同。
- Object是一个基础类型,其他所有类型都从Object继承了基本的行为。
- Array 类型是一组值的有序列表,同时还提供操作转换这些值的功能。
- RegExp类型是ECMAScript支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能。
- 函数实际上是Function类型的实例,因此函数也是对象。
- 每个包装类型都映射到同名的基本类型
- 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据的操作。
- 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象
在所有代码执行之前,作用域中就已经存在两个内置对象:Global 和 Math。在大多数ECMAScript实现中都不能直接访问Global对象;不过,Web浏览器实现了承担该角色的window对象。全局变量和函数都是Global对象的属性。Math对象提供了很多属性和方法,用于辅助完成复杂的数学计算任务。
网友评论