JavaScript面试核心考点(精华)阿斯顿23

引言

Javascript是前端面试的重点,本文重点梳理下 Javascript 中的常考基础知识点,然后就一些容易出现的题目进行解析。限于文章的篇幅,无法将知识点讲解的面面俱到,本文只罗列了一些重难点。

一、变量类型

1.JS 的数据类型分类

根据 JavaScript 中的变量类型传递方式,分为基本数据类型和引用数据类型。其中基本数据类型包括Undefined、Null、Boolean、Number、String、Symbol (ES6新增,表示独一无二的值),而引用数据类型统称为Object对象,主要包括对象、数组和函数。

在参数传递方式上,有所不同:

  • 函数的参数如果是简单类型,会将一个值类型的数值副本传到函数内部,函数内部不影响函数外部传递的参数变量
  • 如果是一个参数是引用类型,会将引用类型的地址值复制给传入函数的参数,函数内部修改会影响传递参数的引用对象。

题目:基本类型和引用类型的区别

基本类型和引用类型存储于内存的位置不同,基本类型直接存储在栈中,而引用类型的对象存储在堆中,与此同时,在栈中存储了指针,而这个指针指向正是堆中实体的起始位置。下面通过一个小题目,来看下两者的主要区别:

// 基本类型
var a = 10
var b = a
b = 20
console.log(a) // 10
console.log(b) // 20

上述代码中,a b都是值类型,两者分别修改赋值,相互之间没有任何影响。再看引用类型的例子:

// 引用类型
var a = {x: 10, y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a) // {x: 100, y: 200}
console.log(b) // {x: 100, y: 200}

上述代码中,a b都是引用类型。在执行了b = a之后,修改b的属性值,a的也跟着变化。因为a和b都是引用类型,指向了同一个内存地址,即两者引用的是同一个值,因此b修改属性时,a的值随之改动

2.数据类型的判断

1)typeof

typeof返回一个表示数据类型的字符串,返回结果包括:number、boolean、string、symbol、object、undefined、function等7种数据类型,但不能判断null、array等

typeof Symbol(); // symbol 有效
typeof ‘‘; // string 有效
typeof 1; // number 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof new Function(); // function 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效

2)instanceof

instanceof 是用来判断A是否为B的实例,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性,但它不能检测null 和 undefined

[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
new RegExp() instanceof RegExp//true
null instanceof Null//报错
undefined instanceof undefined//报错

3)constructor

constructor作用和instanceof非常相似。但constructor检测 Object与instanceof不一样,还可以处理基本数据类型的检测。不过函数的 constructor 是不稳定的,这个主要体现在把类的原型进行重写,在重写的过程中很有可能出现把之前的constructor给覆盖了,这样检测出来的结果就是不准确的。

4)Object.prototype.toString.call()

Object.prototype.toString.call() 是最准确最常用的方式

Object.prototype.toString.call(‘‘) ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]

3.浅拷贝与深拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存

