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 内存区域 #

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. 数据类型 #

类型
Boolean true或false
Null null
Undefined undefined
Number 数字
String 字符串
Symbol 符号类型

4. 执行上下文 #

4.1 如何存储 #

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 执行上下文分类 #

5.2 多个执行上下文 #

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 生命周期有两个阶段 #

6.2 变量对象 #

6.2.1 基本类型 #

console.log(a);
var a = 1;
```js

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


#### 6.2.2 变量提升
- 正常编写

```js
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 激活对象 #

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 全局上下文的变量对象 #

7. 作用域 #

7.1 作用域 #

function one() {
    var a = 1;
}
console.log(a);

7.2 作用域链 #

7.2.1 作用域链 #

function one() {
    var a = 1;
    function two() {
        var b = 2;
        function three() {
            var c = 3;
            console.log(a, b, c);
        }
        three();
    }
    two();
}
one(); 


// 1.创建全局上下文
var globalExecuteContextVO = { one: `()=>{var a = 1;}` }
var globalExecuteContext = {
    VO: globalExecuteContextVO,
    scopeChain: [globalExecuteContextVO]
}
var executeContextStack = [globalExecuteContext];
//2.执行one,创建one执行上下文
var oneExecuteContextVO = {
    a: 1,
    two: `()=>{var b = 2 ;}`
}
var oneExecuteContext = {
    VO: oneExecuteContextVO,
    scopeChain: [oneExecuteContextVO, globalExecuteContext.VO]
}
//2.执行two,创建two执行上下文
var twoExecuteContextVO = {
    b: 2,
    three: `()=>{var c = 3 ;}`
}
var twoExecuteContext = {
    VO: twoExecuteContextVO,
    scopeChain: [twoExecuteContextVO, oneExecuteContext.VO, globalExecuteContext.VO]
}
//3.执行three,创建three执行上下文
var threeExecuteContextVO = {
    c: 3
}
var threeExecuteContext = {
    VO: threeExecuteContextVO,
    scopeChain: [threeExecuteContextVO, twoExecuteContext.VO, oneExecuteContext.VO, globalExecuteContext.VO]
}
function getValue(varName) {
    for (let i = 0; i < threeExecuteContext.scopeChain.length; i++) {
        if (varName in threeExecuteContext.scopeChain[i]) {
            return threeExecuteContext.scopeChain[i][varName];
        }
    }
}
//console.log(a, b, c);
console.log(
    getValue('a'),
    getValue('b'),
    getValue('c'),
);

7.2.2 作用域链 #

function one() {
    var a = 1;
    function two() {
        console.log(a);
    }
    return two;
}
var a = 2;
var two = one();
two();

// 1.创建全局上下文
var globalExecuteContextVO = { one: `()=>{var a = 1;}`, a: undefined, two: undefined }
var globalExecuteContext = {
    VO: globalExecuteContextVO,
    scopeChain: [globalExecuteContextVO]
}
//2.开始执行
globalExecuteContextVO.a = 2;
//3.开始执行one
var oneExecuteContextVO = { a: undefined, two: `()=>{console.log(a)}` }
var oneExecuteContext = {
    VO: oneExecuteContextVO,
    scopeChain: [oneExecuteContextVO, globalExecuteContextVO]
}
oneExecuteContextVO.a = 1;
//4.给two赋值
globalExecuteContextVO.two = oneExecuteContextVO.two;
//5.执行two
var twoExecuteContextVO = {}
var twoExecuteContext = {
    VO: twoExecuteContextVO,
    //scopeChain是在创建此函数据的时候就决定了,跟在哪里执行无关
    scopeChain: [twoExecuteContextVO, oneExecuteContextVO, globalExecuteContextVO]
}

8. 闭包 #

8.1 闭包 #

function one() {
    var a = 1;
    var b = 2;
    function two() {
        var c = 3;
        debugger;
        console.log(a,c);
    }
    return two;
}
let two = one();
two();
function one() {
    var a = 1;
    var b = 2;
    function two() {
        debugger;
        console.log(a);
    }
    two();
}
one();

closure2

