《前端口试手记》之JavaScript基础知识梳理(下)

👇 内容速览 👇

  • 完成ES5继承的4种要领
  • 原型和原型链
  • 作用域和作用域链
  • Event Loop
  • 实行上下文
  • 闭包的明白和剖析

🔍检察悉数教程 / 浏览原文🔍

ES5继承

题目:ES5中经常运用继承要领。

要领一:绑定组织函数

瑕玷:不能继承父类原型要领/属性

function Animal(){
  this.species = '动物'
}

function Cat(){
  // 实行父类的组织要领, 上下文为实例对象
  Animal.apply(this, arguments)
}


/**
 * 测试代码
 */
var cat = new Cat()
console.log(cat.species) // output: 动物

要领二:原型链继承

瑕玷:没法向父类组织函数中通报参数;子类原型链上定义的要领有先后递次题目。

注重:js中交流原型链,均须要修复prototype.constructor指向题目。

function Animal(species){
  this.species = species
}
Animal.prototype.func = function(){
  console.log('Animal')
}

function Cat(){}
/**
 * func要领是无效的, 因为背面原型链被从新指向了Animal实例
 */
Cat.prototype.func = function() {
  console.log('Cat')
}

Cat.prototype = new Animal()
Cat.prototype.constructor = Cat // 修复: 将Cat.prototype.constructor从新指向自身

/**
 * 测试代码
 */
var cat = new Cat()
cat.func() // output: Animal
console.log(cat.species) // undefined

要领3:组合继承

连系绑定组织函数和原型链继承2种体式格局,瑕玷是:挪用了2次父类的组织函数。

function Animal(species){
  this.species = species
}
Animal.prototype.func = function(){
  console.log('Animal')
}

function Cat(){
  Animal.apply(this, arguments)
}

Cat.prototype = new Animal()
Cat.prototype.constructor = Cat 

/**
 * 测试代码
 */
var cat = new Cat('cat')
cat.func() // output: Animal
console.log(cat.species) // output: cat

要领4:寄生组合继承

改进了组合继承的瑕玷,只须要挪用1次父类的组织函数。它是援用范例最理想的继承范式。(引自:《JavaScript高等程序设想》)

/**
 * 寄生组合继承的中心代码
 * @param {Function} sub 子类
 * @param {Function} parent 父类
 */
function inheritPrototype(sub, parent) {
  // 拿到父类的原型
  var prototype = Object(parent.prototype) 
  // 转变constructor指向
  prototype.constructor = sub
  // 父类原型赋给子类
  sub.prototype = prototype
}

function Animal(species){
  this.species = species
}
Animal.prototype.func = function(){
  console.log('Animal')
}

function Cat(){
  Animal.apply(this, arguments) // 只挪用了1次组织函数
}

inheritPrototype(Cat, Animal)

/**
 * 测试代码
 */

var cat = new Cat('cat')
cat.func() // output: Animal
console.log(cat.species) // output: cat

原型和原型链

  • 一切的援用范例(数组、对象、函数),都有一个__proto__属性,属性值是一个平常的对象
  • 一切的函数,都有一个prototype属性,属性值也是一个平常的对象
  • 一切的援用范例(数组、对象、函数),__proto__属性值指向它的组织函数的prototype属性值

:ES6的箭头函数没有prototype属性,然则有__proto__属性。

const obj = {};
// 援用范例的 __proto__ 属性值指向它的组织函数的 prototype 属性值
console.log(obj.__proto__ === Object.prototype); // output: true

原型

题目:怎样JS中的原型?

// 组织函数
function Foo(name, age) {
    this.name = name
}
Foo.prototype.alertName = function () {
    alert(this.name)
}
// 建立示例
var f = new Foo('zhangsan')
f.printName = function () {
    console.log(this.name)
}
// 测试
f.printName()
f.alertName()

然则实行alertName时发生了什么?这里再记着一个重点 当试图获得一个对象的某个属性时,假如这个对象自身没有这个属性,那末会去它的__proto__(即它的组织函数的prototype)中寻觅,因而f.alertName就会找到Foo.prototype.alertName

