深入浅出javaScript类型(一)

604 阅读7分钟

本文已参与『新人创作礼』活动,一起开启掘金创作之路

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

介绍

官方解释:javascript(简称"JS")是一种具有函数优先的轻量级,解释性或即时编译型的编程语言javaScript是2012年,所有浏览器都完整的支持ECMScript5.1,旧版本的浏览器至少支持ECMAScript 3 标准。ECMA国际组织发布了ECMAScript的第六版,该版本正式名称为ECMAScript 2015,但通常被称为es6或者ES2015

1.计算机栈

  • 者,存储货物或供旅客住宿的地方,可引申为仓库。计算机领域里,就是指数据暂时存储的地方,所以才有进栈、出栈的说法。

1.1 数据结构中的栈

  • 栈是一组数据的存放方式,特点是先进后出,后进先出

instack

outstack

方法名操作
push()添加新元素到栈顶
pop()移除栈顶的元素,同时返回被移除的元素
class Stack {
    private items: number[] = [];
    // 添加元素到栈顶,也就是栈的末尾
    push(element: number) {
        this.items.push(element);
    }
    // 栈的后进先出原则,从栈顶出栈
    pop(): number {
        return this.items.pop();
    }
}

let stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.pop());

1.2 代码的运行方式

  • 表示函数的一层层调用
function one() {
    function two() {
        function three() {
            debugger;
        }
        three();
    }
    two();
}
one();

callbackstack

1.3 内存区域

  • 栈也是是存放数据的一种内存区域

  • 程序运行的时候,需要内存空间存放数据。一般来说,系统会划分出两种不同的内存空间:一种叫做stack(栈),另一种叫做heap(堆)

    • stack是有结构的,每个区块按照一定次序存放,可以明确知道每个区块的大小
    • heap是没有结构的,数据可以任意存放。因此,stack的寻址速度要快于heap
  • 只要是局部的、占用空间确定的数据,一般都存放在stack里面,否则就放在heap里面,所有的对象都存放在heap

function task() {
    var a = 1;
    var b = 2;
    var c = {
        name: 'zhufeng',
        age: 10
    }
}
task();

memoryposition

2. 队列

  • 队列是一种操作受限制的线性表
  • 特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作
  • 进行插入操作的端称为队尾,进行删除操作的端称为队头
  • 因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出线性表

inqueue.png

outqueue.png

class Queue {
    private items: number[] = [];
    // 添加元素到栈顶,也就是栈的末尾
    enqueue(element: number) {
        this.items.push(element);
    }
    dequeue() {
        return this.items.shift();
    }
}

let queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
console.log(queue.dequeue());//1

3. 数据类型

  • JS中有七种基本数据类型

    • 六种基本数据类型 Boolean Null Undefined Number String Symbol
    • 一种引用类型 object {} [] /^$/ new Date() Math
类型
Booleantrue或false
Nullnull
Undefinedundefined
Number数字
String字符串
Symbol符号类型

4. 执行上下文

4.1 如何存储

  • 当函数运行时,会创建一个执行环境,这个执行环境就叫执行上下文(Execution Context)
  • 执行上下文中会创建一个对象叫作变量对象(Value Object),基础数据类型都保存在变量对象中
  • 引用数据类型的值保存在堆里,我们通过操作对象的引用地址来操作对象
function task(){
    var a = 1;
    var b = {
        name:'zhufeng'
    }
    var c = [1,2,3];
}
let ExecuteContext = {
    VO:{
        a:1,
        b:'XO1',
        c:'XA1'
    }
};

valueobject

4.2 如何复制

4.2.1 基本数据

  • 基本数据类型复制的是值本身
var a = 1;
var b = a;
b = 2;
console.log(a);
var ExecuteContext = {
    VO: { a: 1 }
};

ExecuteContext.VO.b = ExecuteContext.VO.a;
ExecuteContext.VO.b = 2;
console.log(ExecuteContext.VO.a);

changebasictype

4.2.2 引用数据

  • 引用数据类型复制的是引用地址指针
var m = { a: 1, b: 2 };
var n = m;
n.a = 10;
console.log(m.a);
var ExecuteContext = {
    VO: { m: { a: 1, b: 2 } }
};

ExecuteContext.VO.b = ExecuteContext.VO.a;
ExecuteContext.VO.a = 10;
console.log(ExecuteContext.VO.a);

copyrefer

5. 多个执行上下文栈

5.1 执行上下文分类

  • JS代码在执行的时候会进入一个执行上下文,可以理解为当前代码的运行环境

  • JS中运行环境主要分为全局执行上下文环境和函数环执行上下文环境

    • 全局执行上下文只有一个,在客户端中一般由浏览器创建,也就是我们熟知的window对象,我们能通过this直接访问到它
    • window对象还是var声明的全局变量的载体。我们通过var创建的全局对象,都可以通过window直接访问

5.2 多个执行上下文

  • 在JS执行过程会产出多个执行上下文,JS引擎会有栈来管理这些执行上下文
  • 执行上下文栈(下文简称执行栈)也叫调用栈,执行栈用于存储代码执行期间创建的所有上下文,具有LIFOLast In First Out后进先出,也就是先进后出)的特性
  • 栈底永远是全局上下文,栈顶为当前正在执行的上下文
  • 当开启一个函数执行时会生成一个新的执行上下文并放入调用栈,执行完毕后会自动出栈