8.2 闭包优化 #

function one() {
    var a = 1;
    function two() {
        var b = 2;
        function three() {
            var c = 3;
            debugger;
            console.log(a, b, c);
        }
        three();
    }
    two();
}
one();
function one() {
    var a = 1;
    function two() {
        var b = 2;
        function three() {
            var c = 3;
            debugger;
            console.log(a, c);
        }
        three();
    }
    two();
}
one();

8.3 arguments #

function log(a, b) {
    debugger;
    console.log(a, b);
}
log(1, 2);

arguments

9. var和let #

9.1 ES5问题 #

9.1.1 全局变量 #

9.2 let #


'use strict'
function fn() {
    console.log("out");
}
(function () {
    if (false) {
        function fn() {
            console.log("in");
        }
    }
    fn();
}());

9.3 var&let&const #

9.3.1 暂时性死区 #

// 不存在变量提升
'use strict';
function func(){
    console.log(i);
    let i;
};
func(); // 报错

9.3.2 全局变量 #

9.3.3 题目 #

'use strict' 
var a = 1;
console.log(a);//1
{
    console.log(a);// f 1
    function a() {
        console.log(1);
    }
}
console.log(a);// f 1

10. this #

10.1 全局对象 #

var a=1;//声明绑定变量对象,但在全局环境中,变量对象就是全局对象
this.b=2;//this绑定全局对象
c=3;//赋值操作 隐式绑定

10.1 用点调用 #

let obj = {
    getName(){
        console.log(this);
    }
};
obj.getName();

10.2 直接调用 #

let obj = {
    getName(){
        console.log(this);
    }
};
let getName = obj.getName;
getName();

10.3 绑定事件 #

container.addEventListener('click',function(){
    console.log(this);
});

10.4 箭头函数 #

let fn = () => {
    console.log(this);
    console.log(arguments);//Uncaught ReferenceError: arguments is not defined
}
console.log(fn.prototype);//undefined
fn();
new fn();//VM4416:8 Uncaught TypeError: fn is not a constructor

10.5 构造函数 #

function fn(){

}
let obj = new fn();

10.6 call/apply/bind #

!function (proto) {
    function getContext(context) {
        context = context || window;
        var type = typeof context;
        if (['number', 'string', 'boolean', 'null'].includes(type)) {
            context = new context.constructor(context);
        }
        return context;
    }
    function call(context, ...args) {
        context = getContext(context);
        context._fn = this;
        let result = context._fn(...args);
        delete context._fn;
        return result;
    }
    function apply(context, args) {
        context = getContext(context);
        context._fn = this;
        let result = context._fn(...args);
        delete context._fn;
        return result;
    }

    function bind(context, ...bindArgs) {
        return (...args) => this.call(context, ...bindArgs, ...args);
    }
    proto.call = call;
    proto.apply = apply;
    proto.bind = bind;
}(Function.prototype)

11. 面向对象 #

11.1 原型链 #

11.1.1 一切皆对象 #

11.1.1.1 typeof #

console.log(typeof a);    // undefined
console.log(typeof 1);   // number
console.log(typeof 'zhufeng'); // string
console.log(typeof true);  // boolean
console.log(typeof Symbol('a'));  // symbol

console.log(typeof function () { });  //function

console.log(typeof [1, 2, 3]);  //object
console.log(typeof { name: 'zhufeng' });  //object
console.log(typeof null);  //object
console.log(typeof new Number(1));  //object

11.1.2 函数 #

let obj = new Object();
obj.name='zhufeng';
obj.age = 10;

11.1.3 隐式原型 #

11.1.3.1 proto #

objectprototype

object_prototypes

11.1.3.2 自定义函数的prototype #

customefuntionprototype

11.1.3.3 自定义函数 #
let add = new Function('a','b','return a+b');
console.log(add(1,2));

2functionprotype

3functionprotype

11.1.4 instanceof #

prototypechain

11.2 批量创建对象 #

