吃透JavaScript核心——变量、数据类型、深浅拷贝、堆和栈

202 阅读10分钟

1. 初识Js

1.1 浏览器执行JS

浏览器分成两部分:渲染引擎JS引擎

渲染引擎:用来解析HTML和CSS,俗称内核,比如Chrome浏览器的blink,老版本的webkit。

JS引擎:也称为JS解释器。用来读取网页中的JS代码,对其处理后运行,比如Chrome浏览器的V8。

浏览器本身不会执行JS代码,而是通过JS引擎执行JS代码。JS引擎执行代码时逐行解释每一句源码,转换为机器语言然后由计算机去执行,所以JS归为脚本语言,会逐行解释执行。

1.2 JS的组成

  • JS由三部分组成:
    • ECMAScript:Javascript语法
    • DOM:页面文档对象模型
    • BOM:浏览器对象模型

ECMAScript规定了JS的编程语法和基础知识核心,是所有浏览器厂商共同遵守的一套JS语法工业标准

DOM(Document Object Model)——文档对象模型,是W3C组织推荐的处理可扩展标记语言的标准编程接口,通过DOM提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色...)

BOM(Browser Object Model)——浏览器对象模型,提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过DOM可以操作浏览器窗口(弹出框、控制浏览器跳转、获取分辨率)

1.3 JS三种书写位置

行内式内嵌式外部
在HTML中推荐使用双引号,JS中推荐使用单引号。可以将多行JS代码写到script标签中。引用外部JS文件的script标签中间不可以写代码。
特殊情况下使用是JS学习时常用的方式适用于JS代码量大的情况

1.4 JS注释与输入输出语句

JS注释

单行注释多行注释
///**/
ctrl+/ctrl+shift+/

JS输入输出语句

方法说明归属
alert(msg)浏览器弹出警示框浏览器
console.log(msg)浏览器控制台打印输出信息浏览器
prompt(info)浏览器弹出输入框,用户可以输入,取过来的值时字符型的浏览器

1.5 解释型语言和编译型语言

  • 程序语言翻译成机器语言的工具叫翻译器
  • 翻译器翻译的方式有两种:编译解释,区别在于翻译的时间点不同。
  • 编译器是在代码执行之前进行编译,生成中间代码。
  • 解释器是在运行时进行及时解释,并立即执行。 image.png

1.6 标识符、关键字、保留字

  • 标识符:开发者为变量、属性、函数、参数取的名字。标识符不能是关键字或保留字。
  • 关键字:JS本身已经使用了的字,不能再用它们充当变量名、方法名。
    breakcasecatchcontinuedefaultdeletedoelsefinallyforfunctionifininstanceofnewreturnswitchthisthrowtrytypeofvarvoidwhilewith
    
  • 保留字:预留的“关键字”,不能使用它们当变量名。
    booleanbytecharclassconst、debugger、doubleenumexport、extends、fimal、floatgoto、implements、importint、interface、long、mative、package、privateprotectedpublicshortstatic、super、synchronized、throws、transient、volatile
    

2. JS变量

2.1 变量概述与使用

通俗:变量是用于存放数据的容器,我们通过变量名获取数据,甚至数据可以修改。

变量的本质:变量是程序在内存中申请的一块用来存放数据的空间。

简单案例:变量的使用

1.弹出一个输入框,提示用户输入姓名,
2.弹出一个对话框,输出用户刚才输入的姓名。
<script>
    var name=prompt('请输入您的姓名');
    alert(name);
<script/>

2.2 变量语法扩展

更新变量:一个变量被重新赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。

声明多个变量

var age=18,
    address='Beijing',
    gz=2000;

声明变量的多个情况

//1. 只声明 不赋值
var sex;
console.log(sex);//undefined

//2. 不声明 不赋值 直接使用
console.log(tel);//error: tel is not defined

//3.不声明 只赋值
qq=110;
console.log(qq);//110