浅拷贝的实现方式(详见https://github.com/ljianshu/Blog/issues/5):

  • Object.assign():需注意的是目标对象只有一层的时候,是深拷贝
  • Object.assign(target, ...sources);target:目标对象,sources:一个或多个源对象
  • 注:Object.assign 可以把 n 个源对象拷贝到目标对象中去,如下
  • let m ={name: {asd: ‘123‘}};
    let n = Object.assign({}, m);
    console.log(n);//{name: {asd: ‘123‘}}

    那到底是深拷贝还是浅拷贝呢,答案是修改第一级属性深拷贝,以后级别属性浅拷贝 。大家看下面两段代码

  • let s ={name: {asd: ‘123‘}};
    let d = Object.assign({}, s);
    d.name.asd = ‘123456789‘;
    console.log(d, s);//{name:{asd: "123456789"}},{name:{asd: "123456789"}}
    let o ={name: {asd: ‘123‘}};
    let p = Object.assign({}, o);
    p.name = ‘123456789‘;
    console.log(p, o);//{name: "123456789"},{name: {asd: "123"}}
  • Array.prototype.concat()
  • Array.prototype.slice()

深拷贝就是在拷贝数据的时候,将数据的所有引用结构都拷贝一份。简单的说就是,在内存中存在两个数据结构完全相同又相互独立的数据,将引用型类型进行复制,而不是只复制其引用关系。

深拷贝的实现方式:

  • 热门的函数库lodash,也有提供_.cloneDeep用来做深拷贝
  • jquery 提供一个$.extend可以用来做深拷贝
  • JSON.parse(JSON.stringify())
  • 手写递归方法

递归实现深拷贝的原理:要拷贝一个数据,我们肯定要去遍历它的属性,如果这个对象的属性仍是对象,继续使用这个方法,如此往复。

//定义检测数据类型的功能函数
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆---对象/数组
function clone(target) {
//判断拷贝的数据类型
//初始化变量result 成为最终克隆的数据
let result,
targetType = checkedType(target)
if (targetType === ‘Object‘) {
result = {}
} else if (targetType === ‘Array‘) {
result = []
} else {
return target
}
//遍历目标数据
for (let i in target) {
//获取遍历数据结构的每一项值。
let value = target[i]
//判断目标结构里的每一值是否存在对象/数组
if (checkedType(value) === ‘Object‘ || checkedType(value) === ‘Array‘) {
//对象/数组里嵌套了对象/数组
//继续遍历获取到value值
result[i] = clone(value)
} else {
//获取到value值是基本的数据类型或者是函数。
result[i] = value
}
}
return result
}

二、作用域和闭包

1.执行上下文和执行栈

执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行。执行上下文的生命周期包括三个阶段:创建阶段→执行阶段→回收阶段,我们重点介绍创建阶段。

创建阶段(当函数被调用,但未执行任何其内部代码之前)会做以下三件事:

  • 创建变量对象:首先初始化函数的参数arguments,提升函数声明和变量声明。
  • 创建作用域链:下文会介绍
  • 确定this指向:下文会介绍

function test(arg){
// 1. 形参 arg 是 "hi"
// 2. 因为函数声明比变量声明优先级高,所以此时 arg 是 function
console.log(arg);
var arg = ‘hello‘; // 3.var arg 变量声明被忽略, arg = ‘hello‘被执行
function arg(){
console.log(‘hello world‘)
}
console.log(arg);
}
test(‘hi‘);
/* 输出:
function arg() {
console.log(‘hello world‘);
}
hello
*/

这是因为当函数执行的时候,首先会形成一个新的私有的作用域,然后依次按照如下的步骤执行:

  • 如果有形参,先给形参赋值
  • 进行私有作用域中的预解释,函数声明优先级比变量声明高,最后后者会被前者所覆盖,但是可以重新赋值
  • 私有作用域中的代码从上到下执行

函数多了,就有多个函数执行上下文,每次调用函数创建一个新的执行上下文,那如何管理创建的那么多执行上下文呢?

JavaScript 引擎创建了执行栈来管理执行上下文。可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则

从上面的流程图,我们需要记住几个关键点:

  • JavaScript执行在单线程上,所有的代码都是排队执行。
  • 一开始浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部。
  • 每当进入一个函数的执行就会创建函数的执行上下文,并且把它压入执行栈的顶部。当前函数执行完成后,当前函数的执行上下文出栈,并等待垃圾回收。
  • 浏览器的JS执行引擎总是访问栈顶的执行上下文。
  • 全局上下文只有唯一的一个,它在浏览器关闭时出栈。

2.作用域与作用域链

ES6 到来JavaScript 有全局作用域、函数作用域和块级作用域(ES6新增)。我们可以这样理解:作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。在介绍作用域链之前,先要了解下自由变量,如下代码中,console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为 自由变量。

var a = 100
function fn() {
var b = 200
console.log(a) // 这里的a在这里就是一个自由变量
console.log(b)
}
fn()

自由变量的值如何得到 —— 向父级作用域(创建该函数的那个父级作用域)寻找。如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是作用域链 。

function F1() {
var a = 100
return function () {
console.log(a)
}
}
function F2(f1) {
var a = 200
console.log(f1())
}
var f1 = F1()
F2(f1) // 100

3.闭包是什么

闭包这个概念也是JavaScript中比较抽象的概念,我个人理解,闭包是就是函数中的函数(其他语言不能这样),里面的函数可以访问外面函数的变量,外面的变量的是这个内部函数的一部分。

闭包的作用:

  • 使用闭包可以访问函数中的变量。
  • 可以使变量长期保存在内存中,生命周期比较长

(闭包的缺点)-> 闭包不能滥用,否则会导致内存泄露,影响网页的性能。闭包使用完了后,要立即释放资源,将引用变量指向null。

闭包主要有两个应用场景:

  • 函数作为参数传递(见作用域部分例子)
  • 函数作为返回值(如下例)

function outer() {
var num = 0 //内部变量
return function add() {
//通过return返回add函数,就可以在outer函数外访问了。
num++ //内部函数有引用,作为add函数的一部分了
console.log(num)
}
}
var func1 = outer() //
func1() //实际上是调用add函数, 输出1
func1() //输出2
var func2 = outer()
func2() // 输出1
func2() // 输出2

4.this全面解析

先搞明白一个很重要的概念 —— this的值是在执行的时候才能确认,定义的时候不能确认!为什么呢 —— 因为this是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子:

// 情况1
function foo() {
console.log(this.a) //1
}
var a = 1
foo()

// 情况2
function fn(){
console.log(this);
}
var obj={fn:fn};
obj.fn(); //this->obj

// 情况3
function CreateJsPerson(name,age){
//this是当前类的一个实例p1
this.name=name; //=>p1.name=name
this.age=age; //=>p1.age=age
}
var p1=new CreateJsPerson("尹华芝",48);

// 情况4
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

// 情况5
<button id="btn1">箭头函数this</button>
<script type="text/javascript">
let btn1 = document.getElementById(‘btn1‘);
let obj = {
name: ‘kobe‘,
age: 39,
getName: function () {
btn1.onclick = () => {
console.log(this);//obj
};
}
};
obj.getName();
</script>

三、异步

1.同步 vs 异步

同步,我的理解是一种线性执行的方式,执行的流程不能跨越。比如说话后在吃饭,吃完饭后在看手机,必须等待上一件事完了,才执行后面的事情。

异步,是一种并行处理的方式,不必等待一个程序执行完,可以执行其它的任务。比方说一个人边吃饭,边看手机,边说话,就是异步处理的方式。在程序中异步处理的结果通常使用回调函数来处理结果。

// 同步
console.log(100)
alert(200);
console.log(300)  //100 200 300
// 异步
console.log(100)
setTimeout(function(){
  console.log(200)
})
console.log(300) //100 300 200

2.异步和单线程

JS 需要异步的根本原因是 JS 是单线程运行的,即在同一时间只能做一件事,不能“一心二用”。为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

一个 Ajax 请求由于网络比较慢,请求需要 5 秒钟。如果是同步,这 5 秒钟页面就卡死在这里啥也干不了了。异步的话,就好很多了,5 秒等待就等待了,其他事情不耽误做,至于那 5 秒钟等待是网速太慢,不是因为 JS 的原因。

3.前端异步的场景

前端使用异步的场景

  • 定时任务:setTimeout,setInterval
  • 网络请求:ajax请求,动态加载
  • 事件绑定

4.Event Loop

一个完整的 Event Loop 过程,可以概括为以下阶段:

  • 一开始执行栈空,我们可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。micro 队列空,macro 队列里有且只有一个 script 脚本(整体代码)。
  • 全局上下文(script 标签)被推入执行栈,同步代码执行。在执行的过程中,会判断是同步任务还是异步任务,通过对一些接口的调用,可以产生新的 macro-task 与 micro-task,它们会分别被推入各自的任务队列里。同步代码执行完了,script 脚本会被移出 macro 队列,这个过程本质上是队列的 macro-task 的执行和出队的过程。
  • 上一步我们出队的是一个 macro-task,这一步我们处理的是 micro-task。但需要注意的是:当 macro-task 出队时,任务是一个一个执行的;而 micro-task 出队时,任务是一队一队执行的。因此,我们处理 micro 队列这一步,会逐个执行队列中的任务并把它出队,直到队列被清空。
  • 执行渲染操作,更新界面
  • 检查是否存在 Web worker 任务,如果有,则对其进行处理
  • 上述过程循环往复,直到两个队列都清空

接下来我们看道例子来介绍上面流程:

Promise.resolve().then(()=>{
console.log(‘Promise1‘)
setTimeout(()=>{
console.log(‘setTimeout2‘)
},0)
})
setTimeout(()=>{
console.log(‘setTimeout1‘)
Promise.resolve().then(()=>{
console.log(‘Promise2‘)
})
},0)

最后输出结果是Promise1,setTimeout1,Promise2,setTimeout2

  • 一开始执行栈的同步任务(这属于宏任务)执行完毕,会去查看是否有微任务队列,上题中存在(有且只有一个),然后执行微任务队列中的所有任务输出Promise1,同时会生成一个宏任务 setTimeout2
  • 然后去查看宏任务队列,宏任务 setTimeout1 在 setTimeout2 之前,先执行宏任务 setTimeout1,输出 setTimeout1
  • 在执行宏任务setTimeout1时会生成微任务Promise2 ,放入微任务队列中,接着先去清空微任务队列中的所有任务,输出 Promise2
  • 清空完微任务队列中的所有任务后,就又会去宏任务队列取一个,这回执行的是 setTimeout2

让我们再看一个例子:

for (var i = 0; i < 5; i++) {
  console.log(i);
}
//输出://0 1 2 3 4
//-------省略线---------
//如果改成这样呢?
for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000 * i);
}
//setTimeout 会延迟执行,那么执行到 console.log 的时候,其实 i 已经变成 5 了
//输出://开始输出一个 5,然后每隔一秒再输出一个 5,一共 5 个 5
//&那应该怎么改才能输出 0 到 4 呢?
//加个闭包就解决了,稳!
for (var i = 0; i < 5; i++) {
  (function() {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  })(i);
}
//&删掉这个 i 会发生什么?
for (var i = 0; i < 5; i++) {
  (function() {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  })(i);
}
//这样子的话,内部其实没有对 i 保持引用,其实会变成输出 5。
//&如果改一下,会输出什么?
for (var i = 0; i < 5; i++) {
  setTimeout((function(i) {
    console.log(i);
  })(i), i * 1000);
}
//&如果改成这样,会输出什么?
for (var i = 0; i < 5; i++) {
  setTimeout((function(i) {
    console.log(i);
  })(i), i * 1000);
}
//这里给 setTimeout 传递了一个立即执行函数。额,setTimeout 可以接受函数或者字符串作为参数,那么这里立即执行函数是个啥呢,应该是个 undefined ,也就是说等价于:

setTimeout(undefined, ...);

//而立即执行函数会立即执行,那么应该是立马输出的。
//“应该是立马输出 0 到 4 吧。”
//&最后改成这样,会输出什么?
setTimeout(function() {
  console.log(1)
}, 0);
new Promise(function executor(resolve) {
  console.log(2);
  for( var i=0 ; i<10000 ; i++ ) {
    i == 9999 && resolve();
  }
  console.log(3);
}).then(function() {
  console.log(4);
});
console.log(5);
//首先先碰到一个 setTimeout,于是会先设置一个定时,在定时结束后将传递这个函数放到任务队列里面,因此开始肯定不会输出 1 。

//然后是一个 Promise,里面的函数是直接执行的,因此应该直接输出 2 3 。

//然后,Promise 的 then 应当会放到当前 tick 的最后,但是还是在当前 tick 中。

//因此,应当先输出 5,然后再输出 4 。

//最后在到下一个 tick,就是 1 。
//最终输出2 3 5 4 1

例子出处:https://zhuanlan.zhihu.com/p/25407758

四、原型链与继承

1.原型和原型链

原型:在JavaScript中原型是一个prototype对象,用于表示类型之间的关系。

https://www.ximalaya.com/youshengshu/24991228/
https://www.ximalaya.com/youshengshu/24991186/
https://www.ximalaya.com/youshengshu/24991182/
https://www.ximalaya.com/youshengshu/24991385/
https://www.ximalaya.com/youshengshu/24991401/
https://www.ximalaya.com/youshengshu/24991379/
https://www.ximalaya.com/youshengshu/24991372/
https://www.ximalaya.com/youshengshu/24991345/
www.jianshu.com/p/c3ea8ea881bb
www.jianshu.com/p/a48f58436dc3
www.jianshu.com/p/8b54769d719f
www.jianshu.com/p/3b98ab2da7b5
www.jianshu.com/p/68d3c5b781d8