function Person(name) {
    this.name = name;
}
Person.prototype.getName = function () {
    console.log(this.name);
}
let person = new Person('zhufeng');
person.getName();
Object.create = function (proto) {
    function F() {}
    F.prototype = proto;
    return new F();
};
function _new(clazz, ...args) {
    let _this = Object.create(clazz.prototype);
    let result = clazz.call(_this, ...args);
    if ((result != null && typeof result === 'object') || typeof result === 'function') {
        return result;
    }
    return _this;
}

11.3 继承 #

class Father {
    static staticFatherName = "FatherName"
    static staticGetFatherName = function () {
        console.log(Father.staticFatherName);
    }
    constructor(public name) {
        this.name = name;
    }
    getName() {
        console.log(this.name);
    }
}
class Child extends Father {
    static staticChildName = "ChildName"
    static staticGetChildName = function () {
        console.log(Child.staticChildName);
    }
    constructor(public name, public age) {
        super(name);
        this.age = age;
    }
    getAge() {
        console.log(this.age);
    }
}
let child = new Child('zhufeng', 10);
child.getName();
child.getAge();
Child.staticGetFatherName();
Child.staticGetChildName();
var _extends = (function () {
    var extendStatics = function (Child, Father) {
        return Object.setPrototypeOf(Child, Father);
    }
    return function (Child, Father) {
        extendStatics(Child, Father);
        function Temp() {
            this.constructor = Child;
        }
        Temp.prototype = Father.prototype;
        Child.prototype = new Temp();
    };
})();

var Father = (function () {
    function Father(name) {
        this.name = name;
    }
    Father.prototype.getName = function () {
        console.log(this.name);
    };
    Father.staticFatherName = "FatherName";
    Father.staticGetFatherName = function () {
        console.log(Father.staticFatherName);
    };
    return Father;
}());
//_super父类构造函数
var Child = (function (_super) {
    _extends(Child, _super);

    function Child(name, age) {
        _super.call(this, name);//继承父类的实例私有属性
        this.age = age;
        return this;
    }
    Child.prototype.getAge = function () {
        console.log(this.age);
    };
    Child.staticChildName = "ChildName";
    Child.staticGetChildName = function () {
        console.log(Child.staticChildName);
    };
    return Child;
}(Father));

let child = new Child('zhufeng', 10);
console.log(child);

child.getName();
child.getAge();
Child.staticGetFatherName();
Child.staticGetChildName();
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Father = /** @class */ (function () {
    function Father(name) {
        this.name = name;
        this.name = name;
    }
    Father.prototype.getName = function () {
        console.log(this.name);
    };
    Father.staticFatherName = "FatherName";
    Father.staticGetFatherName = function () {
        console.log(Father.staticFatherName);
    };
    return Father;
}());
var Child = /** @class */ (function (_super) {
    __extends(Child, _super);
    function Child(name, age) {
        var _this = _super.call(this, name) || this;
        _this.name = name;
        _this.age = age;
        _this.age = age;
        return _this;
    }
    Child.prototype.getAge = function () {
        console.log(this.age);
    };
    Child.staticChildName = "ChildName";
    Child.staticGetChildName = function () {
        console.log(Child.staticChildName);
    };
    return Child;
}(Father));
var child = new Child('zhufeng', 10);
child.getName();
child.getAge();
Child.staticGetFatherName();
Child.staticGetChildName();

11.3.6 原型链面试题 #

11.3.7 异步面试题 #

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
console.log('script start')
setTimeout(function () {
    console.log('setTimeout')
})
async1()
new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

12. ES6 #

12.1 词法环境 #

function fn() {
    var a = 1;
    let b = 2;
    {
        let b = 3;
        var c = 4;
        let d = 5;
        //console.log(a, b, c, d);//TODO
    }
    {
        let b = 6;
        let d = 7;
        //console.log(a, b, c, d);
    }
}
fn();

/**
 * 1.global编译阶段
 */

let globalEC = {
    this: globalThis,
    outer: null,//外部的执行上下文,词法作用域就是静态作用域,就是指作用域是由代码中函数声明的位置来决定的
    variableEnvironment: {
        fn() { console.log(a, b, c, d) }
    },
    lexicalEnvironment: {}
}


/**
 * 2.fn编译阶段
 */
