1. 原型 / 构造函数 / 实例

  • 原型( prototype ): ⼀个简单的对象,⽤于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个 JavaScript 对象中都包含⼀个__proto__ (⾮标准)的属性指向它爹(该对象的原型),可 obj.proto 进⾏访问。
  • 构造函数: 可以通过 new 来 新建⼀个对象 的函数。
  • 实例: 通过构造函数和 new 创建出来的对象,便是实例。 实例通过 proto 指向原型,通过 constructor 指向构造函数。
  • 以 Object 为例,我们常⽤的 Object 便是⼀个构造函数,因此我们可以通过它构建实例。
// 实例
const instance = new Object()
  • 则此时, 实例为 instance , 构造函数为 Object ,我们知道,构造函数拥有⼀个 prototype 的属性指向原型,因此原型为:
// 原型
const prototype = Object.prototype

这⾥我们可以来看出三者的关系:

  • 实例.proto === 原型
  • 原型.constructor === 构造函数
  • 构造函数.prototype === 原型
// 这条线其实是是基于原型进⾏获取的,可以理解成⼀条基于原型的映射线
// 例如:
// const o = new Object()
// o.constructor === Object --> true
// o.__proto__ = null;
// o.constructor === Object --> false
实例.constructor === 构造函数

2.原型链:

  • 原型链是由原型对象组成,每个对象都有 proto 属性,指向了创建该对象的构造函数的原型, proto 将对象连接起来组成了原型链。是⼀个⽤来实现继承和共享属性的有限的对象链
  • 属性查找机制: 当查找对象的属性时,如果实例对象⾃身不存在该属性,则沿着原型链往上⼀级查找,找到时则输出,不存在时,则继续沿着原型链往上⼀级查找,直⾄最顶级的原型对象 Object.prototype ,如还是没找到,则输出 undefined ;
  • 属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进⾏添加该属性,如果需要修改原型的属性时,则可以⽤: b.prototype.x = 2 ;但是这样会造成所有继承于该对象的实例的属性发⽣改变。

3. 执⾏上下⽂(EC)

  • 执⾏上下⽂可以简单理解为⼀个对象:

它包含三个部分:

  • 变量对象( VO )
  • 作⽤域链(词法作⽤域)
  • this 指向

它的类型:

  • 全局执⾏上下⽂
  • 函数执⾏上下⽂
  • eval 执⾏上下⽂

代码执⾏过程:

  • 创建 全局上下⽂ ( global EC )
  • 全局执⾏上下⽂ ( caller ) 逐⾏ ⾃上⽽下 执⾏。遇到函数时,函数执⾏上下⽂( callee ) 被 push 到执⾏栈顶层
  • 函数执⾏上下⽂被激活,成为 active EC , 开始执⾏函数中的代码, caller 被挂起
  • 函数执⾏完后, callee 被 pop 移除出执⾏栈,控制权交还全局上下⽂ ( caller ),继续执⾏

4.变量对象

  • 变量对象,是执⾏上下⽂中的⼀部分,可以抽象为⼀种 数据作⽤域,其实也可以理解为就是⼀个简单的对象,它存储着该执⾏上下⽂中的所有 变量和函数声明(不包含函数表达式)。
  • 活动对象 ( AO ): 当变量对象所处的上下⽂为 active EC 时,称为活动对象。

5. 作⽤域

  • 执⾏上下⽂中还包含作⽤域链。理解作⽤域之前,先介绍下作⽤域。作⽤域其实可理解为该上下⽂中声明的 变量和声明的作⽤范围。可分为 块级作⽤域 和函数作⽤域

特性:

  • 声明提前: ⼀个声明在函数体内都是可⻅的, 函数优先于变量
  • ⾮匿名⾃执⾏函数,函数变量为 只读 状态,⽆法修改
let foo = function() { console.log(1) }
(function foo() {foo = 10 // 由于foo在函数中只为可读,因此赋值⽆效
console.log(foo)
}())
// 结果打印: ƒ foo() { foo = 10 ; console.log(foo) }

6.作⽤域链

  • 我们知道,我们可以在执⾏上下⽂中访问到⽗级甚⾄全局的变量,这便是作⽤域链的功劳。作⽤域链可以理解为⼀组对象列表,包含 ⽗级和⾃身的变量对象,因此我们便能通过作⽤域链访问到⽗级⾥声明的变量或者函数。

由两部分组成:

  • [[scope]] 属性: 指向⽗级变量对象和作⽤域链,也就是包含了⽗级的 [[scope]] 和 AO
  • AO : ⾃身活动对象
  • 如此 [[scopr]] 包含 [[scope]] ,便⾃上⽽下形成⼀条 链式作⽤域。

