一、JS原始值之间的数据类型转换
1.其他数据类型转为number类型
Number();书写格式
- 字符串转为number
console.log(Number('1.1'));//1.1
console.log(Number('10px'));//NaN
console.log(Number('-10'));//-10
console.log(Number('true'));//NaN
console.log(Number(''),'------');//0
console.log(Number(' '),'@@@@@');//0 【空串都是零】
- 布尔值转为number
console.log(Number(true));//1
console.log(Number(false));//0
- null/undefined转为number
console.log(Number(null));//0
console.log(Number(undefined));//NaN
- symbol转为number
console.log(Number(Symbol()));//symbol不能转number,会报错
console.log(Number(98765456787654n));
console.log(Number(10n));
2.其他数据类型转为string(字符串)类型
总结:直接加引号
3.其他数据类型转为Boolean(布尔值)类型
除了null nudefined NaN 0 ‘’空串这5个意外是false, 其他都是true
二、引用数据类型——普通对象
把多组键值对用大括号包起来 ,并且属性与属性之间用“逗号”进行分割
语法:
var obj={
属性名1:属性值,
属性名2:属性值
......
}
var obj={
"name":"lili",
"age":18
}
属性名和属性值
- 属性名:就是用来描述某种特征或者特点的名字,(又被称作键,key)
- 属性值:就是这个特征的具体值(又被称作值,value)
- 合称键值对
基本操作:增、删、改、查
1.属性值的获取——查
对象的属性名一般都是字符串格式(还可以是数字格式),属性值可以是任意类型数据
- 对象.属性名
- 对象.['属性名']
注意:如果对象里面没有这个属性,得到的值就是“undefined”
var obj={
"name":"lili",
"age":18
}
console.log(obj.name);
console.log(obj["name"])
2.增、改
对象的属性名(键)是不允许重复的,之前没有这个属性则为新增,之前有这个属性,则是修改对应的属性值
如果原来的对象中没有那个属性名,就是新增,如果有就是修改
var obj={
"name":"lili",
"age":18
}
obj.name="dawei";====>修改
obj.sex="男"=====》 增加
console.log(obj)
3.删除
- 彻底删除 delete 对象["属性名"]
- 只是让对象中的属性值为空, obj["属性名"]=null;
var obj={
"name":"lili",
"age":18
}
delete obj["age"];
obj.name=null;
console.log(obj);
注意
- 对象的属性名不能是引用数据类型值
- 基于 对象[属性名] 的方式操作,需要保证属性名是一个值(字符串/数字/布尔等都可以),如果不是值而是一个变量,它会把变量存储的值作为对象的属性名进行操作
- 基于 对象.属性名 的方式操作,属性名就是点后面的
let n = {
x: 100
};
let m = [100, 200];
let obj = {};
obj[n] = "哈哈";
obj[m] = "呵呵";
console.log(obj);
三、引用数据类型——数组(简单了解)
- 用中括号([])包含以逗号分隔的元素列表
- 数组是特殊的对象:
- 1.它的属性名是数字,数字从零开始,逐级递增,每一个数字代表着当前项的位置 =>我们把这种数字属性名叫做“索引”
- 2.默认有一个length属性存储数组的长度
let arr = [10, 20, 30];
console.log(arr[0], arr[1], arr[2]);
console.log(arr.length);
console.log(arr['length']);
四、数据类型之间的转换
Number()
对象转为数字:先把对象转为字符串,再把字符串转为数字
- 普通对象转为数字类型
/*
* 1.先把obj转化为字符串 "[object Object]"
* 2.把字符串转换为数字 Number("[object Object]")
*/
let obj={x:100};
console.log(Number(obj)); //=>NaN
- 数组转为数字类型
/*
* 1.先把arr转换为字符串: "10"
* 2.在把"10"转换为数字:10
*/
let arr = ["10"];
console.log(Number(arr)); //=>10
/*
* 1.先把ARR转换为字符串: "10,20"
* 2.在把"10,20"转换为数字:NaN
*/
arr = ["10", "20"];
console.log(Number(arr)); //=>NaN
console.log(Number([])); //=> []->'' Number('')->0
console.log(Number(['AA'])); //=> ['AA']->'AA' Number('AA')->NaN
String()
-
普通对象转换为字符串
普通对象转换为字符串都是 "[object Object]"
-
数组转换为字符串
数组对象转换为字符串是 "第一项,第二项..."(逗号分隔数组中的每一项)
Boolean()
除了0 "" NaN undefined null 其他都是true
基础调试代码
var num=0;
// 1、打印
console.log(num);
function fun(){}
// 2、详细输出
// console.dir输出一个对象或者一个值的详细信息;
// console.log可以一次性输出多个值,但是dir不可以;
console.log(fun,10,100);
console.dir(fun);
// 3、弹框的时候,会把数据转为字符串(toString)
// alert是在浏览器窗口中弹出一个提示框,提示框中输出指定的信息
// 需要等到alert弹出框,点击确定关闭后,后面的代码才会继续执行
var obj={name:"lili"};
// alert(obj);
//4、提示框,如果点击是确定,返回值就是true,如果点击的是取消,返回值就是false
// confirm相对于alert来说,给用户提供了确定和取消两种选择
var res=confirm("你准备好了吗?");
console.log(res);
//5、带输入框的提示框: 返回值,如果点击的是确定,返回的就是你输入的内容,
// 如果点击是取消是null
var res2=prompt("你是男孩还是女孩?");
console.log(res2);
五、浅谈js运行机制
(堆栈内存和不同数据类型的操作方式)
堆(heap)栈(stack)内存
浏览器加载页面,运行代码的时候:
- 每打开一个页面,就会从计算机的内存条中分配出两块内存:堆内存(heap)和栈内存(stack)
- 堆内存(heap):
- 主要存放引用数据类型的值
- 栈内存(stack):
- 给代码提供可执行的环境
- 存贮基本数据类型的值
思考题:
var a=12;
var b=a;
console.log(b);
var obj1={"name":"lili","age":12};
var obj2=obj1;
obj2.age=18;
console.log(obj1.age);
1、浏览器打开页面的时候会划分两块内存,堆内存和栈内存:
- 栈内存的作用:
- 1、给js提供一个可运行的环境
- 2、存储基本数据类型的值
- 堆内存的作用:存放引用数据类型,对象的话存贮的就是键值对,如果是函数,把整个函数当成字符串进行存储
2、代码自上往下执行 (之前还有一个变量提升阶段,会在后面的课程中进行讲解)
====> 基本数据类型:存在栈内存中, 按值操作
====> 引用数据类型的值比较复杂,存在堆内存中,按引用地址的操作
3、赋值操作的三步曲:
- 先创建值
- 再创建变量
- 最后把创建的变量和值关联在一起
六、在JS中用来检测数据类型的四种方式
typeof
- 用法:typeof [value]
- 返回值:是一个字符串,其次是一个字符串包裹了对应的数据类型('object','undefined','function','number')
- 特点:
- typeof null==>'object'
- 不能细分对象:typeof 检测对象的时候,除了函数会返回'function',其他的都是'object'(是因为它检测出为对象后,会再去看看是否实现了call方法。如果实现了就说明是一个函数)
- typeof 在检测一个未被声明的变量,不会报错,结果是'undefined'
- 原理:typeof 在检测数据类型的时候,是按照数据值在计算机底层存储的 二进制 值,进行检测的,其中如果二进制值的前三位是零,都会被识别为对象,然后去看对象是否具备call方法,具备call方法则返回'function',不具备的返回'object'。而null在计算机底层二进制值都是零,所有typeof null==>'object'
- 应用:
- 检测除null之外的原始值类型(typeof 使用起来方便,而且性能还好)
- 笼统检测是否为对象
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> const isObject = function isObject(value) { // 这个值的检测结果 let type = typeof value // 是对象的条件:不能是null,并且typeof检测的结果是'object'和'function'中的一个 return value !== null && (type === 'object' || type === 'function') } </script> </body> </html>
- 检测是否为函数
- 判断兼容性
instanceof
- 用法:对象 instanceof 构造函数
- 原本的意义是用来检测“某个对象是否是相应类的实例”,只不过针对于这个特点,我们可以检测一些数据类型
- 检测是否为数组:值 instanceof Array
- 检测是否为正则:值 instanceof RegExp
- 也就是可以 基于 instanceof ,可以弥补typeof 不能细分对象的缺陷、
- 特点:
- 无法检测原始值类型 ,返回结果都是false:【原因:基于instanceof进行操作,不会对原始值类型进行“装箱”操作】
- 原本不是检测数据类型的,但是非要让其检测类型,所以检测的结果不一定准确
let num = 10 //原始值类型 console.log(num.toFixed(2)) //"10.00" 默认进行了“装箱”操作(把原始值转换为对象)num->Object(num) let num2 = new Number(10) //对象类型 console.log(num2 + 10) //20 默认进行了“拆箱”操作(把对象转换为原始值)num2[Symbol.toPrimitive] -> num2['valueOf']()
- 原理:依次查找对象的原型链(__proto__),一直到Object.prototype,在此过程中,如果构造函数.prototype 出现在了其原型链的某个环节,则说明 当前对象 是此构造函数的一个实例,检测结果就是true
constructor
获取对象的构造函数,从而判断是否是属于某一个数据类型
只不过这种方式我们一般很少去使用,因为 constructor 值是可以被更改的「修改值的成本低」,一但被更改,则检测结果是不准确的!
Object.prototype.toString.call()
- 不仅仅 Object.prototype 上有 toString 方法,在 Number/String/Boolen/Array/Function... 的原型对象上,也有 toString 方法,只不过其它原型上的toString方法都是用来转换为字符串的,只有Object.prototype.toString是用来检测数据类型的
-
把 Object.prototype 上的 toString 方法执行,让方法中的 this 指向要检测的数据值,这样就可以返回此数据值的数据类型 -> "[object ?]
-
特点:精准且强大「唯一不足就是写起来麻烦一丢丢」
-
“?”一般情况下,就是检测值所属的构造函数(前提:内置的构造函数)
const toString = Object.prototype.toString
toString.call(null) -> “[object Null]” 虽然Null不是构造函数,但是结果还是很准的
toString.call(undefined) -> “[object Undefined]”
toString.call([]) -> “[object Array]”
toString.call(/\d+/) -> “[object RegExp]”
-
如果被检测的值具备 Symbol.toStringTag 这个属性,那么属性值是啥,最后检测结果中的“?”就是啥
在Promise.prototype上,具备 Symbol.toStringTag 这个属性,属性值是 "Promise"
let p = new Promise(()=>{})
toString.call(p) -> "[object Promise]"
-
-
此办法虽然很不错,但是也不是所有的数据类型检测都使用这个办法,一般来讲:需要笼统的检测或者按照大的类别去检测,使用 typeof 会更方便,而需要很精准检测的时候,使用 toString 会更好!!
除了以上四个检测数据类型的方法,还有一些快捷的方法
- isNaN 检测是否为有效数字
- Array.isArray 检测是否为数组