文章目录
前言
我们要了解JavaScript这门脚本的来源,他的一些数据类型,以及如何判断数据类型,而且在JavaScript中存在隐式转化要注意一些阴间玩意~~~~
一、JavaScript是什么语言类型?
- 静态语言: 在声明变量之前需要先定义变量类型。我们把这种在使用之前就需要确认其变量数据类型的称为静态语言。
- 动态语言:在声明变量之前不需要先定义变量类型。我们把这种在使用之前不需要确认其变量数据类型的称为动态语言。
- 强/弱语言:通常把会偷偷转换的操作称为隐式类型转换。而支持隐式类型转换的语言称为弱类型语言,不支持隐式类型转换的语言称为强类型语言。
由上面类型的判断,我们可以知道JavaScript 是一种弱类型的、动态的语言。这些特点也意味着。弱类型,你不需要告诉JavaScript引擎这个变量是什么类型的数据,JavaScript引擎在运行代码的时候回自己机计算出来。动态也就以为这你可以用同一个变量保存不同类型的数据。
//弱类型
let a = 'sadf';
let b = 4573;
let c = undefined;
console.log(typeof(a)); //string
console.log(typeof(b)); //number
console.log(typeof(c)); //undefined
//动态
a = 5645
console.log(typeof(a)); //number
二、数据类型
- undefined : 一个没有被赋值的变量会有个默认值 undefined
- Null : Null 类型只有一个值: null
- Boolean : 表示逻辑实体,有两个值true和false
- Number : 数字类型 ,范围 -/+( 2^63-1)
- String : 字符串类型,不可修改,第一个字下表为0
- Symbol:符号类型是唯一的且不可修改的,通常用来做object的key
- BigInt : 新的数据类型,可以用任意精度表示整数
- Object : 一组属性的集合
注意点
- 除了引用型数据是存储在堆中的,其他类型都是存储在栈中的,而引用型的数据会在栈中保留一个指针,指向在堆中的位置
- 除了Object是引用数据类型,其他都是基本类型,而深/浅拷贝只对object和Array这些引用类型起作用
- 使用 typeof 检测 Null 类型时,返回的是 Object。这是当初 JavaScript 语言的一个 Bug,一直保留至今,之所以一直没修改过来,主要是为了兼容老的代码。
- Object 类型比较特殊,它是由上述 7 种类型组成的一个包含了 key-value 对的数据类型。如下所示:
- 栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。所以每次使用完对象的时候都要把它设置为null,从而减少无用内存的消耗
- 除了Object是引用型数据,其他都是基本数据类型,而在JavaScript中,赋值操作(=)和其他语言有很大的不同,原始类型的赋值会完整复制变量值,而引用类型的赋值是复制引用地址。也应为这个原因对于引用型数据有深拷贝这个影响的出现。
- 对于变量,永远不要显式给它赋值为undefined,但对于变量要是要保存对象的话,永远要对他保存为null,这样我们就能保证null指向空指针的语义,同时区分开和undefined
三、真值/假值
补充一个知识点,就是什么是真值和假值,以及他们的用途效果
- 假值:
- false
- null
- undefined
- 0
- ‘’(空字符串)
- NAn
- 真值
*除了上面以外的都为真值
注意
在判断是要注意区分开了,自己判断的是某个字变量(null,undefined…)同时他还是个假值的影响
四、类型判断
简介
typeof
定义:
- 这个方法很常见,一般用来判断基本数据类型,如:string,number,boolean,symbol,bigint(es10新增一种基本数据类型bigint),undefined等。
typeof 目前能返回string,number,boolean,symbol,bigint,unfined,object,function这八种判断类型
//用typeof判断类型
let a ;
let b = null;
let c = true;
let d = 666;
let e = "牛逼";
let f = 6546513248976512376878646514657876534535434n;
let g = {
a: 7856,
b: 4613
};
let h = function() {};
console.log(typeof a); //undefind
console.log(typeof b); //object
console.log(typeof c); //boolean
console.log(typeof d); //number
console.log(typeof e); //string
console.log(typeof f); //bigint
console.log(typeof g); //object
console.log(typeof h); //function
console.log(typeof aa); //undefind
注意点
- 对于null的判断是object
- 对于未初始化和声明的变量的判断都是undefined
instanceof
定义:
- 一般用来判断引用数据类型的判断,如:Object,Function,Array,Date,RegExp等
instanceof 主要的作用就是判断一个实例是否属于某种类型 - instanceof 也可以判断一个实例是否是其父类型或者祖先类型
- instanceof原理实际上就是查找目标对象的原型链
缺点
- 不能检测原始值类型;
- 原型链可以重构,导致结果不准确
//这段代码来自MDN
// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype 不在 o 的原型链上
o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上
手写实现instanceof
思路
- 先判断是否为对象类型或者特殊情况null
- 再比较实例对象的原型等不等于构造函数的prototype,
- 如果等于,则返回true
- 如果不等于,则找实例对象原型的原型,比较它等不等于构造函数的prototype,
- 如果等于,则返回true
- 如果不等于,则继续在原型链往上找,直到找到原型链的最顶层,即null,则为false
//后面打算写篇关于手写实现所有JavaScript中关键的方法的。
function myInstanceof(left, right) {
//基本数据类型直接返回false
if(typeof left !== 'object' || left === null) return false;
//getProtypeOf是Object对象自带的一个方法,能够拿到参数的原型对象
let proto = Object.getPrototypeOf(left);
while(true) {
//查找到尽头,还没找到
if(proto == null) return false;
//找到相同的原型对象
if(proto == right.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
console.log(myInstanceof("111", String)); //false
console.log(myInstanceof(new String("111"), String));//true
Object.prototype.toString.call(这个是判断类型最准的方法)
定义
- 每一个Object原型上的都会继承toString()方法,该方法没有重写,都会返回其调用者的具体类型,返回的类型格式为[object,xxx],xxx是具体的数据类型
- 但是我们使用的很多数据类型都重写了toString()方法,所以我们同时还得用call()或Reflect.apply()指向它的Object,确保执行的是object的toString方法。
- 不能通过new来创建,我们是根据原型链来查找到该元素的Object下的toString()方法的。
Object.prototype.toString() 的原理
- 如果参数为null或undefined,会直接返回。
- 如果并不是,就会把参数转化为对象,再判断。
- 转为对象后,取得该对象的获取this对象的[[Class]]属性的值. 作为 tag,返回 "[object " + tag + “]” 形式的字符串。
console.log(Object.prototype.toString.call(null)); // => "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // => "[object Undefined]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
console.log(Object.prototype.toString.call(1753)); // "[object Number]"
console.log(Object.prototype.toString.call("你好")); // "[object String]"
console.log(Object.prototype.toString.call([1,2,5])); // "[object Array]"
console.log(Object.prototype.toString.call((function() {
return arguments;
})())); // "[object Arguments]"
console.log(Object.prototype.toString.call(function(){})); // "[object Function]"
console.log(Object.prototype.toString.call(new Error())); // "[object Error]"
console.log(Object.prototype.toString.call(/\d+/)); // "[object RegExp]"
console.log(Object.prototype.toString.call(new Date())); // "[object Date]"
console.log(Object.prototype.toString.call(new class {})); // "[object Object]"
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
提问环节
1.问:为什么一定要分“堆”和“栈”两个存储空间呢?所有数据直接存放在“栈”中不就可以了吗?
答:不可以的。这是因为 JavaScript 引擎需要用栈来维护程序执行期间上下文的状态,如果栈空间大了话,所有的数据都存放在栈空间里面,那么会影响到上下文切换的效率,进而又影响到整个程序的执行效率。
2.在JS中为什么0.2+0.1>0.3?
答:因为在JS中,是转化为二进制计算,浮点数是使用64位固定长度来表示的,第一位表示符号位,11位用来表示指数位,剩下的52位尾数位,由于只有52位表示尾数位。标准位数的多余的位数会被截断,造成进度缺失了,计算完成后又转化为十进制就变为0.300000000000004
演变题型:
- 为什么0.2 + 0.3 = 0.5 (因为刚好)
- 那么如何让0.1+0.2 = 0.3
3.为什么typeof null是Object
答:在JavaScript中,对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全为0,所以判断出来的结果object,并且null在逻辑上讲,表示一个空对象指针。(想深入看看如何二进制的存储的,随便看了眼,好像跟前端二进制啥的有关,还没了解过,埋个坑吧)
其他的一些常用的
- 000 对象
- 1 整型
- 010 双精度类型
- 100字符串
- 110布尔类型