Javascript高级之数据类型
数据类型
typeof操作符
- 对一个值使用typeof操作符会返回下列字符串之一
undefined
表示值已定义,未赋值boolean
表示值为布尔值string
表示值为字符串number
表示值为数值object
表示值为对象(不是函数)或nullfunction
表示值为函数symbol
表示值为符号
let message= 'some string';
console.log(typeof message); // string
console.log(typeof(message)); // string
console.log(typeof(null)); // object
数据类型检测
- 数据类型的检测方法
Object.prototype.toString.call()
全类型检测instanceof Array[,Function,Date,RegExp,Object]
只能检测对象类型typeof
只能检测除null外的值类型- 常用于
(typeof value == "string") ? "'" + value + "'" : value;
- 常用于
Array.isArray()
仅只检测Array类型isFinite()
用于检测数值是否在安全范围之内isNaN()
用于检测数据是否为空valueOf()
用于返回对象的原始数值
let value= '9';
console.log((typeof value == "string") ? "'" + value + "'" : value);
数据类型的初始化
- 定义一个空对象
let obj= null;
console.log(typeof obj);
- 定义一个空函数
let fun= Function.prototype;
console.log(typeof fun);
- 定义一个空数组
let arr= [];
console.log(Array.isArray(arr));
- 定义一个空字符串
let str= '';
console.log(typeof str);
- 定义一个空符号
let sym= Symbol();
console.log(typeof sym);
强制类型转换
- 强制类型转换
- 任意类型 --> 字符串
x.toString()
- x不能是undefined或nullString(x)
- 相当于隐式转换
- 任意类型 --> 数字
Number(x)
- 专用于将非字符串类型转数字,相当于隐式转换parseInt(str)
- 将字符串转为整型数字,不认识小数点,碰上第一个非数字字符就停止,自动跳过开头的空字符parseFloat(str)
- 将字符串转为浮点型数字,认识第一个小数点
- 任意类型 --> Boolean
Boolean(x)
- 相当于隐式转换- 只有5个值转为false - "" NaN undefined null 0,其余都转为true
- 快速转换
- 任意类型转String -
x + ""
- 任意类型转Boolean -
!!x
- 任意类型转Number - 除”+”以外的其他运算
- 任意类型转String -
- 任意类型 --> 字符串
// Number(x) VS parseInt(str)
let b = true;
console.log(Number(b)); //1
console.log(parseInt(String(b))); //NaN
let width="60px";
console.log(Number(width)); //NaN
console.log(parseInt(width)); //60
// 十进制转十六进制
let num1 = 125;
console.log(num1.toString(16)); //输出7d
console.log(num1.toString(8)); // 输出175
// 十六进制转十进制
let num2 = '7d';
console.log(parseInt(num2,16)); //输出125
// 十进制转十六进制
let array = [170, 15, 19, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 218];
let newArray = array.map(item =>{
return item.toString(16);
});
console.log(newArray);
// 十六进制转十进制
let arr1 = ["aa", "f", "13", "0", "0", "0", "0", "0", "0", "2", "1", "1", "0", "0", "0", "da"];
let arr2 = arr1.map(item =>{
return parseInt(item,16);
})
console.log(arr2);
转换成字符串类型
toString()
let num = 5;
console.log(num.toString());
String()
- String()函数存在的意义:有些值没有toString()
- 这个时候可以使用String()。比如:undefined和null
let s = null;
console.log(s.toString());
console.log(String(s));
- 拼接字符串方式
num + ""
- 当+两边一个操作符是字符串类型,一个操作符是其它类型的时候
- 会先把其它类型转换成字符串再进行字符串拼接,返回字符串
转换成数值类型
Number()
- Number()可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回NaN
let a = Number('1');
let b = Number(1);
let c = Number('c');
let d = Number(null);
let e = Number(undefined);
console.log(a,b,c,d,e); // 1 1 NaN 0 NaN
parseInt()
- 如果第一个字符是数字会解析,直到遇到非数字结束
- 如果第一个字符不是数字或者符号就返回NaN
let a = parseInt('1.2df');
let b = parseInt(1);
let c = parseInt('c12');
let d = parseInt(null);
let e = parseInt(undefined);
console.log(a,b,c,d,e); //1 1 NaN NaN NaN
parseFloat()
- parseFloat() 把字符串转换成浮点数
- parseFloat()和parseInt非常相似
- 不同之处在与parseFloat会解析第一个 . 遇到第二个.或者非数字结束
- 如果解析的内容里只有整数,解析成整数
let a = parseFloat('1.2df');
let b = parseFloat('1.3.4');
let c = parseFloat('c12');
let d = parseFloat(null);
let e = parseFloat(undefined);
console.log(a,b,c,d,e); //1.2 1.3 NaN NaN NaN
+ - -0
等运算
let str = '500';
console.log(+str); // 取正
console.log(-str); // 取负
console.log(str - 0);
转换成布尔类型
Boolean()
- 0、''(空字符串) 、null、 undefined 、NaN 会转换成false 其它都会转换成true
let a = Boolean('0');
let b = Boolean(0);
let c = Boolean('1');
let d = Boolean(null);
let e = Boolean(undefined);
let f = Boolean(NaN);
console.log(a,b,c,d,e,f); //true false true false false false
undefined类型
- 概念
- undefined类型只有一个值,就是特殊值undefined
- 对于未声明的变量,只能执行一个有用的操作,就是对它调用typeof
- 永远不要显式的将变量值设置为undefined
let message;
console.log(message); // undefined
console.log(age); // 报错
console.log(typeof message); // undefined
console.log(typeof age); // undefined
if(message){
console.log('1号程序执行了'); // 不执行
}
if(!message){
console.log('2号程序执行了'); // 执行
}
if(age){
console.log('3号程序执行了'); // 报错
}
Null类型
- 概念
- null类型只有一个值,就是特殊值null
- 逻辑上来讲,null值表示一个空对象指针
- 在定义将来要保存的对象值变量时,建议使用null来初始化
- undefined值是由null值派生而来的
console.log(undefined==null); // true
let message= null;
if(message){
console.log('1号程序执行了'); // 不执行
}
if(!message){
console.log('2号程序执行了'); // 执行
}
Boolean类型
-
概念
- 布尔值字面量区分大小写
- 其他类型的值可以转化为布尔值
-
不同类型与布尔值之间的转换规则
- 转换为true的值
- 非空字符串
- 非零数值(包括无穷值)
- 任意对象
- N/A(不存在)
- 转化为false的值
- ""(空字符串)
- 0、NaN
- null
- undefined
- 转换为true的值
let message='你好,中国!';
if(message){
console.log(message);
}
Number类型
- 概念
- 使用八进制和十六进制格式创建的数值在所有的数学操作中都被视为十进制数值
- 八进制
- 前缀添加0
- 若字面量超出范围,则当成十进制数
- 十六进制
- 前缀添加0x(区分大小写)
- 十六进制数字中的字母不区分大小写
- 正零和负零在所有情况下都认定为等同的
浮点数
- 概念
- 对于非常大或非常小的数值,浮点数可以用科学计数法来表示
- 浮点值的精确度最高可达17位小数,但在算术计算中远不如整数精确
let num1= 3.14e5;
console.log(num1); // 314000
console.log(0.1+0.2); // 0.30000000000000004
值得范围
- 概念
- JS的下限值保存在
Number.MIN_VALUE
- JS的上限值保存在
Number.MAX_VALUE
- 超出范围,返回Infinity
- 检测数据是否在范围之内
isFinite()
- JS的下限值保存在
// JS最小数值
console.log(Number.MIN_VALUE);
// JS最大数值
console.log(Number.MAX_VALUE);
console.log(Number.MAX_VALUE*2); // Infinity
console.log(isFinite(Number.MAX_VALUE)); // true
console.log(isFinite(Number.MAX_VALUE*2)); // false
NaN
- 概念
- NaN表示不是数值
- 用于表示本来要返回数值的操作失败了
- NaN不等于任何值,包括自己
- 检测数据是否为空
isNaN()
console.log(0/0); // NaN
console.log(5/0); // Infinity
console.log(NaN == NaN); // false
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false
console.log(isNaN('10')); // false
console.log(isNaN('blue')); // true
console.log(isNaN(true)); // false
String类型
- 概念
- 字符串可以用双引号(")单引号(')反引号(`)标示
字符字面量
- 字面量
\n
换行\t
制表\b
退格\r
回车\f
换页\\
反斜杠\'
单引号\"
双引号- ``` 反引号
\xnn
以十六进制编码nn表示的字符\unnnn
以十六进制编码nnnn表示的Unicode字符
字符串的特点
- 字符串是不可变的
模板字面量
let strTemp1= '你好,中国!\n我的祖国!';
console.log(strTemp1);
let strTemp2= `你好,中国!
我的祖国!`;
console.log(strTemp2);
字符串插值
-
概念
- 模板字面量最常用的一个特性是支持字符串插值
- 字符换插值通过在${}中使用一个Javascript表达式实现
- 所有插入的值都会使用toString()强制转型为字符串
- 任何Javascript表达式都可以用于插值
-
嵌套的模板字符串无须转义
console.log(`Hello,${`world`}!`);
- 将表达式转换为字符串时会调用toString()
let foo= {toString: ()=>'world'};
console.log(`Hello,${foo}!`);
- 在插值表达式中可以调用函数和方法
function capitalize(word){
return `${word[0].toUpperCase()}${word.slice(1)}`;
}
console.log(`${capitalize('hello')},${capitalize('world')}!`);
- 模板可以插入自己之前的值
let value= '';
function append(){
value= `${value}哈哈!`;
console.log(value);
}
append();
append();
append();
模板字面量标签函数
- 概念
- 标签函数会接收被插值记号分隔后的模板和对每个表达式求值的结果
- 因为表达式参数的数量是可变的,所以通常应该使用剩余操作符将它们收集到一个数组中
let a= 18;
let b= 27;
function simpleTag(strings, a, b, sum){
console.log(strings);
console.log(a);
console.log(b);
console.log(sum);
return 'over';
}
let res= `${a}+${b}=${a+b}`;
let resTag= simpleTag`${a}+${b}=${a+b}`;
console.log(res);
console.log(resTag);
let a= 18;
let b= 27;
function simpleTag(strings, ...exps){
console.log(strings);
console.log(exps);
let arr= exps.map(item=>{
return item;
})
console.log(arr);
for(exp of exps){
console.log(exp);
}
return 'over';
}
let resTag= simpleTag`${a}+${b}=${a+b}`;
console.log(resTag);
let a= 18;
let b= 27;
function simpleTag(strings, ...exps){
return strings[0]+ exps.map((e, i)=>`${e}${strings[i+1]}`).join('');
}
let resTag= simpleTag`${a}+${b}=${a+b}`;
console.log(resTag);
原始字符串
- 概念
- 使用模板字面量可以直接获取原始的模板字面量内容
- 可以通过标签函数的第一个参数,即字符串数组的.raw属性取得每个字符串的原始内容
console.log(`\u00A9`);
console.log(String.raw`\u00A9`);
function printRaw(strings){
console.log('模板字面量:');
for(const string of strings){
console.log(string);
}
console.log('原始字面量:');
for(const stringRaw of strings.raw){
console.log(stringRaw);
}
}
printRaw`\u00A9${'and'}\n`;
Symbol类型
- 概念
- 符号是原始值,且符号实例是唯一、不可变的
- 符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险
符号的基本用法
- 概念
- 符号需要使用Symbol()函数初始化
- Symbol()函数不能与new关键字一起作为构造函数使用
let sym= Symbol();
console.log(typeof sym);
let genericSymbol= Symbol();
let otherGenericSymbol= Symbol();
console.log(genericSymbol== otherGenericSymbol); // false
let fooSymbol= Symbol('foo');
let otherFooSymbol= Symbol('foo');
console.log(fooSymbol== otherFooSymbol); // false
使用全局符号注册表
-
概念
- 如果运行时的不同部分需要共享和重用符号实例
- 可以用一个字符串作为键,在全局符号注册表中创建并重用符号
-
Symbol.for()
方法- 对每个字符串键都执行幂等操作
- 全局注册表中的符号必须使用字符串键来创建
- 注册表中使用的键同时也会被用作符号描述
let fooGlobalSymbol= Symbol.for('foo');
let otherGlobalFooSymbol= Symbol.for('foo');
console.log(fooGlobalSymbol=== otherGlobalFooSymbol); // true
let emptyGlobalSymbol= Symbol.for();
console.log(emptyGlobalSymbol); // Symbol(undefined)
Symbol.keyFor()
方法- 查询全局注册表
- 接受符号,返回该全局符号对应的字符串键
- 如果查询的不是全局符号,则返回undefined
let s= Symbol.for('foo');
console.log(Symbol.keyFor(s)); // foo
let s= Symbol('foo');
console.log(Symbol.keyFor(s)); // undefined
使用符号作为属性
- 概念
- 凡是可以使用字符串或数值作为属性的地方,都可以使用符号
- 包括对象字面量属性和
Object.defineProperty()
Object.defineProperties()
定义的属性 - 对象字面量只能在计算属性语法中使用符号作为属性
let s1= Symbol('Sunny'),
s2= Symbol('Jerry'),
s3= Symbol('Marry'),
s4= Symbol('Tommy');
let o= {
[s1]: 'programmer'
};
console.log(o); // {Symbol(Sunny): "programmer"}
Object.defineProperty(o, s2, {value: 'Photographer'});
console.log(o);
Object.defineProperties(o, {
[s3]: {value: 'Designer'},
[s4]: {value: 'Operation'}
});
console.log(o);
常用内置符号
- 概念
- ES6引入了一批常用内置符号,用于暴露语言的内部行为
- 开发者可以直接访问、重写或模拟这些行为
- 这些内置符号都以Symbol工厂函数字符串属性的形式存在
- 所有内置符号属性都是不可写、不可枚举、不可配置的
- 在ES规范中,经常引用符号在规范中的名称,前缀为@@
@@iterator
指的就是Symbol.iterator
Symbol.asyncIterator
- 概念
- 这个符号作为一个属性表示
- 一个方法,该方法返回对象默认的
AsyncIterator
- 由
for-await-of
语句使用
- 一个方法,该方法返回对象默认的
- 这个符号表示实现异步迭代器API的函数
- 返回的对象是实现该API的
AsyncGenerator
- 返回的对象是实现该API的
- 这个符号作为一个属性表示
class Foo{
async *[Symbol.asyncIterator](){}
}
let f= new Foo();
console.log(f[Symbol.asyncIterator]()); // AsyncGenerator {<suspended>}
class Emitter{
constructor(max){
this.max= max;
this.asyncIdx= 0;
}
async *[Symbol.asyncIterator](){
while(this.asyncIdx < this.max){
yield new Promise((resolve)=>resolve(this.asyncIdx++));
}
}
}
async function asyncCount(){
let emitter= new Emitter(5);
for await(const x of emitter){
console.log(x);
}
}
asyncCount();
Object类型
-
概念
- 对象就是一组数据和功能的集合
-
每个Object实例都有如下的属性和方法
constructor
用于创建当前对象的函数hasOwnProperty(propertyName)
用于判断当前对象实例(不是原型)上是否存在给定的属性isPrototypeOf(object)
用于判断当前对象是否为另一个对象的原型propertyIsEnumerable(propertyName)
用于判断给定的属性是否可以使用for-in语句枚举toLocaleString()
返回对象的字符串表示,该字符串反映对象所在的本地化执行环境toString()
返回对象的字符串表示valueOf()
返回对象对应的字符串、数值或布尔值表示,通常与toString()的返回值相同