「JavaScript」 基础知识要点及常考面试题(二)

var let const


什么是变量提升

先来看一段代码

console.log(a) // undefined
var a = 1

这里输出得是undefined, 但是并没有报错,证明变量a是可以被使用得。这就是变量提升
同样函数也一样可以被提升

console.log(a) // ƒ a() {}
function a() {}
var a = 1

但是对于let const来说,变量是不会产生变量提升,这点要非常注意

console.log(a) // ReferenceError: a is not defined
let a = 1

这种情况是运行不过去的
const 声明之后,变量不可改变
小结:

  • 函数提升优先于变量提升,函数提升会把整个函数挪到作用域顶部,变量提升只会把声明挪到作用域顶部
  • var 存在提升,我们能在声明之前使用。let、const 因为暂时性死区的原因,不能在声明前使用
  • var 在全局作用域下声明变量会导致变量挂载在 window 上,其他两者不会
  • let 和 const 作用基本一致,但是后者声明的变量不能再次赋值

原型继承和 Class继承

原型如何实现继承?Class 如何实现继承?Class 本质是什么?

  • 原型继承
    首先来看下最常见的一种继承方式,组合继承
function Parent(value) {
  this.val = value
}
Parent.prototype.getValue = function() {
  console.log(this.val)
}
function Child(value) {
  Parent.call(this, value)
}
Child.prototype = new Parent()  // 实现原型链到父类,完成可复用的效果

const child = new Child(1)

child.getValue() // 1
child instanceof Parent // true

上面是综合了原型链继承和构造函数继承的综合参考链接
原型链继承缺点:
》无法实现传参
》无法引用共享
构造函数继承却缺点:
》没有原型,无法实现复用(
组合继承:
》这种继承方式优点在于构造函数可以传参,不会与父类引用属性共享,可以复用父类的函数,但是也存在一个缺点就是在继承父类函数的时候调用了父类构造函数,导致子类的原型上多了不需要的父类属性,存在内存上的浪费。
寄生组合继承

function Parent(value) {
  this.val = value
}
Parent.prototype.getValue = function() {
  console.log(this.val)
}

function Child(value) {
  Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
  constructor: {
    value: Child,
    enumerable: false,
    writable: true,
    configurable: true
  }
})

const child = new Child(1)

child.getValue() // 1
child instanceof Parent // tr

这种方法就解决了,只是将父类得原型付给子类,免去了将父类多余得属性复值给子类

  • Class
    class 的本质其实还是函数,就是一个语法糖
    它实现继承的方式比较简单(java类似)
class Parent{
  construct(value) {
    this.vlaue = value  
  }  
  getValue() {
    console.log(value)
  }
}

class Child extends Parent {
  construct(value) {
    super(value) 
}
}

let child = new Child() ;
child.getValue(1); // 1
child instanceof Parent  // true

异步策略

回调函数

ajax(url, () => {
    // 处理逻辑
    ajax(url1, () => {
        // 处理逻辑
        ajax(url2, () => {
            // 处理逻辑
        })
    })
})

存在问题:
产生回调地狱,导致函数之间的耦合性很高

Generator的理解

es6提供的一种异步解决策略,控制函数执行,他有两个特征

  1. function 关键字与函数明之间有个*号
  2. 函数体内部使用yeild表达式
  3. generator内部会产生一个函数迭代器,只有通过next()方法来执行
function *foo(x) {
  let y = 2 * (yield (x + 1))
  let z = yield (y / 3)
  return (x + y + z)
}
let it = foo(5)
console.log(it.next())   // => {value: 6, done: false}
console.log(it.next(12)) // => {value: 8, done: false}
console.log(it.next(13)) // => {value: 42, done: true}

上面有个特点就是,yeild表达式本身没有返回值,或者说返回undefined。next方法上的参数可以作为yeild表达式的返回值。

Promise 的特点是什么,分别有什么优缺点?什么是 Promise 链?Promise 构造函数执行和 then 函数执行有什么区别?

  1. promise 有三种状态,pending, resolve, reject
  2. promise通过then的实现promise链
  3. promise构造函数式一开始就会执行,then得等待结果放回才执行
  4. 缺点: 比如无法取消 Promise,错误需要通过回调函数捕获。

async 及 await 的特点,它们的优点和缺点分别是什么?await 原理是什么?

  1. async 返回的是一个promise对象
  2. async能很好解决promise多个then导致难以区分的情况
  3. 原理: await 内部实现了 generator,其实 await 就是 generator 加上 Promise 的语法糖,且内部实现了自动执行 generator

setTimeout setInterval requestAnimationFrame

  1. setTimeout
    执行时间不定期,执行一次
  2. setInterval
    多次执行
  3. requestAnimatinFrame
    与setTimeout相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机。具体一点讲,如果屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,如果刷新率是75Hz,那么这个时间间隔就变成了1000/75=13.3ms,换句话说就是,requestAnimationFrame的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题。
    cancelAnimationFrame 用于取消定时器
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文为阮一峰大神的《ECMAScript 6 入门》的个人版提纯! babel babel负责将JS高级语法转义,...
    Devildi已被占用阅读 2,021评论 0 4
  • 弄懂js异步 讲异步之前,我们必须掌握一个基础知识-event-loop。 我们知道JavaScript的一大特点...
    DCbryant阅读 2,749评论 0 5
  • 面试题一:https://github.com/jimuyouyou/node-interview-questio...
    R_X阅读 1,648评论 0 5
  • 以下内容是我在学习和研究ES6时,对ES6的特性、重点和注意事项的提取、精练和总结,可以做为ES6特性的字典;在本...
    科研者阅读 3,150评论 2 9
  • 艰辛的人生 伟大的母爱 —祝贺母亲钱大妹80岁生日 今年农历10月19日,是我母亲钱大...
    多甜那个秋阅读 1,174评论 0 1