js的变量有着松散类型的本质,就是变量存储的值及数据类型可以在脚本的生命周期里改变。
这个特性是既强大又容易出问题。 (这也是为啥现在更加推崇使用ts来编写项目)

基本类型和引用类型的值

偶然看到群里有人发了一个链接,点进去一看https://www.cnblogs.com/youxin/p/3354903.html
什么?没有按引用传递? 先不说这篇文章的博主写的对不对,我先来自己捋一捋这块的概念。

小红书在第四章讲到,ECMAscript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。
基本类型的值就是简单的数据段,前面提到过的,string null undifined number blooean Symbol都是基本类型。
那自然不用说,其他的就是引用类型了,也就是我们常说的对象。

基本类型可以直接操作保存在变量中的值。按值访问。
引用类型的值是保存在内存中的对象。这块有个重点, js与其他语言不同,不允许直接访问内存中的位置。 也就是不能操作对象的内存空间。 操作对象时候,实际上是在操作对象的引用,而不是实际的对象。

书下附了一段字
这种说法不严密,复制保存着对象的变量时,操作的是对象的引用,但是在为对象添加属性时,操作的是实际的对象。

原理:我的理解

基本数据类型都是放在栈内存中的,拷贝的话会新开辟一个新的内存空间,然后把原始值复制一份的新的内存中,两部分是独立的。
(图解准备中)

而引用数据类型就不同了。
创建引用数据类型时候,会将引用类型存放到堆内存中。 前面讲到了,我们不能直接访问引用类型。
js会在栈中存放一个指针,这个指针指向堆内存中的引用类型数据。
而直接进行复制的话其实复制的是指针。 这个指针存储的就是引用类型数据的地址。

函数传递参数

函数传递参数其实只有值传递, 基本类型传递就相当于基本类型的值复制了一份, 引用类型传递同引用类型复制一样,其实传递的是栈中存储的指针。
注意: 如果直接在函数中对传入的引用类型重新赋值,相当于把指针的副本指向了一个新的对象,这样是不会改变原对象的。 如果是添加属性的话,则是通过指针找到堆中存储的对象进行操作,这样会影响对象本身。

类型检查

前面说的typeof可以检查出基本数据类型,但是对于引用类型,无法进行判断。 不能知道是哪一个对象类型

检测类型 instanceof 构造函数
判断是不是某一个类型。
那它的原理是什么呢?

  1. function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
  2. var O = R.prototype; // 取 R 的显示原型
  3. L = L.__proto__; // 取 L 的隐式原型
  4. while (true) {
  5. if (L === null)
  6. return false;
  7. if (O === L) // 当 O 显式原型 严格等于 L隐式原型 时,返回true
  8. return true;
  9. L = L.__proto__;
  10. }
  11. }

其实就是顺着原型链不断的向上查找,如果检测类型的原型链上包含构造函数的原型,那么就是true
instanceof 从原型的角度,来判断某引用属于哪个构造函数,从而判定它的数据类型。

执行环境及作用域

执行环境定义了变量或者函数有权访问其他数据,决定了它们各自的行为。每个执行环境都有与之关联的变量对象。
环境中定义的所有变量和函数都在这个对象中。

全局环境是最外围的一个执行环境。 在web浏览器中表现为window对象。

垃圾收集

标记清除: 先给变量打标记,如果有用到的消除标记,然后删除有标记的变量。