前言
本篇博客旨在清晰认识JS六种基础类型以及特征。
面试回答
基础类型:值类型有string、number、Boolean、undefined、null、Symbol。值类型是栈内存,占用空间固定,保存和复制的是值本身。一般我们用typeof去判断值类型,不过不能用来判断null,因为null在内存中属于引用类型,只不过因为方便效率所以归为值类型。至于typeof的检测原理,涉及信息储存和机器码的问题,就没有深入了。
知识点
基础类型都是栈(stack),简单理解一下,有两个特征:1. 保存和复制值的本身。2.占用空间固定, 栈内存中,由操作系统自动分配内存空间,自动释放。
1.Boolean
对于Boolean类型就一句话:undefined、null、""、0、NaN、false除了这6个值在js中属于假值,其他均为真值。
2.Undefined
定义
undefined 表示声明了变量但未对其初始化时赋予该变量值的返回值。
应用场景
1.返回undefined场景
//变量被声明了,但没有赋值时,返回undefined
let i ;
i //undefined
//调用函数时,应该提供的参数没有提供,该参数为undefined
function f(x){
console.log(x)
}
f()//undefined
//对象没有赋值的属性,该属性的值为undefined
let j = {}
j.p // undefined
//函数没有返回值时,默认返回undefined
let x = function z(){}
x //undefined
3.Null
定义
已定义,且表示"无"的值
对于null与undefined的异同可以从内存角度看:null在内存里属于引用类型,undefined在内存里属于基本类型。所以typeof null 的输出为Object,typeof undefined 的输出为undefined。之所以把null归为基本类型,是因为"效率"。当然,日常开发中,为了方便使用,将null理解为:声明并赋值的变量,该变量的值为null;将undefined理解为:声明变量,但没有赋值的返回值
4.Number
应用场景
1.精度问题
JavaScript 采用“IEEE 754 标准定义的双精度64位格式” ,所以会出现精度缺失的异常情况。
解决办法:
乘除法
//0.1+0.2 !== 0.3
let number = 0.1*10+0.2*10
let trueNumber = number/10 //0.3
toFixed(n):保留n位小数,不准确,且n不能过大。
//0.1+0.2!== 0.3。
let number = 0.1+0.2
let trueNumber = number.toFixed(2) //'0.30' string类型 ,
2.添加千分位
toLocaleString()
let num = 10000000 //输入必须是number类型
num.toLocaleString()
//"10,000,000" 输出的是字符串
当然复杂特殊的添加千分号就不满足了,需要自定义,思路如下:
1、统一处理为字符串:JSON.stringify(a)
2、切割整数和小数
3、将整数部分颠倒,方便插入","
4、for循环,每三位插入
5、将整数部分颠倒回原样,并加上小数部分
function transfor(data){
//1
if(typeof data === 'number'){
data = JSON.stringify(data)
}
//2、3
let integer = data.split('.')[0].split('').reverse()
let decimal = data.split('.')[1]
let num = ''
//4
for(let i=0;i
5.String
常用API
indexOf(): 返回字符串中指定文本首次出现的索引位置
split():根据参数将字符串分割,输出为数组
trim():去掉字符串两端的空格
replace() : 根据参数替换指定字符
toLowerCase():把字符串转换成小写
toUpperCase():把字符串转换成大写
parseInt() :把字符串转换成整数
parseFloat() :把字符串转换成数字
let str = " Hello World "
str.indexOf("o",6)//8
"o"表示要检索的字符串,6表示从哪里开始
str.split("o",1) // [' Hell']
"o"表示分割节点,1表示返回数组的最大长度
str.trim() //'Hello World'
str.replace("ell","ddd") // ' Hdddo World '
这边需要注意的是str本身的值不改变,相当于新建了一个对象
str.toUpperCase() //' HELLO WORLD '
str.toLowerCase() //' hello world '
parseInt('1010',2) //10
解析一个2进制的'1010'字符串并返回的十进制整数 ,2是对'1010'字符串是几进制的补充说明。
parseFloat('25.555') //25.555
6.Symbol
定义
"Symbol" ,表示唯一的标识符。
特点1:Symbol具有唯一性,即使用同一"描述"生成的值也不相等
特点2:Symbol具有隐藏性,这个特点使Symbol类型受到保护,防止被意外使用或重写,不过可以通过Object.getOwnPropertySymbols方法读取到
相关API
创建Symbol
Symbol():Symbol()定义的值不放入全局symbol注册表中,每次都是新建,即使描述相同值也不相等,即无法被Symbol.for()查询到对应的值,所以创建Symbol也推荐使用Symbol.for()创建,除非你不打算获取Symbol()的值。
//Symbol 保证是唯一的,即使两个描述相同的 Symbol 也是 不相等的
let sym1 = Symbol("id");
let sym2 = Symbol("id");
alert(id1 === id2); // false
查询Symbol的值
Symbol.for:接受一个"描述"作为参数,然后全局环境中搜索是否有以该参数注册的Symbol值。如果有,就返回这个Symbol值。没有就创建并返回一个以该字符串作为名称的Symbol值,并放入一个全局 symbol 注册表中。
let sym1 = Symbol.for("foo");
let sym2 = Symbol.for("foo");
sym1 === sym2; // true
查询Symbol的描述
Symbol.keyFor():接受一个"变量名"作为参数,返回一个 Symbol的"描述"
let sym1 = Symbol("des1")
let sym2 = Symbol("des2")
console.log(Symbol.keyFor(sym1)) // des1
console.log(Symbol.keyFor(sym2)) // des2
应用场景
1.替代常量 :保证常量的唯一性
const TYPE_MUSIC = Symbol.for("MUSIC")
const TYPE_MOVIE = Symbol.for("MOVIE")
const TYPE_IMG = Symbol.for("IMG")
function test(data){
switch(data.type){
case TYPE_MUSIC:
console.log('MUSIC')
break;
case TYPE_MOVIE:
console.log('MOVIE')
break;
case TYPE_IMG:
console.log('IMG')
break;
}
}
test({
type:Symbol.for("MUSIC")
})
代码里经常会使用常量来控制业务逻辑关系,如果常量少还比较好维护,但是常量一多,光是维护值得唯一性就是一项不小的工作。使用Symbol,可以保证常量的唯一性,也可以使代码相对优雅规范一些。
2.作为属性名或变量名,避免重名带来的问题;作为属性名,必须使用[]运算符来定义和获取;
const name = Symbol.for('name');
const obj = {
[name]: 'test',
}
console.log(obj[name]) //test
//注意:发送请求时,若对象中含有Symbol类型,不能作为参数,会报错
//且用Symbol作为key,取值时,必须使用[]进行取值,如上console
3.作为内置对象的特定方法的属性名,方便开发者对其重写,相当于定义类的私有属性/方法
const PASSWORD = Symbol.for('password')
class Login {
constructor(username, password) {
this.username = username
this[PASSWORD] = password
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login
//由于使用者无法在外部创建出一个相同的Symbol,所以就无法调用该参数
4.注意事项
对象的合并、覆盖、使用用JSON.stringify()
将对象转换成JSON字符串的时候,Symbol属性会被排除在输出内容之外;
for...in ,object.key()等方法访问不到;
不会被隐式转换,如alert等,非要显示需要在它上面调用toString()方法, Symbol("id").toString()
应用
1. || 、&&操作符的返回结果
我们经常根据某几个变量做if判断,如何确认判断结果是你想要的,可以使用下面这种方法:先确定返回结果,再根据"undefined、null、""、0、NaN、false除了这6个值在js中属于假值,其他均为真值",那么我们便需要知道基本数据类型及引用数据类型的操作符返回结果:
&&且运算符:
1.当结果为真时,返回最后一个真值
2.当结果为假时,返回第一个假值
||或运算符:
1.当结果为假时,返回最后一个假值
2.当结果为真时,返回第一个真值
判断逻辑:先去看&&,一假全假,返回第一个假
let a=(undefined&&123)||(3||5)&&0的返回值是什么?
由于&&0,所以在if判断中a必定为false,至于a的返回值是什么,需要判断(undefined&&123)||(3||5)是不是false
(undefined&&123)||(3||5)
其中(undefined&&123) 返回undefined
(3||5) 返回3
所以最终结果:3&&0 ,返回值为0
2.隐式类型转换
1.if判断
undefined、null、false、NaN、''、0除了这6个值在js中为假值,其他均为真值
2.加减乘除
加:转为字符串优先
1+2+'3' // '33'
'3'+2+null // '32null' ,多种数据类型算术:从左往右按照隐式类型转化的规则进行计算
1+undefined //NaN
'1a'+undefined //'1aundefine'
1+null // null,在数值加减时,会被转换成数字0
'1a'+null // 1anull
减乘除:转为number优先
'3'-2+'1' // '11'
'3'*2*null // 0
1*undefined //NaN
'1a'-undefined //NaN
1*null // 0
'1a'-null // NaN ,因为'1a'无法转化为数字
最后
走过路过,不要错过,点赞、收藏、评论三连~