原型链:JavaScript万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。

var Person = function() {
this.age = 18
this.name = ‘匿名‘
}
var Student = function() {}
//创建继承关系,父类实例作为子类原型
Student.prototype = new Person()
var s1 = new Student()
console.log(s1)

当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的 __proto__(即它的构造函数的prototype)中寻找。如果一直找到最上层都没有找到,那么就宣告失败,返回undefined。最上层是什么 ——

原文地址:https://www.cnblogs.com/chenzhisisw/p/11161404.html

时间: 2024-11-10 13:44:38

JavaScript面试核心考点(精华)阿斯顿23的相关文章

JavaScript面试核心考点(精华)

引言 Javascript是前端面试的重点,本文重点梳理下 Javascript 中的常考基础知识点,然后就一些容易出现的题目进行解析.限于文章的篇幅,无法将知识点讲解的面面俱到,本文只罗列了一些重难点. 一.变量类型 1.JS 的数据类型分类 根据 JavaScript 中的变量类型传递方式,分为基本数据类型和引用数据类型.其中基本数据类型包括Undefined.Null.Boolean.Number.String.Symbol (ES6新增,表示独一无二的值),而引用数据类型统称为Objec

快速搞定前端初级JavaScript面试完整版

资源获取链接:点击获取完整教程 抓紧面试前的宝贵时间 快速搞定前端初级JavaScript面试 BAT资深面试官针对时下面试高频考点,帮你解决面试问题.课程不局限于简单地讲解每一个知识点,而是以面试官的角度出发,带你了解前端面试中每个“门道”与“套路”.手把手带你分析考点及解答策略,梳理JS考试体系,帮助前端新人快速通过JS面试部分. 课程紧凑,分秒必争 拒绝题海战术,绝不浪费时间解析典型面试题,分析前端面试核心考点拆解一道题,解决一类题 匠心设计,直击考点 凝聚讲师三年面试课程授课经验结合大量

