JavaScript复习速记-1

171 阅读5分钟

原型链

每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。

image.png

可以使用Object.getPrototypeOf()来获取某个对象的原型

继承

segmentfault.com/a/119000001… 继承方式

  1. 原型链继承
  • 直接让子代构造函数的prototype指向父代的父代
  • 无法传参,不够灵活
function Parent () {
    this.name = 'kevin';
}

Parent.prototype.getName = function () {
    console.log(this.name);
}

function Child () {

}

Child.prototype = new Parent();

var child1 = new Child();

console.log(child1.getName()) // kevin

2.借用构造函数继承

  • 借用了父类的构造函数,让子类被创建的时候执行父类的构造函数,使用call让该函数的this指向子类
  • 方法都在构造函数中定义,每一次都会执行Parent.call(this)来把所有方法创建一遍
function Parent () {
    this.names = ['kevin', 'daisy'];
}

function Child () {
    Parent.call(this);
}
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy"]

3.组合继承

  • 原型链继承和经典继承双剑合璧
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
    console.log(this.name)
}
function Child (name, age) {

    Parent.call(this, name);
    this.age = age;

}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
  • 缺点:在子类实例化和修改原型链的时候会执行两次父类的构造函数

优化:把上面的Child.prototype = new Parent()换成Object.create(Person.prototype),这样可以少使用一次构造函数,同时可以完成继承

//......和上面一致
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
  1. ES6中class的继承 懂的都懂,需要先调用super方法来调用父类的构造函数

作用域

作用域分为以下两种

  • 语法(静态)作用域:函数的作用域在定义的时候就决定了
  • 词法(动态)作用域:函数的作用在调用执行的时候才决定

执行上下文栈

github.com/mqyqingfeng…

  1. 初始的时候创建一个全局上下文栈,每遇到一个函数都会创建一个执行上下文压入栈中,每一个函数执行完毕之后都会被弹出当前的执行栈,注意只有函数被执行的时候才会被压入栈中,例如以下代码 代码一
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();

代码二

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

这两段代码的执行结果虽然相同(都是在一个地方被创建的,根据静态作用域,都会拿到外层的第一个scope),但是执行栈的调用方式是不一样的

ECStack.push(<checkscope> functionContext);
ECStack.push(<f> functionContext);
ECStack.pop();
ECStack.pop();
ECStack.push(<checkscope> functionContext);
ECStack.pop();
ECStack.push(<f> functionContext);
ECStack.pop();

变量对象

每个执行上下文都有三个重要属性

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this 变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。全局上下文中的变量对象就是全局对象

函数上下文

当进入执行上下文时,这时候还没有执行代码,

一个变量对象包括了以下元素

  1. 函数的所有形参 (如果是函数上下文)
    • 由名称和对应值组成的一个变量对象的属性被创建
    • 没有实参,属性值设为 undefined
  2. 函数声明
    • 由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
    • 如果变量对象已经存在相同名称的属性,则完全替换这个属性
  3. 变量声明
    • 由名称和对应值(undefined)组成一个变量对象的属性被创建;
    • 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性

在代码执行阶段,会顺序执行代码,根据代码,修改变量对象的值 总结一下上面的过程

  1. 全局上下文的变量对象初始化是全局对象
  2. 函数上下文的变量对象初始化只包括 Arguments 对象
  3. 在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值
  4. 在代码执行阶段,会再次修改变量对象的属性值

作用域链

函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,当函数被执行的时候会复制这个作用域链,然后生成了变量对象的时候,会把当前的活动对象压入到当前被复制的作用域链的顶端

闭包

闭包是指一个可以访问另外一个函数作用域中的变量的函数(定义在函数内部的函数) 经典题目

for(var i =0; i<5; i++) {
    setTimeout(function(){
     console.log(i);
    },1000);
}
// 为什么输出的全是5
// 同步代码for循环先执行,在异步代码执行的时候会在全局的AO对象中寻找,此时AO对象中的i为5

解决方式

for(var i =0; i<5; i++) {
    (funtion(i){
      setTimeout(function(){
     console.log(i);
    },1000)
    }
    )(i);
}
// 使用闭包,立即执行函数在执行的时候会产生执行上下文,把本次循环的i给保留下来,
// 里面的定时函数执行的时候会通过作用域链去找i,在外层立即执行函数中找到,成功输出

其他方式

  • 使用let
  • 传入setTimeout的第三个参数
  • ......

this的指向问题

juejin.cn/post/694602… 简单总结

  1. 箭头函数的this在定义的时候决定,无法修改,并且不能用作构造函数
  2. 使用new的时候,在构造函数内部里面的this都指向这个构造函数创建的新对象
  3. 通过bind和apply,call来改变this指向,其中bind中的this不会被修改(只有第一次有效),call单个传递,apply传递数组
  4. 在对象中谁调用的this就指向谁
  5. 直接调用this指向全局

常见手写题目

后续单独写一遍 mp.weixin.qq.com/s/sDZudDS2j…

垃圾回收机制

v8回收机制 新生代老生代 juejin.cn/post/684490… rust回收机制 所有权系统 kaisery.github.io/trpl-zh-cn/… c手动回收机制

数据类型以及浮点数精度

基础数据类型:number string boolean null undefined object Symbol BigInt 判断数据类型的方式: juejin.cn/post/691980…

事件循环

掌握node和浏览器环境中两种不同的事件循环

zhuanlan.zhihu.com/p/33058983

简单梳理一下node中事件循环的方式 juejin.cn/post/684490…