function one() {
    var a = 1;
    debugger;
    function two() {
        var b = 1;
        debugger;
        function three() {
            var c = 1;
            debugger;
        }
        three();
        debugger;
    }
    two();
    debugger;
}
one();
var globalExecuteContext = {
    VO: { setTimeout: 'setTimeout' }
}
var executeContextStack = [globalExecuteContext];
var oneExecuteContext = {
    VO: { a: 1 }
}
executeContextStack.push(oneExecuteContext);
var twoExecuteContext = {
    VO: { b: 2 }
}
executeContextStack.push(twoExecuteContext);
var threeExecuteContext = {
    VO: { c: 3 }
}
executeContextStack.push(threeExecuteContext);
console.log(executeContextStack);

executeContextStack.pop();
executeContextStack.pop();
executeContextStack.pop();

6. 执行上下文生命周期

6.1 生命周期有两个阶段

  • 一个新的执行上下文的生命周期有两个阶段

    • 创建阶段

      • 创建变量对象
      • 确定作用域链
      • 确定this指向
    • 执行阶段

      • 变量赋值
      • 函数赋值
      • 代码执行

6.2 变量对象

  • 变量对象会保存变量声明(var)、函数参数(arguments)、函数定义(function)

    • 变量对象会首先获得函数的参数变量和值
    • 获取所有用function进行的函数声明,函数名为变量对象的属性名,值为函数对象,如果属性已经存在,值会用新值覆盖
    • 再依次所有的var关键字进行的变量声明,每找到一个变量声明,就会在变量对象上建一个属性,值为undefined,如果变量名已经存在,则会跳过,并不会修改原属性值,let声明的变量并不会在此阶段进行处理
  • 函数声明优先级更高,同名的函数会覆盖函数和变量,但同名var变量并不会覆盖函数.执行阶段重新赋值可以改变原有的值

6.2.1 基本类型

console.log(a);
var a = 1;
var a = undefined;//变量提升
console.log(a);
a = 1;

6.2.2 变量提升

  • 正常编写
var a = 1;
function fn(m) { console.log('fn'); }
function fn(m) { console.log('new_fn'); }
function a() { console.log('fn_a'); }
console.log(a);
fn(1);
var fn = 'var_fn';
console.log(fn);
//1
//new_fn
//var_fn
  • 真正执行
// 创建阶段
function fn(m) { console.log('fn'); }
function fn(m) { console.log('new_fn'); }
function a() { console.log('fn_a'); }
var a = undefined;
var fn = undefined;
//执行阶段
a = 1;
console.log(a);
fn();
fn = 'var_fn';
console.log(fn);
  • 上下文
// 创建阶段
var globalEC = {
    VO: {
        ...arguments,
        a: () => { console.log('fn_a'); },
        fn: () => { console.log('new_fn'); }
    }
}
var ECStack = [globalEC];
//执行阶段
globalEC.VO.a = 1;
console.log(globalEC.VO.a);
globalEC.VO.fn();
globalEC.VO.fn = 'var_fn';
console.log(globalEC.VO.fn);

6.2.3 激活对象

  • 在函数的调用栈中,如果当前执行上下文处于函数调用栈的顶端,则意味着当前上下文处于激活状态,此时变量对象称为活动对象(AO,Activation Object) VO=>AO
  • 活动变量包含变量对象所有的属性,并有包含this指针
function one(m) {
    function two() {
        console.log('two');
    }
}
one(1);

//执行阶段 VO=>AO
let VO = AO = {
    m:1,
    two: () => { console.log('two'); },

}
let oneEC={
    VO,
    this: window,
    scopeChain:[VO,globalVO]
}

6.2.4 全局上下文的变量对象

  • 在浏览器里,全局对象为window
  • 全局上下文的变量对象为window,而且这个变量对象不能激活变成活动对象
  • 只在窗口打开,全局上下文会一直存在,所有的上下文都可以直接访问全局上下文变量对象上的属性
  • 只有全局上下文的变量对象允许通过VO的属性名称来间接访问,在函数上下文中是不能直接访问VO对象的
  • 未进入执行阶段前,变量对象中的属性都不能访问!但是进入到执行阶段之后,变量对象转变成了活动对象,里面的属性都能被访问了,对于函数上下文来讲,活动对象与变量对象其实都是同一个对象,只是处于执行上下文的不同生命周期

原型链面试题

   function Foo() {
     getName = function () {
         console.log(1);
     }
     return this;
   }
   Foo.getName = function () {
     console.log(2);
   }
   Foo.prototype.getName = function () {
     console.log(3);
   }
   var getName = function () {
     console.log(4);
   }
   function getName() {
     console.log(5);
   }
   Foo.getName();
   getName();
   Foo().getName();
   getName();//1
   new Foo.getName();
   new Foo().getName();
   new new Foo().getName();

知道答案或者文章有遗漏地方的小伙伴可以在评论区评论哦~~