7. 闭包

  • 闭包属于⼀种特殊的作⽤域,称为 静态作⽤域。它的定义可以理解为: ⽗函数被销毁 的情况下,返回出的⼦函数的 [[scope]] 中仍然保留着⽗级的单变量对象和作⽤域链,因此可以继续访问到⽗级的变量对象,这样的函数称为闭包。

闭包会产⽣⼀个很经典的问题:

  • 多个⼦函数的 [[scope]] 都是同时指向⽗级,是完全共享的。因此当⽗级的变量对象被修改时,所有⼦函数都受到影响。
    ••解决:**
  • 变量可以通过 函数参数的形式 传⼊,避免使⽤默认的 [[scope]] 向上查找
  • 使⽤ setTimeout 包裹,通过第三个参数传⼊
  • 使⽤ 块级作⽤域,让变量成为⾃⼰上下⽂的属性,避免共享

8. script 引⼊⽅式:

html 静态 <script> 引⼊
js 动态插⼊ <script>
<script defer> : 异步加载,元素解析完成后执⾏
<script async> : 异步加载,但执⾏时会阻塞元素渲染

9. 对象的拷⻉

浅拷⻉: 以赋值的形式拷⻉引⽤对象,仍指向同⼀个地址,修改时原对象也会受到影响

  • Object.assign
  • 展开运算符( … )

深拷⻉: 完全拷⻉⼀个新对象,修改时原对象不再受到任何影响

  • JSON.parse(JSON.stringify(obj)) : 性能最快
  • 具有循环引⽤的对象时,报错
  • 当值为函数、 undefined 、或 symbol 时,⽆法拷⻉
  • 递归进⾏逐⼀赋值

10. new运算符的执⾏过程

  • 新⽣成⼀个对象
  • 链接到原型: obj.proto = Con.prototype
  • 绑定 this: apply
  • 返回新对象(如果构造函数有⾃⼰ retrun 时,则返回该值)

11. instanceof原理

  • 能在实例的 原型对象链 中找到该构造函数的 prototype 属性所指向的 原型对象,就返回 true 。即:
// __proto__: 代表原型对象链
instance.[__proto__...] === instance.constructor.prototype
// return true

12. 代码的复⽤

  • 当你发现任何代码开始写第⼆遍时,就要开始考虑如何复⽤。⼀般有以下的⽅式:

    • 函数封装
    • 继承
    • 复制 extend
    • 混⼊ mixin
    • 借⽤ apply/call

13. 继承

  • 在 JS 中,继承通常指的便是 原型链继承,也就是通过指定原型,并可以通过原型链继承原型上的属性或者⽅法。

最优化: 圣杯模式

var inherit = (function(c,p){var F = function(){};
return function(c,p){F.prototype = p.prototype;
c.prototype = new F();
c.uber = p.prototype;
c.prototype.constructor = c;
}
})();
  • 使⽤ ES6 的语法糖 class / extends

14. 类型转换

  • ⼤家都知道 JS 中在使⽤运算符号或者对⽐符时,会⾃带隐式转换,规则如下:

    • -、*、/、% :⼀律转换成数值后计算
    • +:
      • 数字 + 字符串 = 字符串, 运算顺序是从左到右

      • 数字 + 对象, 优先调⽤对象的 valueOf -> toString

      • 数字 + boolean/null -> 数字

      • 数字 + undefined -> NaN

  • [1].toString() === ‘1’
  • {}.toString() === ‘[object object]’
  • NaN !== NaN 、+ undefined 为 NaN

15. 类型判断

  • 判断 Target 的类型,单单⽤ typeof 并⽆法完全满⾜,这其实并不是bug ,本质原因是 JS 的万物皆对象的理论。因此要真正完美判断时,我们需要区分对待:

    • 基本类型( null ): 使⽤ String(null)
    • 基本类型( string / number / boolean / undefined ) + function : - 直接使⽤typeof 即可
    • 其余引⽤类型( Array / Date / RegExp Error ): 调⽤ toString 后根据 [objectXXX] 进⾏判断
