持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情
前言
结束了前几篇对DOM、BOM的基本解析,开始JavaScript语言的新篇章,从JavaScript基础语言开始。
JavaScript基础知识
主要对JavaScript语言基础的进一步概括和解析,不讲分支语句。
数据类型
- 基本数据类型:Undefined、Null、Boolean、Number、String 和 Symbol(ES6)、 bigint(ES6)
- number: 整数、浮点、八进制 0o10、二进制 0b10、 十六进制 0xff、Infinity、科学计数法 1.89E8NaN
- String: split、 slice、substr、substring、replace、trim、toLowerCase、concat、indexOf、lastIndexOf、repeat、search、valueOf、charAt
- 复杂数据类型:Object
- Function、Object、Array、Math、Date、RegExp、Set(ES6)、Map(ES6)
判断数据类型
typeof操作符
适用于number、boolean、string、undefined、function、symbol(ES6)、bigint(ES6)
===(全等)在两个操作数未经过转换就相等的情况的返回true
- 特殊:
- null和undefined只有一个唯一的值 所以可以使用全等判断 null和undefined
- NaN和NaN是不相等的
instanceof
简单理解: A instanceof B : 判断B在不在A的原型链上 只要在就都会返回true
完美的检测任意数据类型
Object.prototype.toString()
运算符
自增和自减
++、--在自身的基础上+1或-1(不管++放在操作数的前面或后面,那执行完本行之后肯定是加完之后的结果)放在操作数的后面先用后加,放在操作数的前面先加后用。
复合运算符
-=、*=、/=、%= 如a += b,完全等价于a = a + b
赋值运算符
=,将等号右边的值或表达式的值给到变量 (左边肯定是个容器(变量、对象属性),右边肯定是值或有值的内容)
比较运算符
>,大于、<,小于、>=,大于等于、<=,小于等于 (返回true或false)- 比较规则:
- 如果两个操作数都是数值,则执行数值比较
- 如果两个操作数都是字符串,则比较字符串对应的字符编码
- 其他类型值的比较都调用
Number()进行转换 - 特殊:任何数和NaN比较最后结果都为false
相等运算符
==,如果两个操作数相等,则返回true。!=,不等于,如果两个操作数不相等,返回true。- 比较规则:
- 类型相同直接比较值是否相等。
- 类型不同,只要有一个操作数是数值就先调用
Number() - 基本数据类型number、string、boolean和number、string、boolean比较的时候都会先转换为数值型。
- null和undefined是相等的。
- NaN和NaN是不相等的。
- 补充null和0的关系:
null>=0比较的0>=0true。null==0,null在做相等判断时不进行转型。null==0,因为null不转换类型那没办法比较所以最后结果是false。
全等和不全等
===,全等于,在两个操作数未经过转换就相等的情况的返回true。!==,两个操作数没有经过转换就不相等的情况下返回true。
逻辑运算符 not、and、or
&&逻辑与操作符- 第一个操作数和第二个操作数都为true的时候返回true,否则返回false
- 逻辑与操作符可以用于任何类型的操作数,而不仅仅是布尔值。如果第一个操作数经过
Boolean()转换之后为false,那么返回第一个操作数。如果第一个操作数经过Boolean转换之后为true,那么将会返回第二个操作数 - 逻辑与的短路操作,如果第一个操作数能够决定结果,那么不会对第二个操作数求值
||逻辑或- 第一个操作数和第二个操作数任意一个为true则返回true否则返回false
- 逻辑或操作符可以用于任何类型的操作数,如果第一个操作数经过Boolean转换后为true,返回第一个操作数,如果第一个操作数经过Boolean转换后返回false。则返回第二个操作数
- 逻辑或操作符也属于短路操作,第一个操作数的求值为true,不会对第二个操作数求值
!逻辑非,用来进行取反的操作
三元运算符
- 一元运算符:
!、++、-- - 二元运算符:
+、-、*、/ - 三元运算符:三个运算元:
条件 ? true表达式 : false表达式
运算符优先级
- 一元运算符优先级较高然后是二元最后是三元
- JavaScript严格按照从左到右的顺序计算表达式,然后再按照优先级和关联性计算各个表达式和运算符的结果。 优先级决定了先算谁,关联性决定了如果拥有相同的优先级执行顺序是什么
程序执行过程
堆和栈
堆和栈本身是数据结构,堆(链表结构)、栈(栈结构)。程序在运行的时候内存中按照逻辑分为了堆内存和栈内存
- 栈:栈结构中开辟的内存,比较小,速度快,操作系统自动分配自动回收。
- 特点:先进后出
- 堆:
- 空间比较大,速度稍微 慢一些,一般都是由程序员自己用的时候自己去申请;如果要让内存回收也必须手动释放内存。
- 特点:先进先出
- 在底层语言中是这样的,但是在JS中我们的内存回收起来几乎都是自动回收,JS中封装了垃圾回收机制。
执行环境
JavaScript的运行环境分为两种:
- Global,全局。JavaScript代码开始运行的时候默认就在这个环境下运行。
- Function,函数。进入到一个JavaScript函数的时候的运行环境(函数调用时候才会进入到这个环境)。 代码在执行的时候开辟出来一段栈空间说明执行顺序,这个栈我们叫执行栈。
- 当JS代码执行时会先将全局执行环境压入到栈底,当执行到函数时候会创建函数的执行环境并将函数执行环境压入到栈中。
- 当函数执行完成后将函数执行环境弹出并且销毁(和其相关的一系列都会被销毁)
- 一直到所有代码都执行完成之后才会将全局执行环境销毁。
执行环境的阶段
- 创建阶段(用来做准备工作)
- 全局环境:一上来就进入到全局中的创建阶段。
- 函数环境:当函数被调用,但是还没有执行函数中的代码之前。
- 代码执行阶段(真正的解释、执行代码)
作用域(变量起作用的范围)
作用域是在进入到全局执行环境或函数执行环境时就确定好的
作用域种类(全局作用域、函数作用域(局部作用域))
- 执行JavaScript进入了全局执行环境这个时候就有了全局作用域。执行某个函数时进入到了函数执行环境就有了函数作用域。
- 执行环境被销毁那么其对应的作用域也会被销毁
- 同一个函数多次调用会产生不同的执行环境,每调用一次就会产生一个新的执行环境
内存中的数据储存
通过下列图解分析内存中堆栈的执行和储存机制
var a = 100;
var b = [1, 2, 3];
function c(){
var a = 1;
var b = 2;
var c = [1,2,3]
return a + b;
}
var r = c();
console.log(r);
执行思路(对应图看)
首先声明a、b、c三个变量储存在执行栈中,因为基本数据类型是存在栈里面,所以a=100直接存储在栈中,而b是一个数组,是引用类型,引用类型开辟了堆内存,通过地址值0bxx去指向堆内存中的值obxx,依次保存着数组里面的内容。接下来c是函数,同样通过地址值去存储在堆内存中的值,接下来var r = c()调用函数,这时候在c函数没有调用之前,r的地址值其实是一个薛定谔的值,谁也不知道,当c函数执行完之后,通过相对应的地址值去运行堆内存中的代码,然后返回的结果是3,所以再赋值给r=3,也就是栈中的结果r为3.同样在执行c函数的时候,里面还有一个c的数组,同样是一个引用类型的,所以也将开辟一个堆存的独有堆和栈中的独有栈,通过栈中的地址值去找堆内存中的值,这也就是为什么函数和变量名之前都能找到相对应的值的关键所在。同样如果是赋值操作也就是拿得地址值的赋值。所以通过这个就能得知浅拷贝和深拷贝,浅拷贝是值的拷贝,只拷贝了地址值找到了相对应的堆内存的内容,而深拷贝则会开辟新的空间,形成一个新的堆用来存储新的内容。
总结
引用类型的值存储在堆内存中,存储引用类型的时候会给堆分配一个地址(这个地址16进制0x),但是标识符还是存储在栈内存中,为了能够让标识符和真正的数据结合起来那么在栈中存储的是引用类型的地址。
查找变量的时候和堆没有关系,和栈的执行环境有关系。
好了,以上就是本篇文章的分享,感谢阅读!