update time 2023年2月15日22:00:52
一、数据类型的定义
- JS是一种弱类型语(动态语言)。
- 在程序运行过程中,类型会被自动确定(根据等号右边的值)
// int num = 10; // java
var num; // 这里的num我们不确定属于哪种数据类型
var num = 10; // num数据数字型
二、数据类型分类
- 原始类型也叫简单数据类型或者基本数据类型。因为其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈(stack)中(按值访问)。
- 引用类型(复杂数据类型或者Object)由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此其存储在堆(heap)中,存储在变量处的值是一个指针,指向存储对象的内存处(按址访问)
三、typeof操作符(数据类型检测)
- 主要是用来检测基本数据类型(对于复杂数据类型效果不大)
- 语法:typeof 待检测的变量
- 返回的值为数据类型
// typeof操作符 (数据类型检测)
// (1) 数字型返回number
var num = 1;
console.log('num: ', typeof num); // number
// (2) 字符串型返回string
var str = '' + 1;
console.log('str: ', typeof str); // string
// (3) 布尔型返回boolean
console.log('flag: ', typeof true); // boolean
// (4) undefined返回undefined
var age;
console.log('age: ', typeof age); // undefined
// (5) null返回object 表示值为对象(空对象的引用)
var space = null;
console.log('space: ', typeof space); // object
var obj = new Object();
console.dir(obj.__proto__.__proto__); // null Object的最顶层就是用null表示
// (6) symbol返回symbol
let sym = Symbol();
console.log('sym: ', typeof sym);
// (7) 函数返回function
// 严格来说,在ECMAscript中,函数也被认为是对象,并不代表一种数据类型,但是函数也有自己特殊的属性。为此,就有必要通过typeof操作符来区分函数还是其他对象
var fun = function() {}
console.log('fun: ', typeof fun); // function 表示值为函数
// (8) 对象返回object
var ob = {};
console.log('ob: ', typeof ob);
// (9) 数组返回object 因为数组也是对象
var arr = [];
console.log('arr: ', typeof arr);
null表示空对象引用
常用数据类型返回值参考
- Number return number
- String return string
- Boolean return boolean
- Undefined return undefined
- Null return object
- Symbol return symbol
- object return object
- Function return function
- Array return object
四、instanceof 操作符
- 主要是用来检测复杂数据类型
- 语法:待检测的变量 instanceof 某种数据类型
- 返回的值为boolean
- 判断方式
- 判断所有基本数据类型是否属于对应的数据类型都返回false
let num = 1;
console.log(num instanceof Number); // false
- 判断所有复杂数据类型是否属于对应的数据类型都返回 true
// (3)判断某些值是否属于引用类型
let arr = [];
let reg = /''/;
let date = new Date();
let obj = {};
console.log(arr instanceof Array); // true
console.log(reg instanceof RegExp); // true
console.log(date instanceof Date); // true
console.log(obj instanceof Object); // true
- 判断所有复杂数据类型是否属于 object 都会返回 true(因为object是所有引用类型的基类)
// (2) 因为object是所有引用类型的基类,所以判断所有引用类型是否是object,都会返回true
console.log(Array instanceof Object); // true
console.log(String instanceof Object); // true
console.log(Number instanceof Object); // true
console.log(RegExp instanceof Object); // true
console.log(Date instanceof Object); // true
动态属性
复制值
作用域链查找
解构赋值
Undefined
- undefined类型只有一个值,就是特殊值undefined
// 1.undefined类型只有一个值,就是特殊值undefined
let variable;
console.log(variable); // undefined
console.log(variable === undefined); // true
let variable1 = undefined; // 此写法是没有任何意义的,只是为了演示
- undefined的出现场景?
- 未初始化的变量默认为undefined
- 获取对象不存在的属性
- 无返回值的函数的执行结果
- 函数的参数没有传入
- void(expression)
- undefined和未定义变量的区别?
- undefined和未定义变量使用typeof操作符检测都返回undefined
- 建议定义变量必须初始化。当typeof返回undefined就是我们没有定义该变量。而不是未初始化
// 2.包含undefined的值和未定义变量的区别?
let message;
// 未定义 age
console.log(message); // undefined
// console.log(age); // 报错 因为没有声明此变量
// 使用typeof检测
console.log(typeof message); // undefined
console.log(typeof age); // undefined
// 结论:建议我们在使用变量时最好都进行初始化,这样当typeof返回“undefined”时,我们知道变量从未声明而不是声明未初始化
- undefined和null的区别和联系?
- undefined值是由null派生而来的,所以在表面上他们是相等的
// undefined继承自null,所以undefined == null,但是undefined又不是null,所以肯定不全等
console.log(undefined == null); // true
console.log(undefined === null); // false
Boolean
- Boolean有两个字面值,true(真)和false(假)
//1. Boolean有两个字面值,true(真)和false(假)
let flag = true;
let flag1 = false;
console.log(flag); // true
console.log(flag1); // false
- Boolean参与运算时,true表示1,false表示0
//2. 布尔值参与运算时,true为1,false为0
console.log(true + 1); // 2
console.log(false + 1); // 1
- 转换为Boolean类型
- 调用Boolean()转型函数
// (1) 调用Boolean转型函数
// 注意:0,'',null,undefined,NaN 转换为boolean值都为flase,其余的都为true
console.log(Boolean(0)); //fasle
console.log(Boolean("")); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(1)); // true
console.log(Boolean('message')); // true
console.log(Boolean({})); // true
- 使用双重取反"!!"转换
// (2) 使用双重取反转换
console.log(!!1); // true
console.log(!!"message"); // true
console.log(!!null); // false
- Boolean类型转换注意事项
数据类型 | 转换为false的值 | 转换为true的值 |
---|---|---|
Boolean | false | true |
string | ’ ’ | 非空字符串 |
number | 0,NaN | 非零数值(包括无穷值) |
object | null | 任意对象 |
undefined | undefined |
由于存在这种自动转换,理解流程控制语句中使用什么变量就非常重要。错误的使用对象而不是布尔值会明显改变应用程序的执行流。
Null
- Null类型同样只有一个值,即特殊值null。逻辑上讲,null表示一个空对象指针,这也是给typeof传一个null会返回“Object”的原因
// 1.Null类型同样只有一个值,即特殊值null。逻辑上讲,null表示一个空对象指针,这也是给typeof传一个null会返回“Object”的原因
var space = null;
console.log(typeof space); // Object
- 在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值。这样,只要检查这个变量的值是不是null就可以知道这个变量是否在后来被重新赋予了一个对象的引用
if (car != null) {
// car是一个对象的引用
}
- 任何时候,只要变量要保存对象,而当时又没有那个对象可以保存,就要使用null来填充该变量。这样就可以保持null是空对象指针的语义,并进步一讲其与undefined区分开来
var car = null; //使用nul来填充空对象
Number
1. 整数和浮点数
在JS中number表示整数和浮点数。最基本的数值为十进制,直接书写即可。
- 整数
- 八进制(以0开头,范围0~7)
- 十六进制(以ox开头,0~ 9,A~F)
- 注意:八进制的数值范围超过了0~7,会忽略前面的0,并以十进制展示
- 使用科学计数法表示较大的数和较小的数值
// 在JS中number表示整数和浮点数。最基本的数值为十进制,直接书写即可,整数可以是八进制(以0开头,范围0~7),可以是十六进制(以ox开头,0~9,A~F)。
// 注意:八进制的数值范围超过了0~7,会忽略前面的0,并以十进制展示
let intNum = 10; // 10 十进制
let octNum1 = 070; // 56 八进制
let octNum2 = 097; // 97 无效的八进制
let hexNum1 = 0xA; // 10 十六进制
let hexNum2 = 0xF; // 15 十六进制
// 使用科学计数法表示较大的数和较小的数值
let maxNum = 3.125e7; // 31 250 000 相当于3.125乘以10的7次幂
let minNum = 3e-7; // 0.000 000 3
- 浮点数
- 浮点数计算会丢失精度,所以尽量避免浮点数的计算
// 浮点数
let floatNum1 = 0.1; // 0.1 浮点数
let floatNum2 = 1.1; // 1.1 浮点数
let floatNum3 = .1; // 0.1 有效,但不推荐
let floatNum4 = 1.0; // 1 小数后面是零是当成整数来处理
let floatNum5 = 1.; // 1 小数点后面没有数字的会当成整数来处理
// 浮点数计算会丢失精度,尽量避免浮点数的计算
const result = 0.1 + 0.2; // 0.30000000000000004 不等于0.3
const result1 = 0.05 + 0.25; // 0.3
const result2 = 0.5 + 0.15; // 0.65
2.数值的范围
- 最大取值范围:
Number.MAX_VALUE
- 最小取值范围:
Number.MIN_VALUE
- 正无穷大:
Infinity
- 负无穷大:
-INfinity
// Number中值的范围
// (1) 最大值
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308 最大取值范围
// (2) 最小值
console.log(Number.MIN_VALUE); // 5e-324 最小取值范围
// (3) 无穷大
console.log('result: ', result); // Infinity 表示正无穷大
console.log(-result); // 表示负无穷大
判断值是不是有限大可以使用isFinite()
,return false表示超出了范围,true表示未超出
- 虽然超出数值范围的值并不常见,但计算非常大的值或者非常小的值时,有必要监测一下计算的结果是否超出了取值范围
const result = Number.MAX_VALUE + Number.MAX_VALUE;
// (5)如果要判断一个值是不是有限大(即JS的最大值和最小值之间),可以使用isFinite()
// 虽然超出数值范围的值并不常见,但计算非常大的值或者非常小的值时,有必要监测一下计算的结果是否超出了取值范围
console.log(isFinite(result)); // false 表示超出了范围
const result3 = 100 + 100;
console.log(isFinite(result3)); // true 表示没有超出范围
注意:当计算结果返回 Infinity 或者 -Infinity时该值不会在参与任何运算。
3.NaN
NaN 意思是"不是数值"(Not a Number)。用于表示本来要返回整数值的操作失败 (而不是抛出错误)。
// (1)NaN 意思是“不是数值”(Not a Number)。用于表示本来要返回整数值的操作失败 (而不是抛出错误)。
console.log(0 / 0); // NaN
console.log(-0 / +0); // NaN
console.log('数字' - 1); //NaN
- NaN有几个独特的的属性。
- 任何涉及NaN的操作始终返回NaN,如(NaN/10)
- NaN不包括NaN在内的任何值
// NaN不包括NaN在内的任何值
console.log(NaN == NaN); // false
- ECMAscript提供了
isNaN()
函数。- 该函数接收一个参数,可以是任意类型,然后判断这个参数"是否不是数值"。
- 该函数会尝试把传入的参数转换为数值格式, 如果是数值格式或者能转换为数值格式就返回false, 反之就返回true。
// ECMAscript提供了isNaN()函数。该函数接收一个参数,可以是任意类型,然后判断这个参数"是否不是数值"。
// 该函数会尝试把传入的参数转换为数值格式, 如果是数值格式或者能转换为数值格式就返回false, 反之就返回true。
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // fasle 10是数值
console.log(isNaN('10')); // fasle 可以转换为数值 10
console.log(isNaN('张三')); // true 不能转换为数值
console.log(isNaN(true)); // false 可以转换为数值1
4. 其他类型转换为number类型
- Number() (强制转换)
- Number()是转型函数,可以用于任何数据类型。由于Number()函数转换字符时复杂且反常规,所以优先使用parseInt()
// (1) Number()函数 (强制转换)
let num3 = Number('hello world'); // NaN
let num4 = Number(''); // 0
let num5 = Number(00001); // 1
let num6 = Number(true); // 1
- parseInt()
- parseInt()将字符串转换为整数
// (2) parseInt() 函数, 字符串转换为整数
let num7 = parseInt('1234blue'); // 1234
let num8 = parseInt(''); // NaN
let num9 = parseInt('0xA'); // 10 将十六进制转换为十进制
let num10 = parseInt('22.5'); // 22 取整
let num11 = parseInt('70'); // 70 转换为十进制
let num12 = parseInt('0xF'); // 15 将十六进制转换为十进制
let num13 = parseInt('blue123'); // NaN
- 不同格式容易混淆,所以parseInt()也可传入第二个参数,用于指定进制数
// 不同格式容易混淆,所以parseInt()也可传入第二个参数,用于指定进制数
let num14 = parseInt('0xAF', 16); // 175 使用十六进制数的完整写法,并且指定进制
let num15 = parseInt('AF', 16); // 175 如果指定了进制数,那么十六进制前面的0x可以省略
let num16 = parseInt('AF'); // NaN 省略了0x,还没有传入第二个参数
let num17 = parseInt('10', 2); // 2 按二进制解析
let num18 = parseInt('10', 8); // 8 按八进制解析
let num19 = parseInt('10', 10); // 10 按十进制解析
let num20 = parseInt('10', 16); // 16 按十六进制解析
//注意: 如果不传进制数,让parseInt()自己决定如何去解析,为了避免出错,建议传入第二个参数
注意: 如果不传进制数,让parseInt()自己决定如何去解析,为了避免出错,建议传入第二个参数
- parseFloat()
- parseFloat()函数,此函数和parseInt()类似
// (2) parseInt() 函数, 字符串转换为整数
let num7 = parseInt('1234blue'); // 1234
let num8 = parseInt(''); // NaN
let num9 = parseInt('0xA'); // 10 转换为十六进制
let num10 = parseInt('22.5'); // 22 取整
let num11 = parseInt('70'); // 70 转换为十进制
let num12 = parseInt('0xF'); // 15 转换为十六进制
let num13 = parseInt('blue123'); // NaN
- parseFloat()和parseInt()的区别在于,它只能解析十进制,因此不能传入第二个参数,并且会忽略十进制前面的0,十六进制数值始终返回0。
// (3) parseFloat()函数,此函数和parseInt()类似
// parseFloat()和parseInt()的区别在于,它只能解析十进制,因此不能传入第二个参数,并且会忽略十进制前面的0,十六进制数值始终返回0。
let num21 = parseFloat('1234blue'); // 1234
let num22 = parseFloat('0xA'); //0
let num23 = parseFloat('22.5'); // 22.5
let num24 = parseFloat('22.34.5'); // 22.34
let num25 = parseFloat('0908.5'); // 908.5
let num26 = parseFloat('3.123e7'); // 31230000
- 使用算数运算符(隐式转换)
- 我们也可以使用算数运算符(-、/、*)等转换
// (4) 使用算数运算符隐式转换
console.log('10' - 0); // 10
console.log('10' * 1); // 10
console.log('10' / 1); // 10
String
1. String表示字符串数据类型,表示0或多个16位Unicode字符序列。
- 字符串可以使用双引号(" ")、单引号(’ ')或反引号( `` )表示
注意:以某种符号开头,必须以某种符号结尾
- 字符串嵌套:外单内双,内单外双
// String表示字符串数据类型,表示0或多个16位Unicode字符序列。字符串可以使用双引号(" ")、单引号(' ')或反引号(` `)表示
// 注意:以某种符号开头,必须以某种符号结尾
let firstName = "张三";
let lastName = '李四';
let lastName1 = `王五`;
// 字符串嵌套
// 外单内双,内单外双
let dou = '我是"中国"人';
console.log(dou); // 字符串 '我是"中国"人'
- 字符串转义符
转义符 | 解释说明 |
---|---|
\n | 换行符 |
\ \ | 斜杠 |
\ ’ | 单引号 |
\ " | 双引号 |
\t | tab缩进(空格) |
\b | 空格 |
// 字符串转义符
let text = '床前明月光,疑是地上霜。\n举头望明月,低头思故乡。';
let xiGeMa = '\u03a3'; // 西格玛符号
2. 字符串的特点
- ECMAscript中规定字符串中的值是不可变的。
意思就是: 值一旦创建就不能改变, 如果需要修改变量中字符串的值, 必须先销毁原始字符串, 然后将包含新值的另一字符串保存在该变量 - 所以,如果大量使用拼接字符串时,效率会降低
- 在早期的浏览器中,拼接字符串时会非常慢,后来浏览器也针对性的解决了此问题
// ECMAscript中规定字符串中的值是不可变得, 意思就是: 值一旦创建就不能改变, 如果需要修改变量中字符串的值, 必须先销毁原始字符串, 然后将包含新值的另一字符串保存在该变量
let lang = 'java';
lang = lang + 'script';
console.log(lang); // 'javascript'
// 解释说明:
// (1) 首先, 变量lang只包含字符串 'java', 紧接着lang被重新定义为包含 'java'和 'script'的组合。
// (2) 整个过程先会分配一个包含10个字符的空间,然后填充上'java'和'script'。
// (3) 最后销毁原有的字符串'java'和'script',因为这两个字符串都没有用了。所有处理都是在后台发生
// 所以,如果大量使用拼接字符串时,效率会降低
// 在早期的浏览器中,拼接字符串时会非常慢,后来浏览器也针对性的解决了此问题
3. 其他类型转换为String
- toString()方法
- toString() 方法可用于 数值、 布尔值、 对象 和字符串值( 字符串值只是返回自身的一个副本)。
- toString()方法在接收数值的时候可以传入一个参数,传入的参数为进制数,如果传入的进制数是2,则将值转换为2进制后转换为字符串结果,以此类推。默认情况下以十进制展示
- null和undefined没有toString()方法
// (1) toString() 方法可用于 数值、 布尔值、 对象 和字符串值( 字符串值只是返回自身的一个副本)。
// 注意:null和undefined没有toString() 方法
let age2 = 11;
let ageAsString = age2.toString(); // '11'
let found = true;
let foundAsString = found.toString(); // 'true'
// toString()方法在接收数值的时候可以传入一个参数,传入的参数为进制数,如果传入的进制数是2,则将值转换为2进制后转换为字符串结果,以此类推。默认情况下以十进制展示
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()函数 (强制转换)
- 如果不确定一个值是null还是undefined的话可以使用String()转型函数,它始终会返回相应类型值的字符串。
- 数值和布尔值与调用toString()结果相同。
// (2)(强制转换) 如果不确定一个值是null还是undefined的话可以使用String()转型函数,它始终会返回相应类型值的字符串,数值和布尔值于调用toString()结果相同
var obj = null;
var str;
console.log(String(obj)); // 'null'
console.log(String(str)); // 'undefined'
- 字符串拼接 (隐式转换)
- 字符串+任何类型 = 字符串 (数值相加,字符相连)
// (3)字符串拼接 (隐式转换)
// 字符串+任何类型 = 字符串 数值相加,字符相连
console.log('你好' + '张三'); // '你好张三'
console.log('现在是' + 21 + '点'); // '现在是21点'
console.log('你好' + true); // '你好true'
console.log(20 + 20); // 数值 40
console.log(20 + '21'); // '2021'
let age1 = 18;
console.log('我今年' + age1 + '岁了'); // '我几年18岁了'
console.log(undefined + '张三'); // 'undefined张三'
4. 模板字面量
- 模板字面量保留换行字符,可以跨行定义字符串
- 模板字面量会保持反括号里面的所有空格
//模板字面量,模板字面量保留换行字符,可以跨行定义字符串
let tem = 'my first\npage';
let tem1 = `my first
page`;
let tem2 = `my first
page`;
console.log(tem === tem1); // true tem和tem的确一样,包括空格,换行,等等。
console.log(tem1 === tem2); // false 因为模板字面量会保持反括号里面的所有空格,当然也包括我们的代码缩进
5. 字符串插值
- 技术上讲,模板字符串不是字符串,而是一种特殊的表达式,只不过求值后得到的是字符串
// 字符串插值
// 技术上讲,模板字符串不是字符串,而是一种特殊的表达式,只不过求值后得到的是字符串
let myName = '张三';
let age = 22;
// (1) 传统的字符串插值
let person = '我是' + myName + '\n我今年' + age + '岁了';
// (2)使用字符串插值
let jack = `我是${myName},我今年${age}岁了`
6. 模板字面量标签函数
// 模板字面量标签函数:标签函数可以自定义插值行为
// 模板字面量函数和定义普通函数方式一致
let a = 6;
let b = 9;
function simpleTag(strings, aVal, bVal, sum) {
console.log(strings);
console.log(aVal); // 6
console.log(bVal); // 9
console.log(sum); // 15
let foobar = `strings[0]`;
return 'foobar'
}
let untaggedResult = `${a}+${b}=${a + b}`;
console.log('untaggedResult: ', untaggedResult);
let taggedResult = simpleTag `${a}+${b}=${a + b}`;
console.log('taggedResult: ', taggedResult);
7. 原始字符串
- 使用String.raw标签函数可以直接获取原始模板字面量内容(换行符或Unicode字符),而不是转换后的字符
// 原始字符串
// 使用String.raw标签函数可以直接获取原始模板字面量内容(换行符或Unicode字符),而不是转换后的字符
//(1) Unicode示例 \u00A9b表示版权号
console.log(`\u00A9`); // ©
console.log(String.raw `\u00A9`); // \u00A9
//(2)换行符示例
console.log(`first line\nsecond line`);
/* 运行结果:
first line
econd line */
console.log(String.raw `first line\nsecond line`);
/* 运行结果:
first line\necond line */
// (3)注意:对于真是存在的换行,String.raw()并不会将其转换“\n”
console.log(`first line
second line`);
/* 运行结果:
first line
econd line */
console.log(String.raw `first line
second line`);
/* 运行结果:
first line
econd line */
注意:对于真是存在的换行,String.raw()并不会将其转换“\n”
Symbol
1. 解释说明:
- Symbol(符号)是ES6新增的数据类型。符号是原始数据类型,且符号实例是唯一,不可变的。
- 符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险
- 符号就是用来创建唯一记号,进而用作非字符串形式的对象属性
2. 符号的基本用法
- 符号需要使用Symbol()函数来初始化
- 调用Symbol()函数时,可以传入一个字符串参数用作对符号的描述,将来可以通过这个字符串来调试代码,这个字符串参数与符号定义或标识完全无关。
- 符号没有字面量语法。你只需要创建Symbol()实例并将其用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性。
- Symbol()函数不能与new关键字一起作为构造函数使用。
- 为了避免创建符号包装对象
- 真的想用符号包装对象,可以借用Object()函数
3.使用全局符号注册表
- 需要使用Symbol.for()方法