JavaScript面试的完美指南(开发者视角)

为了说明 JS 面试的复杂性,首先,请尝试给出以下结果: onsole.log(2.0 == "2" == new Boolean(true) == "1") 十有八九的会给出false, 其实运行结果是true,原因请看 这里. 1) 理解 JS 函数 函数是 JavaScript 的精华,是 JS 一等公民.JS 函数不仅仅是一个普通的函数,与其他语言不同,JS 函数可以赋值给变量,作为参数传递给另一个函数,也可以从另一个函数返回. console.log(sq

前端JavaScript面试技巧

第1章 课程简介从几个常见面试开始,讨论针对一个题目的分析思路,总结题目对应的知识点.最后列出所有 JS 知识点的集合 -- JS 知识体系框架.1-1 课程简介(导学)1-2 前言1-3 几个面试题1-4 如何搞定所有面试题 第2章 JS基础知识(上)讲解 JS 基础语法相关的面试题,分析原理以及解答方法.这一章节讲解了基础知识的第一部分:变量的类型和计算.以及JS "三座大山" -- 原型.作用域和异步中的第一座大山:原型.2-1 变量类型和计算-12-2 变量类型和计算-22-3

Python面试常考点之深入浅出链表操作

Python面试常考点之深入浅出链表操作 在Python开发的面试中,我们经常会遇到关于链表操作的问题.链表作为一个非常经典的无序列表结构,也是一个开发工程师必须掌握的数据结构之一.在本文中,我将针对链表本身的数据结构特点,以及链表的一些常见操作给大家做一个深入浅出的讲解,希望本文的读者能够掌握链表的操作. 1. 什么是链表? 简单地说,链表是一种无序的列表.你可以把链表里面的数据看成是随机排列的,元素之间并没有固定的先后顺序.所以,既然是无序的,那么我们就无法像操作list对象一样简单地用in

JavaScript(核心、BOM、DOM)

http://www.flyne.org/article/407 JavaScript(核心.BOM.DOM) JavaScript是基于对象和事件驱动的客户端脚本语言.有如下特点: 交互性 安全性(不可以直接访问本地硬盘) 跨平台性(只要是可以解析js的浏览器都可以执行,和平台无关) 1.JavaScript和Java不同! ①所属:NetScape和Sun ②基于对象和面向对象 ③JS可以直接解析执行,Java需先编译在运行 ④JavaScript是一种弱类型的语言,Java是强类型的语言.

《程序员面试宝典》精华 编程语言部分

<程序员面试宝典>精华 编程语言部分 正所谓取其精华,去其糟粕.本文谨记录下<程序员面试宝典>一些关键的知识点.易错点,对于一些虽然重要但书中没有解释清楚的地方不做记录.当然这里的糟粕只是指不那么重要,或者比较简单,并不是说书写的不好.希望以后回顾时无需再看此书,只看保留在文中的精华即可. 文中有少许bug,亦摘录在此. 本文专注编程语言部分,包括第五章到第九章的内容 第五章 语言细节 5.1 y = z = 5,等号先计算右边,返回值是赋值后的左边的变量值 5.1 printf函

5个经典的JavaScript面试基础问题

JavaScript程序员在IT领域中的需求量非常巨大.如果你非常精通JavaScript,你会有很多换工作.涨薪水的机会.但是在一家公司录用你之前,你必须顺利通过面试,证明你的技能.在本文中,我将向您展示5个关于JavaScript相关的问题,可以全面地测试面试者JavaScript技能和解决问题的能力.一起来看看这5个经典的JavaScript面试问题. 问题1:Scope作用范围 考虑下面的JavaScript代码: (function() { var a = b = 5; })(); c

面试 -- 核心篇 -- 中间件(消息)

面试 -- 核心篇 -- 中间件(消息) 消息队列的应用场景 参考网址:消息队列的四种应用场景         消息队列设计思路 (1)异步处理 用户注册时,可以同时将 发送邮件 和 发送短信 功能放到消息队列中实现.可以提高用户响应时间,提高系统吞吐量. (2)应用解耦 用户下单和库存扣账中使用消息,可以防止库存系统出问题后,导致用户下单失败. (3)流量削峰 秒杀活动中,由于瞬间吞吐量很大,那么可以在客户端和业务处理中间加入消息队列,限制人数,丢弃掉过多的用户请求.这样可以防止流量暴增导致服