2.3 变量命名规范

  • 由字母、数字、下划线、美元符号($)组成。
  • 严格区分大小写。
  • 不能以数字开头。
  • 不能用关键字(var、for、if...)和保留字。
  • 变量名必须有意义。
  • 遵守驼峰命名法。首字母小写,后面单词的首字母要大写。
  • 尽量不要用name作为变量名称。

2.4 变量交换案例

    var temp;
    var apple1='青苹果';
    var apple2='红苹果';
    temp=apple1;
    apple1=apple2;
    apple2=temp;

2.5 小结

QA
为什么需要变量?因为一些数据需要保存,所以需要变量
变量是什么?变量就是一个容器,用来存放数据,方便以后就我们使用数据
变量的本质是什么?变量是内存中的一块空间,用来存储数据
变量怎么使用?声明变量,然后赋值,声明变量的本质是去内存申请空间。
什么是变量的初始化?声明变量并赋值。

3. 数据类型

3.1 数据类型简介

为什么需要数据类型

在计算机中,不同数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。

数据类型的可变化性

Javascript是一种弱类型或者说是动态语言,变量的数据类型是可以变化的。Javascript变量数据类型是在程序运行过程中,JS引擎根据=右边的值来确定的。

3.2 数据类型分类

JS把数据类型分为两类:

简单数据类型 (Number, String, Boolean, Undefined, Null, symbol(代表创建后独一无二且不可变的数据类型))又叫做基本数据类型、值类型,其中基本包装类型:Boolean, Number, String。

复杂数据类型 (Object、Array数组、Function)又叫做引用类型,在存储时变量中存储的仅仅是地址(引用)。通过new关键字创建的对象(系统对象、自定义对象)

  • 特殊:简单数据类型null返回的是一个空的对象 object。如果有个变量以后打算存储对象,暂时没想好放啥,这个时候就给null。
  • 访问一个没有被赋值过的变量(属性),返回的是undefined

3.2.1 简单数据类型

简单数据类型说明默认值
Number数字型,包含整型值和浮点型值0
Boolean布尔值类型,加法运算:true-1,false-0false
String字符串型,引号可以是'' "" 推荐单引号""
Undefinedvar a;声明了变量a但是没有给值,此时a=undefinedundefined
Nullvar a=null; 声明了变量a为空值null

3.2.2 数字型

  • 进制:八进制前加0,十六进制前加0x。
  • 范围:Number.MIN_VALUE Number.MAX_VALUE
  • 三个特殊值:无穷Infinity``-Infinity非数字NaN
  • isNaN()判断非数字,并返回一个值。

3.2.3 字符串型

  • 引号嵌套:外双内单,外单内双。

  • 转义字符:

    转义符解释
    \n换行
    \\斜杠\
    \'单引号
    \"双引号
    \ttab缩进
    \b空格
  • 字符串长度:str.length

  • 字符串拼接:字符串+任何类型=拼接后的新字符串,通常将字符串和变量来拼接。

    var variable=undefined;
    console.log(variable+'you');//undefinedyou
    console.log(variable+1);//NaN
    var sapce=null;
    console.log(sapce+'you');//nullyou
    console.log(sapce+1);//1
    
  • 字符串与别的类型相加会转换为字符串,+也可用于字符串转数字

    console.log(1 + "1", null + " is not " + undefined);//11 null is not undefined
    console.log(+'1', +(1 + '1'), +'不是一个数字');//1 11 NaN
    // NaN: Not-A-Number
    console.log(typeof NaN);//number NaN表示数字运算出错的结果处理。
    

3.3 数据类型相关方法和知识点

获取变量的数据类型typeof

var num=10;
console.log(typeof num);//number
var str='s';
console.log(typeof s);//string
var timer=null;
console.log(typeof timer);//object !!!!!!

字面量

表示如何表达这个值

  • 数字字面量:8,9,10
  • 字符串字面量:'前端'
  • 布尔字面量:true, false

