nodejs的 面试大全 容易 难的都有

1.如何区分数组和对象?

方法一:通过 ES6 中的 Array.isArray 来识别
Array.isArray([]) //true
Array.isArray({}) //false
方法二:通过 instanceof 来识别
[] instanceof Array
//true
{} instanceof Array
//false
方法三:通过调用 constructor 来识别
{}.constructor
//返回 object
[].constructor
//返回 Array
方法四:通过 Object.prototype.toString.call 方法来识别
Object.prototype.toString.call([])
//["object Array"]
Object.prototype.toString.call({})
//["object Object"]
 

2.怎么判断两个对象相等?

 
ES6 中有一个方法判断两个对象是否相等,这个方法判断是两个对象引用地址是否一致
let obj1= {
a: 1
}
let obj2 = {
a: 1
}
console.log(Object.is(obj1, obj2)) // false
let obj3 = obj1
console.log(Object.is(obj1, obj3)) // true
console.log(Object.is(obj2, obj3)) // false

3.如何遍历对象的属性?

 
遍历可枚举的自身属性和继承属性
(可枚举,可继承的属性) for in
遍历对象的属性
var obj={
name:'张三',
age : '24',
getAge:function(){
console.log(this.age);
}
}
var arry ={};
for(var i in obj){
if(obj.hasOwnProperty(i)&& typeOf obj[i] != 'function'){
arry[i] = obj[i];
}
}
console.log(arry);
{name:'张三',age:24}
注: hasOwnProperty()方法判断对象是有某个属性(本身的属性,不是继承的属性)
for in 输出的是结果值
 
在 JavaScript 里使用 typeof 来判断数据类型,只能区分基本类型,即 “Number”,”
String”,”undefined”,”Boolean”,”Object”,“
Function”,“symbol” (ES6 新增)七种
对于数组、null、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “
object” 字 符串
要 想 区 别 对 象 、 数 组 、 函 数 单 纯 使 用 typeof 是 不 行 的 , JavaScript 中 , 通 过
Object.prototype.toString 方法,判断某个对象值属于哪种内置类型。

4.function详解

  1. 函数是被设计为执行特定任务的代码块。保存一段可重用的代码段的程序结构,再起一个名字。
  2. 函数会在某代码调用它时被执行。只要一段代码,可能被反复使用时,都要定义在一个函数内,
  3. 函数内部
    this
    this是JavaScript中的一个关键字,当一个函数被调用时,除了传入函数的显式参数以外,名为this的隐式参数也被传入了函数。
    this参数指向了一个自动生成的内部对象,这个内部对象被称为函数上下文。
    JavaScript中的this依赖于函数的调用方式。
    this的指向是在函数执行时确定的,即:调用函数的那个对象。

5.为什么要用nodejs?
1⃣️动态语言:V8引擎,无阻塞、事件驱动,开发效率非常高,并有能力构建复杂系统。
2⃣️性能和I/O负载:Nodejs非常好的解决了IO密集的问题,通过异步IO来实现。
3⃣️连接的内存开销:每个Node.js进程可以支持超过12万活跃的连接,每个连接消耗大约2K的内存。
4⃣️操作性:实现了Nodejs对于内存堆栈的监控系统。

6.nodejs的特点?
其特点为:

它是一个Javascript运行环境

依赖于Chrome V8引擎进行代码解释

事件驱动

非阻塞I/O

轻量、可伸缩,适于实时数据交互应用

单进程,单线程

7. NodeJS的优缺点


优点:
高并发(最重要的优点)
适合I/O密集型应用
缺点:
不适合CPU密集型应用;CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起;
解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起;

只支持单核CPU,不能充分利用CPU
可靠性低,一旦代码某个环节崩溃,整个系统都崩溃

原因:单进程,单线程

