前端开发必会的JS硬知识(二)

2,781 阅读6分钟

文/小魔女

本文简介

  • 前端开发必会的JS硬知识的第二篇文
  • Javascript是前端必不可少的,它涵盖的内容很多。
  • 本系列将把前端开发得掌握的所有知识点整理并分享给大家,本文将围绕this、原型链与继承展开。
  • 分享小魔女的音乐🎵

this

this是Javascript语言的一个关键字。 随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,谁调用,this就指向谁

this的指向(4种)

  1. 在全局作用域或者普通函数中,this指向全局对象window

2.方法调用中,谁调用指向谁

3.在构造函数或者构造函数原型对象中,this指向构造函数的实例

4. 箭头函数指向外层作用域的 this

es6中的箭头函数与普通函数有什么区别?

  1. 普通函数this指向调用者,箭头函数的this指向定义的环境(bind\call\apply都不能改变this的指向)
  2. 箭头函数没有arguments,没有函数体,需要使用...rest代替
  3. 箭头函数不能作为构造函数,不能new
  4. 箭头函数不能使用yield命令,不能作为generator函数
  5. 箭头函数没有原型属性
  6. 变量提升:在js的内存机制里,function的级别最高。而箭头函数定义函数是,需要var、let、const等关键字,而只有var能进行变量提升,所以箭头函数定义一定要在调用之前

bind、call和apply有什么区别?

  • 同:bind、call和apply的第一个参数都是this
  • 异:
    • call,传参方式是列举
    • apply,传参方式是数组
    • 重点: call,apply会指向函数(调用),而bind只会改变this,不会指向函数(会返回函数)

练兵场

实现bind

什么是原型对象?什么是原型链?

  • 原型对象:

    • 所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
    • 所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
    • 所有引用类型的__proto__属性都指向它构造函数的prototype 
  • 原型链:
    • 当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即是构造函数的prototype,如果还没有找到就会在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们成为原型链。
    • 一直往上查找,直到到null还没有找到,则返回undefined
    • Object.prototype.**proto** === null
    • 所有从原型或更高级原型中得到、执行的方法,其中的this在执行时,执行当前这个触发事件的执行对象。

如何通过一个实例访问它的构造函数及原型对象?

注:通过class定义的类 和通过构造函数定义的类 二者本质相同。并且在js执行时,会将第一种转会为第二种执行。所以 ES6 class的写法实质就是构造函数。

  • 实例访问构造函数:example.constructor
  • 实例访问原型对象:example.**proto** 

请实现Cat继承Animal的属性,并比较各继承的优缺点

原型链继承

  • 优点:实例是父类的实例,也是子类的实例。父类新增在原型上的方法和属性,所有子类都可以访问到。简单 易于实现
  • 缺点:无法实现多继承。来自原型对象的引用属性和实例,所有子类都是共享的。创建子类实例时,无法向父类构造器传参。(可以在构造函数中,为实例增加实例属性。)

    // 原型链继承 function Animal() { this.species = "动物" }

    function Cat(name, color) { this.name = name this.color = color }

    // 核心:父类的实例作为子类的原型 Cat.prototype = new Animal()

构造继承

  • 相当于复制父类的属性方法给子类(没有用到原型)
  • 子类不能访问父类原型上的方法和属性

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

    function Cat(name, color) {
    this.name = name;
    this.color = color;

    //方法1: Animal.call(this)

    //方法2: Anmial.apply(this) }

组合继承

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

function Cat(name, color) {
    this.name = name
    this.color = color
}
Cat.prototype= new Animal()
Cat.prototype.constructor = Cat //修复构造函数的指向

寄生组合继承 (最好)

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

function Cat(name, color) {
    Animal.call(this)
    this.name = name
    this.color = color
}

function F(){}
F.prototype= Animal.prototype
Cat.prototype= new F()
Cat.prototype.contructor = Cat

new一个实例,经历了什么过程?

自己写一个new方法

es6中的static的作用是什么?用es5如何实现?

类就是实例的原型。class就是构造函数。在方法前加上static关键字,该方法不会被实例继承,只能直接通过类来调用,也就是静态方法.

举个🌰: 

那父类静态方法,子类如何继承?

使用extend关键字

用es5如何实现?

  

使用构造继承

JS单线程是怎么运作的?请说下“异步”和“同步”的区别

  • js单线程要分为浏览器和node环境
  • 浏览器环境:
    1. 先执行同步代码
    2. 执行异步代码的所有微任务
    3. 执行异步代码的一个宏任务
    4. 执行执行异步代码的所有微任务 5.执行异步代码的一个宏任务 6.循环
  • node环境
    1. 先执行同步代码
    2. 执行异步代码的所有微任务
    3. 执行异步代码的所有宏任务
    4. 执行执行异步代码的所有微任务
    5. 执行异步代码的所有宏任务
    6. 循环
  • node的宏任务有六个任务队列
  • 浏览器的宏任务都在同一个任务队列

练兵场

处理异步任务的方法有哪些?

  1. 回调函数 (回调不一定是异步 使用这个实现)

    function f1(callback) { setTimeout(function() { callback() }, 1000) } function f2(){} f1(f2)

  2. 事件监听(事件驱动模式)on,bind,listen,addEventListener,observe

    function f1() { setTimeout(function(){ f1.trigger('done') },1000) }

    f1.on('done',f2)

  • 优:易于理解、可绑定多个事件,可以去耦合,利于模块化。
  • 缺:整个程序变成事件驱动型,运行流程不清晰。
  1. 发布/订阅(publish/subscribe)

    JQuery.subscribe('done', f2) //订阅done function f1() { setTimeout(function() { jQuery.publish('done') //执行f1任务代码 }, 1000) } JQuery.unsubscribe('done', f2) //执行后取消订阅

  2. Promise对象
  3. async/await

请实现一个同步的delay方法

魔女有话说

很感谢你能看到这里,希望你能够有所收获。在学习的路上,大多都是艰辛的,但是只要我们有所期待,坚持不放弃,总会成功的。我们一定要看到成功人士背后的艰辛。今天的知识点都是作为一个前端必须要掌握的,如果读的时候,感觉有点吃力,不妨收藏下来,多读几次。我也会坚持输出高质量的文章,不愿辜负粉丝。 如果可以,请给我点在看,并关注公众号。你的支持,是我坚持的动力。谢谢~~