数据类型转换

  • 转换为字符串

    方式说明案例
    toStringvar num=1; alert(num.toString());
    String()强制转换var num=1; alert(String(num));
    加号拼接字符串隐式转换,和字符串拼接的结果都是字符串var num=1; alert(num+'');
  • 转换为数字型

    方式说明案例
    parseInt(string)string类型→整数数值parseInt('78')
    parseFloat(string)string类型→浮点数数值parseFloat('34')
    Number()强制转换string类型→数值型Number('12')
    js隐式转换(- * /)利用算术运算隐式转换为数值型'12'-0
  • 转换为布尔型

    Boolean()函数,将其他类型转化成布尔型。

    • 代表空、否定的值会被转换为false,如 0 NaN null undefined
    • 其余值都会被转化为true。

4.深入理解简单数据类型和复杂数据类型的区别

4.1 两种数据类型的区别

存放位置不同

  • 基本类型的变量会保存在栈内存中,如果在一个函数中声明一个基本类型的变量,这个变量在函数执行结束后会自动销毁
  • 引用类型的变量名会保存在栈内存中,但是变量值会存储在堆内存中,引用类型的变量不会自动销毁,当没有引用变量引用它时,系统的垃圾回收机制会回收它。 image.png

深拷贝与浅拷贝 赋值不同

  • 基本类型的赋值相当于深拷贝,赋值后相当于又开辟了一个内存空间,如下所示:
    let a = 100;
    let b = a;
    b = 101;
    console.log(a, b); // 100 101  a 的值改变时并不影响 b 的值。
    
  • 引用类型的赋值是浅拷贝,当我们对对象进行操作时,其实操作的只是对象的引用,如下所示:
    let obj = {
      name: "你好",
    };
    let obj2 = obj;
    obj2.name = "你好世界";
    console.log(obj.name, obj2.name); //你好世界 你好世界,把 obj 的值赋值给 obj2,当 obj2 的值改变时,obj 的值也被改变。
    

4.2 实现一个对象的深拷贝

JSON.stringify 和 JSON.parse  API

let obj = {
  name: "你好",
};
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.name = "你好世界";

console.log(obj.name, obj2.name); // 你好 你好世界
  • JSON.stringify() : 将 JavaScript 值转换为 JSON 字符串;
  • JSON.parse() :将 JSON 字符串转化为 JavaScript 对象
  • 缺点:当 obj 里面有函数或 undefined 就会失效。
    let obj = {
      fn: function () {
        console.log("你好世界");
      },
      name: undefined,
    };
    
    let obj2 = JSON.parse(JSON.stringify(obj));
    console.log(obj2); //{}空对象
    

递归

递归遍历对象的每个属性,分别赋值到一个新对象去。

function deep(obj) {
  let oo = {};
  for (const key in obj) {
    if (typeof obj[key] === "object") {
      oo[key] = deep(obj[key]);
    } else {
      oo[key] = obj[key];
    }
  }
  return oo;
}

4.3 堆和栈

堆栈空间分配区别:

  • 栈(操作系统):由OS自动分配释放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;简单数据类型存到栈里。
  • 堆(操作系统):存储复杂数据类型(对象),一般由程序员分配释放,若程序员不释放则由垃圾回收机制回收;复杂数据类型存到堆里。
  • :堆栈是抽象概念。JS里没有堆栈的概念,通过堆栈的方式,更容易理解代码的执行方式。 image.png

利用堆栈理解:简单数据类型的传参

  • 函数的形参可以看做一个变量,把一个值类型变量传给函数的形参,相当于把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部变量。 image.png

利用堆栈理解:复杂数据类型的传参

  • 当我们把引用类型变量传递给形参时,其实是把变量在栈空间里保存的堆地址赋值给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。

    function Person (name) { 
        this.name = name;
    }
    
    function f1(x) {//x=P
        console.log(x.name); // 2.刘德华
        x.name =“张学友”;
        console.log (x.name);// 3.张学友
    }
    
    var p = new Person("刘德华");
    console.log (p.name); // 1. 刘德华
    f1(p);
    console. log (p.name);// 4. 张学友
    

    image.png