let fnEC = {
    this: globalThis,
    outer: globalEC,
    variableEnvironment: { a: undefined, c: undefined },
    lexicalEnvironment: [{ b: undefined }]
}
/**
 * 3.编译代码块1
 */
fnEC.variableEnvironment.a = 1;
fnEC.lexicalEnvironment.b = 2;
fnEC.lexicalEnvironment.push({
    b: undefined,
    d: undefined
});
/**
 * 4.执行代码块1
 */

fnEC.lexicalEnvironment[1].b = 3;
fnEC.variableEnvironment.c = 4;
fnEC.lexicalEnvironment[1].d = 5;

console.log(getValue('a', fnEC), getValue('b', fnEC), getValue('c', fnEC), getValue('d', fnEC));
function getValue(name, ec) {
    for (let i = ec.lexicalEnvironment.length - 1; i >= 0; i--) {
        if (name in ec.lexicalEnvironment[i]) {
            return ec.lexicalEnvironment[i][name];
        }
    }
    let currentVariableEnvironment = ec.variableEnvironment;
    while (currentVariableEnvironment) {
        if (name in currentVariableEnvironment) {
            return currentVariableEnvironment[name];
        }
        currentVariableEnvironment = currentVariableEnvironment.outer;
    }
    return null;
}

/**
 * 5.编译代码块2
 */
fnEC.lexicalEnvironment.pop();
fnEC.lexicalEnvironment.push({
    b: undefined,
    d: undefined
});
/**
 * 5.执行代码块2
 */
fnEC.lexicalEnvironment[1].b = 6;
fnEC.lexicalEnvironment[1].d = 7;
console.log(getValue('a', fnEC), getValue('b', fnEC), getValue('c', fnEC), getValue('d', fnEC));

12.2 静态作用域 #

/* let name = 'zhufeng'
{
    //ReferenceError: Cannot access 'name' before initialization
    console.log(name)
    let name = 'jiagou'
} */

function two() {
    console.log(a);
}
function one() {
    var a = 2;
    two();
}
var a = 1;
one();

let globalEC = {
    a: 1,
    one() { },
    two() { }
}
let twoEC = {
    this: globalThis,
    outer: globalEC,
    variableEnvironment: { a: 1, two() { console.log(a) } } //出生的地方
}
var twoEc = { outer: globalEC };
console.log(twoEC.outer.a);

12.3 闭包 #

function one() {
    var a = 1;
    var name = 'one';
    function two() {
        var b = 2;
        var name = 'two';
        function three() {
            var c = 3;
            var name = 'three';
            return () => console.log(a, b, c);

        }
        return three();
    }
    return two();
}
var fn = one();
fn();
let globalEC = {
    this: globalThis,
    outer: null,
    variableEnvironment: { one() { } }
}
let oneEC = {
    this: globalThis,
    outer: globalEC.variableEnvironment,
    variableEnvironment: { a: 1, two() { }, name: 'one' }
}
let twoEC = {
    this: globalThis,
    outer: oneEC.variableEnvironment,
    variableEnvironment: { b: 2, three() { }, name: 'two' }
}
let threeEC = {
    this: globalThis,
    outer: twoEC.variableEnvironment,
    variableEnvironment: { c: 3, name: 'three' }
}
let fnEC = {
    this: globalThis,
    outer: globalEC,
    //Closure(three) Closure(two) Closure(one)
    closures: [{ a: 1 }, { b: 2 }, { c: 3 }],
    variableEnvironment: { c: 3 }
}
console.log(getValue('a', fnEC), getValue('b', fnEC), getValue('c', fnEC));

function getValue(name, ec) {
    for (let i = ec.closures.length - 1; i >= 0; i--) {
        if (name in ec.closures[i]) {
            return ec.closures[i][name];
        }
    }
    let currentVariableEnvironment = ec.variableEnvironment;
    while (currentVariableEnvironment) {
        if (name in currentVariableEnvironment) {
            return currentVariableEnvironment[name];
        }
        currentVariableEnvironment = currentVariableEnvironment.outer;
    }
    return null;
}