解决方案:(1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;

(2)开多个进程监听同一个端口,使用cluster模块; 

cluster

集群
单个Nodejs实例运行在单个线程中,为充分利用多核系统,需要启用一组Node进程处理负载任务。

cluster允许建立一个主进程和若干个worker进程,由主进程监控和协调worker进程的运行。
worker之间采用进程通信交换消息,cluster模块内置一个负载均衡

开源组件库质量参差不齐,更新快,向下不兼容

Debug不方便,错误没有stack trace

8. es6语法

ES6中声明变量的方式:

//1.使用let声明
let a = 10;

//2.使用const声明
const name = "小红";

2. var ,let , const 的区别:

  1. 不存在变量提升

    • var 命令会发生变量提升现象,即变量可以在声明之前使用,值为undefined
    • let 和 const 则没有变量声明提升的功能,必须要先声明才能使用
  2. 不允许重复声明

    • var命令能重复声明,后者覆盖前者
    • let 和 const不允许在相同作用域内,重复声明同一个变量
  3. 作用域

    • var 的作用域是以函数为界限
    • let 和 const 的作用域是块作用域,块级作用域指 { } 内的范围
    • var 可以定义全局变量和局部变量,let 和 const 只能定义局部变量
    • const 的声明的常量不能被修改,但对于引用类型来说,堆内存中的值是可以被改变的。

常量定义的引用类型可以修改,如:

        //1.使用常量定义数组
        const arr = [100, 200, 300];
        console.log(arr);

        arr[0] = "hello";
        console.log(arr);   //['hello', 200, 300]

        //2.使用常量来定义对象
        const obj = {
            name: "Jack",
            age: 22,
            no: "001"
        }
        console.log(obj);

        obj.age = 100;
        console.log(obj);   //{name: "Jack", age: 100,  no: "001"}

箭头函数

ES6 中函数式声明方式被箭头函数 => 取代
箭头函数:使用 => 定义函数

1.1 什么是箭头函数

ES6中允许使用=>来定义函数。箭头函数相当于匿名函数,并简化了函数定义。

1.2 基本语法

// 箭头函数

let fn = (name) => {

    // 函数体

    return `Hello ${name} !`;

};



// 等同于

let fn = function (name) {

    // 函数体

    return `Hello ${name} !`;

};
//栗子2

//普通函数

    var result = [2, 4, 5, 1, 6].sort(function (a, b) {

        return a - b;

    });

//ES6箭头函数

    var result = [2, 4, 5, 1, 6].sort((a, b) => a - b);

箭头函数在语法上比普通函数简洁多。箭头函数就是采用箭头=>来定义函数,省去关键字function。

函数的参数放在=>前面的括号中,函数体跟在=>后的花括号中

箭头函数用于回调函数,常见简洁

//栗子1

//普通函数

    [1, 2, 3].map(function (x) {

        return x + x;

    });

//ES6箭头函数

[1, 2, 3].map(x => x + x);

箭头函数this指向

  1. 箭头函数没有this,this是父级的
  2. 定义时候绑定,就是this是继承自父执行上下文!!中的this
  3. ES5中,this指调用者,ES6中,this指定义时候绑定

ES6 新增字符串方法

//字符串新增方法:
方法                返回值          作用
includes('str')     boolean         判断字符串中包含子串
endWith('str')      boolean         判断字符串以"str"结尾
startWith('str')    boolean         判断字符串以"str"开头
repeat(n)           重复拼接自身     重复n次输出字符串 repeat + repeat

//不全方法: 补全字符串长度
padStart(length, s);        字符串开头补全
endStart(length, s);        字符串末尾补全

ES6 Promise 解决回调地狱

 promise:为了解决异步编程中的回调地狱而产生

异步编程的一种解决方案,其实是一个构造函数,自己身上有 all、reject、resolve 这几个方法,原型上有 then、catch 等方法。

Promise的实例需要接收一个函数作为参数
该函数又需要接收两个函数数作为参数
resolve 函数
reject 函数

promise 的三种状态

pending 进行中
fullfilled 已成功 resolved 成功 执行resolve函数
rejected 已失败 rejected 失败 执行reject函数

then方法

参数一:是resolve函数的实现
参数二:是reject函数的实现

数组解构

let arr = [1, 2, 3];

//不使用数组解构
let a = arr[0];
let b = arr[1];
let c = arr[2];

//数组解构写法
let [a, b, c] = arr;
console.log(a, b, c);

对象解构

const person = {
  name: "jack",
  age: 21,
  language: ["java", "js", "css"],
};

//普通写法
const name = person.name;
const age = person.age;
const language = person.language;

//对象解构写法
const { name, age, language } = person;

//解构后修改变量名name为abc
const { name: abc, age, language } = person;

扩展运算符

  • 1、拷贝对象
1
2
3
4
//取出参数对象所有可遍历属性拷贝进当前对象
let p1 = { name: "Amy", age: 15 };
let someone = { ...p1 };
console.log(someone); //{name: "Amy", age: 15}
  • 2、合并对象
1
2
3
4
5
6
// 2、合并对象
let age1 = { age: 15 }
let name1 = { name: "Amy" }
let p2 = {name:"zhangsan"}
p2 = { ...age1, ...name1 } 
console.log(p2)

map

接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回。

let arr = ['1', '20', '-5', '3'];
arr = arr.map((item)=>{
    return item*2
});
arr = arr.map(item=> item*2);
console.log(arr); //2 40 -10 6

node  开发效率高,并有能力构建复杂系统 解决了 i/o密集  javascript 运行环境 轻量可伸缩  单线程  优点 高并发 

redis 是一个支持持久化的内存数据库  

缓存雪崩  由于原有缓存失效,新缓存未到期间  加锁

缓存穿透  查缓存 查数据库  布隆过滤器 拦截 

数据类型 string hash list set   sorted set 

egg  提供定制上层框架的能力 高度可扩展插件机制(单元测试 日志中间件)  内置多线程  框架稳定  安全

express callback 回调 异常不可捕获  es5  node 的基础框架 体积大 

  • 回调地狱问题;
  • 很难处理错误异常。

koa web 开发框架  无回调 异步处理 健壮 es7  高级语法糖 轻量级 async await 

express 和koa 区别 

编程模型上的区别。Koa 的中间件是U型的,Express的中间件是线性的。

cookie 和session 的区别 

cookie请求无状态  web想知道发起人服务端通过响应头 set-cookie 将少量数据响应给客户端 最后浏览器保存 

session 实现基于cookie  用户session 加密后直接存储在cookie中的一个字段 用户请求  存储在服务器

传统的 session 认证
session

http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
 基于session 认证暴露的问题

1. 内存开销大 

2.扩展性不强

3.csrf

token
token校验过程

用户第一次登录时,服务端生成Token并返回给客户端,保存在客户端的 localStorage
以后再访问时,需要携带token,将携带的token和在服务端保存的 token 信息进行比对校验
token缺陷

客户端每次登录时,依然需要访问数据库进行查询,并没有减轻对数据库的访问压力
jwt 

用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

token 结构

头部 载荷 签证

token传递过程

  • 用户第一次登录成功后,使用 jwt 创建一个 token,并给用户返回,保存在客户端的 localStorage 中
  • 以后用户再次访问时,需要携带 token,服务端获取token后,再做 token 的校验(服务端不存储token)

token校验过程

服务端获取token后,对token进行切割,切割为三部分
对第二段密文进行 base64url 解密为明文,并获取 payload 信息,检测 token 是否已经超时?
把第1、2段密文拼接,再次执行 HS256 加密,将加密后的密文 与 使用 base64url 解密后的第3段密文进行比较,如相等,则 token 未被修改过(认证通过)
jwt 优势

1.跨语言支持

2.有了 payload 部分,JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息

3.jwt构成简单,便于传输

4.不需要在服务端保存会话信息,易于应用的扩展

docker 轻量,私密paas环境 自动化测试 持续集成部署

跨域

端口域名 协议

一、什么是跨域?
在了解跨域之前,首先要知道什么是同源策略(same-origin policy)。简单来讲同源策略就是浏览器为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的JS进行交互。对于浏览器而言只要域名、协议、端口其中一个不同就会引发同源策略,从而限制他们之间如下的交互行为:

怎么解决跨域

1.jsonp

通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。(即用JavaScript动态加载一个script文件,同时定义一个callback函数给script执行而已。)

<script src="http://example.com/data.php?callback=dosomething"></script>

2. 后端使用cors

//跨域问题解决方面
const cors = require('cors'); 
app.use(cors({
  origin: ['http://localhost:8080','http://www.baidu.com'],//可设置多个跨域域名
  credentials: true//允许客户端携带验证信息
}))

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值