一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
前言
ECMAScript有6种简单(原始)数据类型:Undefined、Null、Boolean、Number、String 和 Symbol(符号);一种复杂数据类型Object。Object是一种无序名值对的集合。
typeof 操作符可以用来确定变量的数据类型。对一个值使用typeof操作符的返回结果:
- undefined:表示值未定义
- boolean: 表示值为布尔值
- string: 表示值为字符串
- number:表示值为数值
- object:表示值为对象(而不是函数)或 null
- function:表示值为函数
- symbol :表示值为符号
undefined 类型
undefined 类型只有一个特殊值就是undefined,当使用var 或者 let 声明了变量但没有初始化时,(const 在声明时就必须初始化赋值)就相当于给变量赋予了undefined值;let message; console.log(message == undefined); // true
注意: 未初始化或者为未声明的变量调用typeof 来判断数据类型后, 最后返回的结果类型都是undefined;
let message; // 这个变量被声明了,只是值为 undefined
// 确保没有声明过这个变量
// let age
console.log(typeof message); // "undefined"
console.log(typeof age); // "undefined"
//俩个变量一个声明了,一个没有声明,但是对于typeof 来执行判断时都无实际执行的操作。
Null 类型
Null 类型同样只有一个特殊值null。逻辑上讲,null 值表示一个空对象指针,这也是给typeof 传一个null 会返回 object 的原因。let car = null; console.log(typeof car); // "object"不必显示的定义一个变量为undefined,但是需要定一个暂时没有值的对象为null;
Boolean 类型
有俩个字面量true 和 false。这俩个布尔值不同于数值,因此true 不等于1,false 不等于0。布尔值的字面量是区分大小写的,如果是True 和False 则不是布尔值,是操作符内容。
- 可以使用转型函数Boolean()
let message = "Hello world!";
let messageAsBoolean = Boolean(message);
console.log(messageAsBoolean); //true
let message = " ";
let messageAsBoolean = Boolean(message);
console.log(messageAsBoolean); //false
- 转换类型表格
| 数据类型 | 转换为true值 | 转换为false值 |
|---|---|---|
| Boolean | true | false |
| String | 非空字符串 | ""(空字符串) |
| Number | 非零数值(包括无穷值) | 0、NaN |
| Object | 任意对象 | null |
| Undefined | N/A(不存在) | undefined |
Number 类型
不同的数值类型,相应的也有不同的数字字面量的格式,最基本的是10进制整数;
let intNum = 55; // 整数
let octalNum1 = 070; // 八进制的 56
let octalNum2 = 079; // 无效的八进制值,当成 79 处理
let octalNum3 = 08; // 无效的八进制值,当成 8 处理
let hexNum1 = 0xA; // 十六进制 10
let hexNum2 = 0x1f; // 十六进制 31
正零(+0)和 负零(-0)在所有情况下都是被认为是等同的,这里特地的说明一下。
浮点值
数值中必须包含小数点,而且小数点后面必须有一个非零的数字
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐
let floatNum1 = 1.; // 小数点后面没有数字,当成整数 1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数 10 处理
// 浮点数相加之后的的数据,会存在一点数据的差异
0.05 + 0.25 = 0.3; // true
0.15 + 0.15 = 0.3; // true
0.1 + 0.2 = 0.3; // false 0.30000000000000004
说明:浮点值的精确度最高可达 17 位小数,但在算术计算中远不如整数精确。
值的范围
-
最小值:Number.MIN_VALUE,5e-324
-
最大值:Number.MAX_VALUE,1.797 693 134 862 315 7e+308
-
当超出最大范围或者最小范围之后,值就会被转换成一个负无穷(-Infinity)/正无穷(+Infinity)
- 当一个值为正无穷或者负无穷之后,这个值就不能被用于计算
- 可以使用isFinite() 函数来判断数值是否是无穷大,也可以理解为是否为一个有限数值(finite number)
let result = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(isFinite(result)); // false
let num = 3;
console.log(isFinite(num)); //true
let num1 = 3 + Number.MAX_VALUE;
console.log(isFinite(num1)); //true
let num2 = 3 + Number.MIN_VALUE;
console.log(isFinite(num2)); //true
let num3 = Number.MIN_VALUE + Number.MIN_VALUE;
console.log(isFinite(num3)); //true
NaN(Not a Number)不是数值
用于表示本来要返回的数值的操作失败了(而不是抛出错误)
console.log(0/0); // NaN
console.log(-0/+0); // NaN
// 数学中的0不能做除数(0不能除以任意数)
//如果分子是非 0 值,分母是有符号 0 或无符号 0,则会返回 Infinity 或-Infinity
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
- 属性
-
任何和NaN的操作始终会返回NaN(如:NaN /10)
-
NaN 和任何值都不想等,包括NaN 本身(如:console.log(NaN == NaN); // false)
-
isNaN()函数:接受任意类型的参数,判断是否是数值;会尝试将参数转化为数值,不能转化为数字的内容就会输出false。
-
isNaN()可以用于测试对象,,,先调用valueof()方法,如果不能返回确定返回的值是否是数值,会再次调用toString() 方法,并测试其中的返回值。
console.log(isNaN(NaN)); // true console.log(isNaN(10)); // false,10 是数值 console.log(isNaN("10")); // false,可以转换为数值 10 console.log(isNaN("blue")); // true,不可以转换为数值 console.log(isNaN(true)); // false,可以转换为数值 1 -
数值转换
将非数值转换为数值:Number()、parseInt() 和parseFloat();Number()可以转换任何类型的数据,后俩个主要是将字符串转换为数值。
Number()规则
-
布尔值,true 转换为 1,false 转换为 0。
-
数值,直接返回。
-
null,返回 0。
-
undefined,返回 NaN。
-
字符串,应用以下规则
- 如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。 因此,Number("1")返回 1,Number("123")返回 123,Number("011")返回 11(忽略前面 的零)。
- 如果字符串包含有效的浮点值格式如"1.1",则会转换为相应的浮点值(同样,忽略前面的零)。
- 如果字符串包含有效的十六进制格式如"0xf",则会转换为与该十六进制值对应的十进制整 数值。
- 如果是空字符串(不包含字符),则返回 0。
- 如果字符串包含除上述情况之外的其他字符,则返回 NaN。
-
对象,调用 valueOf()方法,并按照上述规则转换返回的值。如果转换结果是 NaN,则调用 toString()方法,再按照转换字符串的规则转换。
parseInt()规则
在使用字符串转换得到整数时可以优先使用parseInt()函数;
- 从第一个非空字符串开始转换,如果第一个不是数值字符、加号或者减号,parseInt() 立即返回NaN
console.log(parseInt(' 123')); //123
console.log(parseInt(' +123')); //123
console.log(parseInt(' -123')); //-123
console.log(parseInt(' ')); //NaN
console.log(Number('')); // 0
console.log(parseInt('hello'));//NaN
console.log(parseInt('好'));//NaN
console.log(parseInt('hello22.5'));//NaN
- 如果第一个时数字字符、加号或者减号,则继续依次检测每个字符,知道结束或者碰到非数值字符
console.log(parseInt(' 好'));//NaN
console.log(parseInt(' 123好'));//123
console.log(parseInt('123blue'));//123
console.log(parseInt('22.5'));//22
console.log(parseInt(22.5));//22
console.log(parseInt('hello22.5'));//NaN
- 第一个是数字,会转换为对应的整数格式(十进制、八进制、十六进制)
console.log(parseInt("1234blue")); // 1234
console.log(parseInt("")); // NaN
console.log(parseInt("0xA")); // 10,解console.log(parseInt(22.5)); // 22
console.log(parseInt("70")); // 70,解释为十进制值
console.log(parseInt("0xf")); // 15,解释为十六进制整数
// 在非严格模式下,有时候会转换成8进制数
console.log(parseInt("o8")); // NaN 严格模式
//parseInt()也接收第二个参数,用于指定底数(进制数)
console.log(parseInt("0xAF", 16)) //175
//如果提供了十六进制参数,那么字符串前面的"0x"可以省掉
console.log(parseInt("AF", 16)) //175
console.log(parseInt("AF")) //175
parseFloat()规则
- 从0开始,当检测到无效的浮点数或者末尾结束
- 始终忽略开头的0,且不能指定转换为几进制数,因为只解析和转换10进制数
- 16进制的数,始终被转换为0
console.log(parseFloat("1234blue")) // 1234,按整数解析
console.log(parseFloat("0xA")) //0
console.log(parseFloat("22.5")) //22.5
console.log(parseFloat("22.34.5")) //22.34
console.log(parseFloat("0908.5")) //908.5
console.log(parseFloat("3.125e7")) //31250000
String类型
String(字符串) 类型 数据表示多个0 或者多个16位 Unicode 字符序列,字符串可以使用双引号(“”)、单引号(‘’)、反引号( `` )标示。
let firstName = "John";
let lastName = 'Jacob';
let lastName = `Jingleheimerschmidt`
//可以使用 length属性 获取字符串的长度
let text = " ";console.log(text.length); // 1
let text1 = ".";console.log(text1.length); //1
let text2 = "你";console.log(text2.length); // 1
let text2 = "你 ";console.log(text2.length); // 2
转换为 String 类型的方法
- 使用toString() 方法;返回当前值的字符串等价物
let age = 11;
let ageAsString = age.toString(); // 字符串"11"
let found = true;
let foundAsString = found.toString(); // 字符串"true"
// null 和 undefined 值没有toString() 方法;
// toString 可以接受底数的参数,用来指定输出字符串的类型
let num = 10;
console.log(num.toString()); // "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"
-
String() 转型函数,他始终会返回表示相应类型值的字符串
- 如果值有toString() 方法,则调用该方法(不传参数)并返回结果。
- 如果值是null,返回”null“ (字符串形式的字面量的null)
- 如果值是undefined,返回”undefined“。
let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
let value1 = 10 + " " + "你回答";
let value2 = true + " 你";
let value3 = null + " " + "你你你";
let value4;
console.log(String(value1)); // "10 你回答"
console.log(String(value2)); // "true 你"
console.log(String(value3)); // "null 你你你"
console.log(String(value4)); // undefined
// 说明:用加号操作符给一个值加上一个空字符串" ",也可以将其转换为字符串(加号操作符)
模板字面量
在定义模板时,需要用到模板字面量,使用反引号内部的空格,因此在使用时要格外注意。
// 这个模板字面量在换行符之后有 25 个空格符
let myTemplateLiteral = `first line
second line`;
console.log(myTemplateLiteral.length); // 47
// 这个模板字面量以一个换行符开头
let secondTemplateLiteral = `
first line
second line`;
console.log(secondTemplateLiteral[0] === '\n'); // true
// 这个模板字面量没有意料之外的字符
let thirdTemplateLiteral = `first line
second line`;
console.log(thirdTemplateLiteral);
// first line
// second line
字符串插值
模板字面量最常用的特性是支持字符串插值,可以在一个连续定义中插入一个或者多个值。从技术上来说,模板字面量不是字符串,而是一种特殊的JavaScript句法表达式,在求职之后得到的是字符串
模板字面量在定义时立即求值并转换为字符串实例,任何插入的变量也会从它们最接近的作用域中取值。
let value = 5;
let exponent = 'second';
// 以前,字符串插值是这样实现的:
let interpolatedString = value + ' to the ' + exponent + ' power is ' + (value * value);
// 现在,可以用模板字面量这样实现:
let interpolatedTemplateLiteral = `${ value } to the ${ exponent } power is ${ value * value }`;
console.log(interpolatedString); // 5 to the second power is 25
console.log(interpolatedTemplateLiteral); // 5 to the second power is 25
所有插入的值都会使用toString()强制转型为字符串,而且任何JavaScript表达式都可以用于插值。
//嵌套的模板字符串无需转义:
console.log(`Hello, ${ `World` }!`); // Hello, World!
//将表达式转换为字符串时会调用 toString():
let foo = { toString: () => 'World' };
console.log(`Hello, ${ foo }!`); // Hello, World!
//在插值表达式中可以调用函数和方法:
function capitalize(word) {
return `${ word[0].toUpperCase() }${ word.slice(1) }`;
}
console.log(`${ capitalize('hello') }, ${ capitalize('world') }!`); // Hello, World!
//此外,模板也可以插入自己之前的值:
let value = 'A';
function append() {
value = `${value}abc`
console.log(value);
}
append(); // Aabc
append(); // Aabcabc
append(); // Aabcabcabc
let value = ''; let text = 'AAA'
function append() {
value = `${text}${value}abc`
console.log(value);
};
append();//空格不会被拼接
模板字面量标签函数
标签函数:接受被插值记号($)分隔后的模板和对每个表达式的求值结果。接收到的参数依次是原始字符串数组和每个求值表达式的结果。
let a = 6;
let b =9;
function simpleTag(Strings,expression1,expression2,expression) {
console.log(Strings)
console.log(expression1)
console.log(expression2)
console.log(expression)
return "标签函数返回值是对模板字面量求值得到的字符串"
}
let result =`${a} + ${b} = ${a+b}`;
let taggerResult = simpleTag`${a} +${b} = ${a+b}`;
console.log("result",result) // 6 + 9 = 15
console.log("taggerResult",taggerResult) //标签函数返回值是对模板字面量求值得到的字符串
因为表达数的参数数量是可变的,通常使用rest 操作符(剩余操作符)将他们收集到一个数组中, 所以上面的代码等价于下面的代码:
let a = 6;
let b =9;
function simpleTag(Strings,...expressions) {
console.log(Strings)
for (const expression of expressions){
console.log(expression)
}
console.log(expressions)
return "标签函数返回值是对模板字面量求值得到的字符串"
}
let result =`${a} + ${b} = ${a+b}`;
let taggerResult = simpleTag`${a} +${b} = ${a+b}`;
console.log("result",result)
console.log("taggerResult",taggerResult)
原始字符转
如果不是获取转义之后的字符表示,而是获取字符串的原始模板字面量内容,可以使用 String.raw 标签函数。
// Unicode 示例
// \u00A9 是版权符号
console.log(`\u00A9`); // ©
console.log(String.raw`\u00A9`); // \u00A9
// 换行符示例
console.log(`first line\nsecond line`);
// first line
// second line
console.log(String.raw`first line\nsecond line`); // "first line\nsecond line"
// 对实际的换行符来说是不行的
// 它们不会被转换成转义序列的形式
console.log(`first line
second line`);
// first line
// second line
console.log(String.raw`first line
second line`);
// first line
// second line
也可以通过标签函数的第一个参数,也就是字符串数组的.raw 属性获取每个字符串的原始内容:
function printRaw(strings) {
console.log('Actual characters:');
for (const string of strings) {
console.log(string); // © //(换行符)
}
console.log('Escaped characters;');
for (const rawString of strings.raw) {
console.log(rawString); // \u00A9 // \n
}
}
printRaw`\u00A9${ 'and' }\n`;
Symbol 类型
Symbol(符号)是ES6 新增的数据类型,符号是原始值,且符号实例时唯一、不可变的。确保对象属性使用唯一标识符,不会发生属性冲突的危险。
符号的基本用法
符号需要使用Symbol() 函数初始化。因为符号本身是原始类型,所以使用typeof 操作符返回symbol。
- 可以传入一个字符串参数作为对符号的描述,但是字符串参数与符号定义或标识完全无关
- 没有字面量语法
- Symbol()函数不能和new关键字一起用作构造函数使用。——避免创建符号包装对象,如果确实想使用符号Symbol包装对象,需要使用到Object()函数;
let mySymbol = Symbol();
let myWrappedSymbol = Object(mySymbol);
console.log(typeof myWrappedSymbol); // "object"
全局符号注册表(Symbol.for)
运行时不用的部分需要共享或者重用符号实例,那么可以使用一个字符串作为键,在全局符号注册表中创建并重用符号。let fooGlobalSymbol = Symbol.for('foo'); console.log(typeof fooGlobalSymbol); // symbol
Symbol.for()对每个字符串键都执行幂等操作。第一次使用某个字符串调用时,它会检查全局运 行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。后续使用相同 字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
let otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号
console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
//没有使用全局注册表是俩者的声明的symbol 对象不一样
let localSymbol = Symbol('foo');
let globalSymbol = Symbol.for('foo');
console.log(localSymbol === globalSymbol); // false
使用Symbol.keyFor()来查询全局注册表,方法中接受符号,返回该全局符号对应的字符串键,如果查询的不是全局符号,则返回undefined。
// 创建全局符号
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s)); // foo
// 创建普通符号
let s2 = Symbol('bar');
console.log(Symbol.keyFor(s2)); // undefined
// 如果传给Symbol.keyFor()不是符号,则报错
Symbol.keyFor(123); // TypeError: 123 is not a symbol
符号作为属性
凡是可以使用字符串或数值作为属性的地方,都可以使用符号。包括了Object.defineProperty()和Object.defineProperties()定义的属性。对象字面量只能在计算属性中使用符号作为属性。
let s1 = Symbol('foo'),
s2 = Symbol('bar'),
s3 = Symbol('baz'),
s4 = Symbol('qux');
let o = {
[s1]: 'foo val'
};
// 这样也可以:o[s1] = 'foo val';
console.log(o);
// {Symbol(foo): foo val}
Object.defineProperty(o, s2, {value: 'bar val'});
console.log(o);
// {Symbol(foo): foo val, Symbol(bar): bar val}
Object.defineProperties(o, {
[s3]: {value: 'baz val'},
[s4]: {value: 'qux val'}
});
console.log(o);
// {Symbol(foo): foo val, Symbol(bar): bar val,
// Symbol(baz): baz val, Symbol(qux): qux val}
Object 类型
数据和功能的集合;通过new操作符后跟对象类型的名称来创建开发。
let obj = new Object(); //合法,推荐
let obj = new Object; //合法,但是不推荐
属性和方法
- constructor:用于创建当前对象的函数。
- hasOwnproperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属 性。要检查的属性名必须是字符串(如 o.hasOwnProperty("name"))或符号。
- isPrototypeOf(object):用于判断当前这个对象是否为另一个对象的原型。
- propertyIsEnumerable(PropertyName):用于判断给定的属性(字符串)是否可以使用for-in 语句枚举。
- toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
- toString():返回对象的字符串表示。
- valueOf():返回对象对应的字符串、数值或布尔值表示。通常与 toString()的返回值相同。
>> 最后
我正在成长,如果有什么问题欢迎大家留言,我们一起讨论。。。
如果对您有用,希望您留下评论/👍/收藏。
您的三连,是对我创作的最大的鼓励🙇♀️🙇♀️🙇♀️