很稳的判断封装:
let class2type = {}
'Array Date RegExp Object Error'.split(' ').forEach(e => class2type[ '[obje
function type(obj) {if (obj == null) return String(obj)
return typeof obj === 'object' ? class2type[ Object.prototype.toString.
}

16. 模块化

  • 模块化开发在现代开发中已是必不可少的⼀部分,它⼤⼤提⾼了项⽬的可维护、可拓展和可协作性。通常,我们 在浏览器中使⽤ ES6 的模块化⽀持,在Node 中使⽤ commonjs 的模块化⽀持。

分类:

  • es6: import / export

  • commonjs: require / module.exports / exports

  • amd: require / defined

require与import的区别

  • require ⽀持 动态导⼊, import 不⽀持,正在提案 ( babel 下可⽀持)
  • require 是 同步 导⼊, impor t属于 异步 导⼊
  • require 是 值拷⻉,导出值变化不会影响导⼊值; import 指向 内存地址,导⼊值会随导出值⽽变化

17. 防抖与节流

  • 防抖与节流函数是⼀种最常⽤的 ⾼频触发优化⽅式,能对性能有较⼤的帮助。
  • 防抖 (debounce): 将多次⾼频操作优化为只在最后⼀次执⾏,通常使⽤的场景是:⽤户输⼊,只需再输⼊完成后做⼀次输⼊校验即可。
function debounce(fn, wait, immediate) {let timer = null
return function() {let args = arguments
let context = this
if (immediate && !timer) {fn.apply(context, args)
}
if (timer) clearTimeout(timer)
timer = setTimeout(() => {fn.apply(context, args)
}, wait)
}
}
  • 节流(throttle): 每隔⼀段时间后执⾏⼀次,也就是降低频率,将⾼频操作优化成低频操作,通常使⽤场景: 滚动条事件 或者 resize 事件,通常每隔 100~500 ms 执⾏⼀次即可。
function throttle(fn, wait, immediate) {let timer = null
let callNow = immediate
return function() {let context = this,
args = arguments
if (callNow) {fn.apply(context, args)
callNow = false
}
if (!timer) {timer = setTimeout(() => {fn.apply(context, args)
timer = null
}, wait)
}
}
}

18. 函数执⾏改变this

  • 由于 JS 的设计原理: 在函数中,可以引⽤运⾏环境中的变量。因此就需要⼀个机制来让我们可以在函数体内部获取当前的运⾏环境,这便是 this 。
  • 因此要明⽩ this 指向,其实就是要搞清楚 函数的运⾏环境,说⼈话就是,谁调⽤了函数。例如
    • obj.fn() ,便是 obj 调⽤了函数,既函数中的 this === obj
    • fn() ,这⾥可以看成 window.fn() ,因此 this === window
  • 但这种机制并不完全能满⾜我们的业务需求,因此提供了三种⽅式可以⼿动修改 this 的指向:
    • call: fn.call(target, 1, 2)
    • apply: fn.apply(target, [1, 2])
    • bind: fn.bind(target)(1,2)

19. ES6/ES7

  • 由于 Babel 的强⼤和普及,现在 ES6/ES7 基本上已经是现代化开发的必备了。通过新的语法糖,能让代码整体更为简洁和易读。

声明

  • let / const : 块级作⽤域、不存在变量提升、暂时性死区、不允许重复声明
  • const : 声明常量,⽆法修改

解构赋值

class / extend: 类声明与继承
Set / Map: 新的数据结构

异步解决⽅案:

  • Promise 的使⽤与实现
  • generator :
    • yield : 暂停代码
    • next() : 继续执⾏代码
function* helloWorld() {yield 'hello';
yield 'world';
return 'ending';
}
const generator = helloWorld();
generator.next() // { value: 'hello', done: false }
generator.next() // { value: 'world', done: false }
generator.next() // { value: 'ending', done: true }
generator.next() // { value: undefined, done: true }
  • await / async : 是 generator 的语法糖, babel 中是基于 promise 实现。
async function getUserByAsync(){let user = await fetchUser();
return user;
}
const user = await getUserByAsync()
console.log(user)

20. AST

  • 抽象语法树 ( Abstract Syntax Tree ),是将代码逐字⺟解析成 树状对象 的形式。这是语⾔之间的转换、代码语法检查,代码⻛格检查,代码格式化,代码⾼亮,代码错误提示,代码⾃动补全等等的基础。例如:
function square(n){return n * n
}

21. babel编译原理

  • babylon 将 ES6/ES7 代码解析成 AST
  • babel-traverse 对 AST 进⾏遍历转译,得到新的 AST
  • 新 AST 通过 babel-generator 转换成 ES5

22. 函数柯⾥化

  • 在⼀个函数中,⾸先填充⼏个参数,然后再返回⼀个新的函数的技术,称为函数的柯⾥化。通常可⽤于在不侵⼊函数的前提下,为函数 预置通⽤参数,供多次重复调⽤。
const add = function add(x) {return function (y) {return x + y
}
}
const add1 = add(1)
add1(2) === 3
add1(20) === 21

前端高级面试题-JS相关推荐

  1. 前端基础面试题(JS部分)

    1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined.Null.Boolean.Number.String 值类型:数值.布尔值.null.und ...

  2. 前端常见面试题 - JS篇

    以下会是JS常见面试题: 面试题将会以系列不定时更新,编写不宜,如有用到,请动动小手关注一下. 1. 简述ES6 1. let: 块级作用域. 2. const: 常量; 块级作用域; 一旦声明, 则 ...

  3. 2020前端最新面试题总结(js、html、小程序、React、ES6、Vue、算法、全栈热门视频资源)(3年前端菜鸟级开发师含泪总结)

    2020前端最新面试题总结(js.html.小程序.React.ES6.Vue.算法.全栈热门视频资源) 文档描述 (今年确实挺难 3年前端菜鸟级开发师含泪总结 希望能帮助大家) 本文是关注微信小程序 ...

  4. js考试题 html5新特性,Web前端初级面试题总结

    Web前端初级面试题总结 发布时间:2018-11-02 11:17, 浏览次数:549 , 标签: Web Web篇: 1.常见的浏览器内核有哪些? IE:Trident内核            ...

  5. 前端复习8:JS高级

    前端复习8:JS高级 1.对象 1.1 面向过程与面向对象 1.2 对象与类 2 构造函数和原型 2.1 构造函数 2.2 构造原型prototype 2.2 对象原型 2.3 constructor ...

  6. 2020前端最新面试题(vue篇)

    2020前端最新面试题(vue篇) 由于疫情原因,原本每年的"金三银四"仿佛消失,随之而来的是找工作的压力,这里给要面试的小伙伴们总结了到目前为止我遇到的前端面试题,仅供参考哦,第 ...

  7. 2018最新Web前端经典面试试题及答案

    本篇收录了一些面试中经常会遇到的经典面试题以及自己面试过程中遇到的一些问题,并且都给出了我在网上收集的答案.马上就要过春节了,开年就是崭新的一年,相信很多的前端开发者会有一些跳槽的悸动,通过对本篇知识 ...

  8. 最新前端中高级面试题

    前言 关于前端面试,及面试题目,我之前有很多文章总结过,可以在右侧搜索面试,进行查找.其实面试中可以问的问题很多,最近几年,我也面试过很多工作2-4年的前端,我一般会抓住他们做的项目,进行更详细的追问 ...

  9. 前端开发面试题及答案整理

    前端开发面试题及答案整理 文章目录 一些开放性题目 position的值, relative和absolute分别是相对于谁进行定位的? 如何解决跨域问题 XML和JSON的区别? 谈谈你对webpa ...

  10. web前端高级必备面试资料

    最近整理了下web前端面试的资料,包含了web前端.数据结构和算法.计算机基础.版本控制工具.经验分享.视频课程和面试书籍等资料,还有比这更全的没有? 废话不多说,直接上干货,欢迎收藏,不用客气. 前 ...

最新文章

  1. 一文看懂docker容器技术架构及其中的各个模块
  2. NBT:王运浩、区健辉等综述纳米孔测序技术
  3. python数组操作加法_Numpy数组索引和/或加法似乎是
  4. Day 31 并发编程
  5. Spring Task配置
  6. 我的世界服务器反作弊不起作用,我的世界服务器反作弊怎么搞 | 手游网游页游攻略大全...
  7. 深入浅出python机器学习_5.1.2_朴素贝叶斯的简单应用
  8. 决策树随机森林GBDT
  9. jQuery 动画效果
  10. 微软腾讯京东都在高薪招.NET Core,你准备好了吗!
  11. 利用cli.go来写命令行应用
  12. [转载] Python字符串操作大全(一)
  13. linux下的PDF阅读器
  14. 【长文预警】美团联合创始人王慧文清华产品课
  15. base16、base32和base64转码原理
  16. 熊博士c语言,InstallShield2015制作安装包----------安装后实现电脑开机自启动
  17. 涠洲岛形成及地形地貌特征
  18. 金边富贵竹的养护方法
  19. 2018-7-4 笔记
  20. 面向对象系列(一)-关键字

热门文章

  1. 如何让css中的background-image图片自适应
  2. WSL2不能正常启动,错误代码: process exited with code 4294967295 (0xffffffff)
  3. QT QLabel设置字体的颜色
  4. adb push remount disable-verity的时候,报各种权限错误,一步一步填坑中
  5. 记一次有趣的debug,VS编译器上Debug和Realease的差异
  6. 【程序源代码】码云微信小程序
  7. CAS单点登录原理详解
  8. 【BML全功能AI开发平台初体验】一小时轻松搞定文本数据集标注!
  9. @Cacheable缓存相关使用总结
  10. IoT设备渗透测试环境搭建及常用工具