本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
2021-10-8 更新 读了大佬的一篇文章 发现自己写得太不全面了!
感兴趣的朋友们可以去看一下!文章讲述了0.1+0.2!===0.3、隐式转换、精准判断变量类型等有趣且重要的知识点
复习了一些JS最基础的知识——关于
-
数据类型的分类、判断🎉 以及一些拓展的基础知识
-
数据、变量、内存的理解🤔
-
数据存储的底层知识😴
-
为变量赋值时 赋给它的是?🧐
-
调用函数时传入的实参是值还是引用地址?😐
-
这里的内容虽然简单 但是第一次学习时很难理解透咯
偏偏这些知识在后期学习原型链等深入的知识时会很有帮助!
所以~还是要好好巩固下基础
如果有啥不全面/出现错误的地方 欢迎各位大佬的讨论/指正❤️ 夯实基础冲冲冲!
数据类型的分类、判断
1.数据类型的分类、判断🎉
何为数据?👓
首先明确下 啥是数据?
数据是在内存中可读、可传递的 保存了特定信息的东西 本质是二进制的机器码(给机器看的)我们程序员看到的肯定就是高级语言咯 我们写的代码中包含的数据经过编译让电脑可以理解,从而执行各种操作。
一切皆为数据 函数啊,对象啊啥的都是数据
在内存中 我们所有操作的目标都是数据 比如——
-
算术运算
-
逻辑运算
-
赋值运算
-
运行函数
那么既然要做这些个操作,就会涉及到数据类型们的使用(嘿哟!终于把它们引出来了)来看看这些数据类型的分类,看看怎么判断数据类型们!
数据类型的分类和判断🔐
大家都知道,数据是分为——基本类型、对象引用类型两大种的 我们来列出来看看
基本(值)数据
-
Number 数值类型
-
String 字符串类型
-
Boolean 布尔值类型
-
undefined
-
null
10-8补充
-
Symbol 实例是唯一且不可改变的数据类型
-
BigInt ES10中被提出 用于操作超过最大安全数字(
Number.MAX_SAFE_INTEGER1.111...X 2^52)的数字
以上五种类型是要怎么判断呢?大家心中应该都有答案了吧——使用 typeof ?
是 但不完全是 因为null是不能这样判断der~
| 数据类型 | 判断方法 |
|---|---|
| 数值型 | typeof |
| 字符串型 | typeof |
| 布尔型 | typeof |
| undefined | typeof或者=== |
| null | === |
| Symbol | typeof |
这里多一嘴
===代表严格全等 不会给等式两边自动做数据类型的转换而
==会自动为等式两边做隐式类型转换所以严谨起见 我们追求的是全等 都用
===(我知道大家都知道 我就提一嘴🤐)
var a = 666;
var b = 'bill';
var c = true;
var d;
var e = null;
console.log(typeof a);// number
console.log(typeof b);// string
console.log(typeof c);// boolean
console.log(typeof d, d === undefined);// undefined true
console.log(typeof e, e === null);// object(所以不能用typeof判断null咯) true
这里要注意 typeof a的返回值是字符串嗷
var a = 666;
var d = undefined;
console.log(typeof a, typeof a === 'number');// number true
console.log(d === undefined, typeof d === undefined, typeof d === 'undefined');// true false true
对象(引用)数据
- Object 对象
以下二位都属于特殊的对象
-
Array 数组
-
Function 函数
| 数据类型 | 判断方法 |
|---|---|
| Object | typeof/instanceof |
| Array | instanceof |
| Function | typeof |
var a = {};
var b = new Array(6);
var c = () => {};
console.log(typeof a, a instanceof Object);// object true
console.log(typeof b, b instanceof Array);// object(所以数组不能这么判断~) true
console.log(typeof c, c instanceof Function);// function true
【模拟下面试】undefined null那些事儿✨
面试官:“前面聊了数据类型 那么undefined和null有啥区别啊?”
这时候就可以展开讲一讲了~
简单来说
-
undefined代表定义未赋值
-
null代表定义并赋值了 但是赋了一个null
那么为啥要赋个null嘞 也就是这个null能干啥呢?(又延伸出一个点😂)
var obj = null;// 01 表示我们将要将给obj这个变量赋值为对象~(数组、对象、函数都ok)
obj = ['bill', 21];
obj = null;// 02 让obj指向的对象成为垃圾对象(回头垃圾回收器会过来把它收走 防止内存的消耗~)
如上👆
- 01 初始赋值 表明将要赋值obj为对象
- 02 结束使用obj之后 让对象成为垃圾对象
2.数据、变量、内存的理解🤔
数据存储的底层知识😴
了解数据存储的底层知识之前,先要了解 变量、内存 这两个概念 它们是息息相关的~
- 变量
一个变量对应一小块内存 变量的值保存在内存中!
- 内存
内存条通电后产生的存储空间(临时的 断电后就木有了~)
内存条就是这个绿绿的东西🧐
一块内存包含两方面的数据
-
内部存储的数据(存储于堆空间中——堆空间用于存储对象 占用空间较大)
-
地址值数据(存储于栈空间中——栈空间用于存储变量 占用空间较小)
举个例子
var obj = {name:'Tom'}
实际上就是等号右边的对象的内存内容(也就是它的地址值)赋给变量obj
👇左面的那一条就是模拟的栈~右面即为堆
这里让我想起了之前学习Java的时候 研究面向对象中JVM底部的运行机制时的学习——
这个是当时学习的笔记XD 面向对象基础的笔记
下图中 cat就是变量(位于栈中) 指向了 new Cat() 创建出来的对象(位于堆中)~
为变量赋值时 赋给它的是?🧐
来看个例子
// 01 给变量赋值基本数据 —— 保存的就是这个基本数据
var a = 666;
// 02 给变量赋值对象 —— 保存的是 【对象的地址值】 (如上图)
var obj = {name: "Bill"};
// 03 重要!给变量obj1 obj2赋变量a obj【的内存内容】
// —— 内存空间保存的可以是基本数据(a)也可以是对象的地址(obj)
var obj1 = a;
var obj2 = obj;
很明显地分为了三种情况~
-
【1】如01一样 可以赋给它基本数据类型
-
【2】如02一样 可以赋给它对象的地址值
-
【3】如03一样 赋给它某个对象的内存内容
- 而这个内存内容可以是基本数据类型
- 也可以是对象的地址
【高频面试题】调用函数时传入的实参是值还是引用地址?😐即“值传递/引用传递?”
先说结论
其实这里有两种理解——
【1】不管传递的是数组还是对象 都是值传递 —— 更加规范 因为理论上来说引用传递传递的地址值也是一个值~
【2】可能是值传递(传基本数据类型时) 也可能是引用传递(传地址值时)
其实到这里大家应该已经理解了 但是实际应用时呢?来举个例子吧~
举个🌰1号
var a = 3;
function fn(a){
a = a + 1;
}
fn(a);
console.log(a);
这里的输出是多少呢?
都这么问了肯定是有坑🤣
答案为3
来解释下——
var a = 3;
function fn(a){
a = a + 1;
// a(局部的那个a变量(也就是形参变量)所以在外面输出的是全局变量3)=a(全局的那个a变量 值为3)+1
// 这里的局部变量为4 而外面输出的是全局变量啦!
console.log(a);// 4
}
fn(a);//这里传递的不是a的地址 而是a的值——3
// 调用函数 将实参赋给形参
console.log(a);// 3
在传实参的时候传过去的是a的“值”!
其实吧 这里如果理解了作用域会更好理解 ——
函数作用域里发生的 a = a + 1 (修改值操作) 和我全局作用域有啥关系🤣
举个🌰2号
function fn2(obj){
obj.name = "change";// 这里修改了地址中对象的name属性
}
var obj = {name: "Bill"};
fn2(obj);// 调用函数 修改了地址中对象的name属性
console.log(obj.name);//change
害估计大家都能猜到栗子是啥了 传入的实参是地址值咯...
这时候函数作用域里面进行的修改值操作就起效果了~
你可能会问了这不耍赖皮么 为啥同样是修改值 一个作用范围这么广泛(地址值)一个就只是局部得(原始数据类型)
欸 这个可不一样(又回到了咱们今天讨论的大主题里——变量、内存的关系) 虽然变量是局部的 但是它指向的对象是全局的啊! 我修改的可是全局的对象 只不过你这个变量指向我 所以从中获取的值也跟着改变了~
对象的值改变了 obj.name的值自然会改变~
小结
说了这么多 小结一下
其实在调用函数进行传参时,严谨一点说,进行的都是值传递
只不过有些值传递传过去的是基本数据类型,改变的时候需要注意函数作用域的问题,而有些值传过去是地址值,直接对地址值进行改变才不管作用域呢,直接把对象改变😂看上述的例子就明白了 很简单der~但是面试的时候不得多白话两句显得咱想得比较多嘛(确实想了很多喂(#`O′))