原型链

题目:怎样JS中的原型链?

以上一题为基本,假如挪用f.toString()

  1. f试图从__proto__中寻觅(即Foo.prototype),照样没找到toString()要领。
  2. 继承向上找,从f.__proto__.__proto__中寻觅(即Foo.prototype.__proto__中)。因为Foo.prototype就是一个平常对象,因而Foo.prototype.__proto__ = Object.prototype
  3. 终究对应到了Object.prototype.toString

这是对深度遍历的历程,寻觅的根据就是一个链式构造,所以叫做“原型链”。

作用域和作用域链

题目:怎样明白 JS 的作用域和作用域链。

①作用域

ES5有”全局作用域“和”函数作用域“。ES6的letconst使得JS用了”块级作用域“。

为了处置惩罚ES5的全局争执,平常都是闭包编写:(function(){ ... })()。将变量封装到函数作用域。

②作用域链

当前作用域没有找到定义,继承向父级作用域寻觅,直至全局作用域。这类层级关联,就是作用域链

Event Loop

单线程

题目:解说下面代码的实行历程和效果。

var a = true;
setTimeout(function(){
    a = false;
}, 100)
while(a){
    console.log('while实行了')
}

这段代码会一向实行而且输出”while…”。JS是单线程的,先跑实行栈里的同步使命,然后再跑使命行列的异步使命

实行栈和使命行列

题目:说一下JS的Event Loop。

简朴总结以下:

  1. JS是单线程的,其上面的一切使命都是在两个处所实行:实行栈和使命行列。前者是寄存同步使命;后者是异步使命有效果后,就在个中放入一个事宜。
  2. 当实行栈的使命都实行完了(栈空),js会读取使命行列,并将能够实行的使命从使命行列丢到实行栈中实行。
  3. 这个历程是轮回举行,所以称作Loop

实行上下文

题目:诠释下“全局实行上下文“和“函数实行上下文”。

全局实行上下文

剖析JS时刻,建立一个 全局实行上下文 环境。把代码中行将实行的(内部函数的不算,因为你不知道函数什么时候实行)变量、函数声明都拿出来。未赋值的变量就是undefined

下面这段代码输出:undefined;而不是抛出Error。因为在剖析JS的时刻,变量a已存入了全局实行上下文中了。

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

函数实行上下文

和全局实行上下文差不多,然则多了thisarguments和参数。

在JS中,this是关键字,它作为内置变量,其值是在实行的时刻肯定(不是定义的时刻肯定)

闭包的明白和剖析

题目:诠释下js的闭包

直接上MDN的诠释:闭包是函数声明该函数的词法环境的组合。

而在JavaScript中,函数是被作为一级对象运用的,它既能够本看成值返回,还能够看成参数通报。明白了:“Js中的函数运行在它们被定义的作用域,而不是它们被实行的作用域”(摘自《JavaScript言语精炼》) 这句话即可。

题目:闭包优瑕玷

闭包封住了变量作用域,有效地防备了全局污染;但同时,它也存在内存走漏的风险:

  • 在浏览器端能够经由过程强迫革新处置惩罚,对用户体验影响不大
  • 在服务端,因为node的内存限定和积累效应,可能会形成历程退出以至服务器沓机

处置惩罚要领是显式对外暴露一个接口,特地用以清算变量:

function mockData() {
  const mem = {}
  
  return {
    clear: () => mem = null, // 显式暴露清算接口

    get: (page) => {
      if(page in mem) {
        return mem[page]
      }
      mem[page] = Math.random()
    }
  }
}

更多系列教程

⭐在GitHub上珍藏/定阅⭐

《前端学问系统》

《设想形式手册》

《Webpack4渐进式教程》

⭐在GitHub上珍藏/定阅⭐

    原文作者:心谭
    原文地址: https://segmentfault.com/a/1190000018751529
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