JavaScript

1、js数据类型

  • 基本数据类型:Number、String、Boolean、Null、Undefined、Symbol、bigInt
  • 引用数据类型:object、Array、Date、Function、RegExp

基本数据类型与引用类型在存储上有什么区别?
1.存储位置不同:
基本数据类型:以栈的形式存储, 保存与赋值指向数据本身, 用typeof 来判断类型,存储空间固定。
引用类型:以堆的形式存储, 保存于赋值指向对象的一个指针, 用instanceof 来判断类型 , 存储空间不固定。

2.传值方式不同:
基本数据类型按值传递,无法改变一个基本数据类型的值
引用类型按引用传递,应用类型值可以改变

NaN 是什么
NaN 即非数值(Not a Number),NaN 属性用于引用特殊的非数字值,该属性指定的并不是不合法的数字。
NaN 属性 与 Number.Nan 属性相同。

请使用 isNaN() 来判断一个值是否是数字。原因是 NaN 与所有值都不相等,包括它自己。

js中本地对象?内置对象?宿主对象?
本地对象:ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。

包含了:Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError。

内置对象:ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。包含了:Gobal 和 Math。

宿主对象:由ECMAScript实现的宿主环境提供的对象,可以理解为:浏览器提供的对象。所有的BOM和DOM都是宿主对象。

栈和堆的区别?
栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;
堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释放。

描述以下变量的区别:null,undefined或undeclared
null 表示"没有对象",即该处不应该有值,转为数值时为0。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。

undefined 表示"缺少值",就是此处应该有一个值,但是还没有定义,转为数值时为NaN。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
undeclared :js语法错误,没有申明直接使用,js无法找到对应的上下文。

for..in 和 object.keys的区别
Object.keys不会遍历继承的原型属性
for...in 会遍历继承的原型属性

JS中的匿名函数是什么?
匿名函数:就是没有函数名的函数,如:

(function(x, y){ alert(x + y); })(2, 3);

这里创建了一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数,并传入参数。

解释 JS 中的函数提升
JS允许将声明移动到顶部的默认行为称为提升。JS中创建函数的两种方法是函数声明和函数表达式。

Js隐式转换介绍
在js中,当运算符在运算时,如果两边数据不统一,CPU就无法计算,这时我们编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算

这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换
例如1 > "0"这行代码在js中并不会报错,编译器在运算符时会先把右边的"0"转成数字0`然后在比较大小

隐式转换规则:

  1. 转成string类型: +(字符串连接符)
    2.转成number类型:++/--(自增自减运算符) + - * / %(算术运算符) > < >= <= == != === !=== (关系运算符)
  2. 转成boolean类型:!(逻辑非运算符)

2、js变量和函数声明的提升

  • 在js中变量和函数的声明会提升到最顶部执行
  • 函数的提升高于变量的提升
  • 函数内部如果用 var 声明了相同名称的外部变量,函数将不再向上寻找。
  • 匿名函数不会提升。

3、闭包

  • 闭包的概念:js的作用域中内部函数可以访问外部函数的变量,反之则不行,但是我们为能够达到这一目的,就使用内部函数应用外部函数的变量,把该内部函数通过外部函数return到外部去执行,就形成了闭包。
    (就是能够读取其他函数内部变量的函数,基本上就是一个函数内部返回一个函数)

  • 优点:
    1、可以读取函数内部的变量
    2、将变量始终保持在内存中
    3、可以封装对象的私有属性和私有方法
    4、避免全局变量的污染

  • 缺点:
    1、较耗费内存、使用不当会造成内存溢出的问题

  • 应用场景: 防抖(清除旧定时器,开始新的定时器)、节流(上一个定时器没有结束,则return 不执行新的定时器)、封装功能时(需要使用私有的属性和方法)、函数柯里化、给元素伪数组添加事件需要使用元素的索引值。

Object.is()与原来的比较操作符"==="、"==” 的区别?
1)两等号判等,会在比较时进行类型转换;
2)三等号判等(判断严格),比较时不进行隐式类型转换,(类 型不同则会返回false);
3)Object.is 在三等号判等的基础上特别处理了NaN、-0和+0,保证-0和+0不再相同,但Object.is(NaN, NaN)会返回true。Object.is应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。

4、== 和 ===的区别

  • ==是非严格意义上的相等 值相等就相等

  • ===是严格意义上的相等,会比较两边的数据类型和值大小 值和引用地址都相等才相等

  • 1、对于string,number等基础类型,==和===有区别

  • 1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等。
    2)同类型比较,直接进行“值”比较,两者结果一样。

2、对于Array,Object等高级类型,==和===没有区别
进行“指针地址”比较。

3、基础类型与高级类型,==和===有区别
1)对于==,将高级转化为基础类型,进行“值”比较。
2)因为类型不同,===结果为false。

5、this

  • this总是指向函数的直接调用者
  • 如果有new关键字,this指向new出来的对象
  • 在事件中,this指向触发这个事件的对象

6、js数组和对象的遍历方式

  • for in
  • for
  • forEach
  • for-of

7、map与forEach的区别

  • forEach 方法,是最基本的方法,就是遍历与循环,默认有 3 个传参:分别是遍历的数组内容 item、数组索引 index、和当前遍历数组 Array
  • map 方法,基本用法与 forEach 一致,但是不同的,它会返回一个新的数组,所以 callback需要有 return 值,如果没有,会返回 undefined

8、箭头函数与普通函数的区别?

  • 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象
  • 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误
  • 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 Rest 参数代替
  • 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数

9、同源策略

  • 同源指的是域名、协议、端口号相同

10、如何解决跨域
因为浏览器存在同源策略,协议+域名+端口 必须完全一致不然就会受到浏览器同源策略限制造成跨域。
跨域有如下常用方法:
1、proxy
2、jsonp 原理是利用<script src="https://xxx/a.html?callback=fnName"></script>不是同源策略限制
3、跨域资源贡献(CORS)服务端设置Access-Control-Allow-Origin即可
4、window.name + iframe 原理是window.name保存的字符串数据可以跨不同页面和不同的域
5、h5的postMessage() + window.onmessage() 再不同页面(或iframe)之间发送消息和接受消息
6、nginx代理 原理是因为跨域是存在与浏览器端,所以通过反向代理通过服务端获取数据
7、后端在头部信息里面设置安全域名

11、严格模式的限制

  • 变量必须声明后再使用
  • 函数的参数不能有同名属性,否则报错
  • 不能使用 with 语句
  • 禁止 this 指向全局对象

12、es6新增

  • 新增模板字符串
  • 箭头函数
  • for-of(用来遍历数据—例如数组中的值。)
  • ES6 将 Promise 对象纳入规范,提供了原生的 Promise 对象。
  • 增加了 let 和 const 命令,用来声明变量。
  • 还有就是引入 module 模块的概念

13、attribute 和 property 的区别是什么?

  • attribute 是 dom 元素在文档中作为 html 标签拥有的属性
  • property 就是 dom 元素在 js 中作为对象拥有的属性。
  • 对于 html 的标准属性来说,attribute 和 property 是同步的,是会自动更新的
  • 但是对于自定义的属性来说,他们是不同步的

14、let和const 的区别是什么?

  • let 命令不存在变量提升,如果在 let 前使用,会导致报错
  • 如果块区中存在 let 和 const 命令,就会形成封闭作用域
  • 不允许重复声明
  • const定义的是常量,不能修改,但是如果定义的是对象,可以修改对象内部的数据

15、内存泄漏

  • 定义:程序中己动态分配的堆内存由于某种原因程序未释放或无法释放引发的各种问题。
  • js中可能出现的内存泄漏情况:结果:变慢,崩溃,延迟大等
  • js中可能出现的内存泄漏原因1、全局变量2、dom 清空时,还存在引用3、定时器未清除4、子元素存在引起的内存泄露

16、script 引入方式?

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

17、数组(array)方法

  • map : 遍历数组,返回回调返回值组成的新数组
  • forEach : 无法 break ,可以用 try/catch 中 throw new Error 来停止
  • filter : 过滤
  • some : 有一项返回 true ,则整体为 true
  • every : 有一项返回 false ,则整体为 false
  • join : 通过指定连接符生成字符串
  • push / pop : 末尾推入和弹出,改变原数组, 返回推入/弹出项
  • unshift / shift : 头部推入和弹出,改变原数组,返回操作项
  • sort(fn) / reverse : 排序与反转,改变原数组
  • concat : 连接数组,不影响原数组, 浅拷贝
  • slice(start, end) : 返回截断后的新数组,不改变原数组
  • splice(start,number,value…): 返回删除元素组成的数组,value 为插入项,改变原数组
  • indexOf / lastIndexOf(value, fromIndex) : 查找数组项,返回对应的下标
  • reduce / reduceRight(fn(prev, cur) ,defaultPrev) : 两两执行,prev 为上次化简函数的return 值,cur 为当前值(从第二项开始)

18、JavaScript 深浅拷贝?

  • 浅拷贝:Object.assign
  • 深拷贝:可以通过 JSON.parse(JSON.stringify(object)) 来解决

19、说说异步编程的实现方式?

  • 回调函数
    优点:简单、容易理解
    缺点:不利于维护、代码耦合高
  • 事件监听
    优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数
    缺点:事件驱动型,流程不够清晰
  • 发布/订阅(观察者模式)
    类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者
  • Promise 对象
    优点:可以利用 then 方法,进行链式写法;可以书写错误时的回调函数
    缺点:编写和理解,相对比较难
  • Generator 函数
    优点:函数体内外的数据交换、错误处理机制
    缺点:流程管理不方便
  • async 函数
    优点:内置执行器、更好的语义、更广的适用性、返回的是 Promise、结构清晰
    缺点:错误处理机制
    20、说说面向对象编程思想?
  • 基本思想是使用对象,类,继承,封装等基本概念来进行程序设计
  • 优点1、易维护2、易扩展3、开发工作的重用性、继承性高,降低重复工作量。4、缩短了开发周期

21、项目性能优化

  • 减少 HTTP 请求数
  • 减少 DNS 查询
  • 使用 CDN
  • 避免重定向
  • 图片懒加载
  • 减少 DOM 元素数量
  • 减少 DOM 操作
  • 使用外部 JavaScript 和 CSS
  • 压缩 JavaScript、CSS、字体、图片等
  • 优化 CSS Sprite
  • 使用 iconfont
  • 多域名分发划分内容到不同域名
  • 尽量减少 iframe 使用
  • 避免图片 src 为空
  • 把样式表放在 link 中
  • 把 JavaScript 放在页面底部

22、什么是单线程,和异步的关系?

  • 单线程 :只有一个线程,只能做一件事
  • 原因 : 避免 DOM 渲染的冲突;浏览器需要渲染 DOM;JS 可以修改 DOM 结构;JS 执行的时候,浏览器 DOM 渲染会暂停;两段 JS 也不能同时执行(都修改 DOM 就冲突了);webworker 支持多线程,但是不能访问 DOM
  • 解决方案 :异步

23、说说负载均衡?

  • 单台服务器共同协作,不让其中某一台或几台超额工作,发挥服务器的最大作用
  • http 重定向负载均衡:调度者根据策略选择服务器以 302 响应请求,缺点只有第一次有效果,后续操作维持在该服务器 dns 负载均衡:解析域名时,访问多个 ip 服务器中的一个(可监控性较弱)原因 - 避免 DOM 渲染的冲突
  • 反向代理负载均衡:访问统一的服务器,由服务器进行调度访问实际的某个服务器,对统一的服务器要求大,性能受到 服务器群的数量

24、作用域链?

  • 作用域链可以理解为一组对象列表,包含 父级和自身的变量对象,因此我们便能通过作用域链访问到父级里声明的变量或者函数

25、什么是原型、原型链、继承?

  • 原型:js中一切皆对象,对象都有一个隐式的属性proto,它指向该对象的原型-prototype(原型对象)
  • 原型链:我们调用对象的某个属性,如果该对象上没有该属性,则会向上在该对象的原型对象上找,有则返回,如果没有的话继续向原型的原型上找,直到Object的原型,Object的prototype为null,如果没有找到该属性则返回undefind。我们把整个访问的过程称为原型链

通过Object.create(null) 创建的对象没有原型对象

26、JS垃圾回收机制是怎样的?

1.概述

  • js的垃圾回收机制是为了防止内存泄漏(已经不需要的某一块内存还一直存在着),垃圾回收机制就是不停歇的寻找这些不再使用的变量,并且释放掉它所指向的内存。
  • 在JS中,JS的执行环境会负责管理代码执行过程中使用的内存。

2.变量的生命周期

  • 当一个变量的生命周期结束之后,它所指向的内存就会被释放。js有两种变量,局部变量和全局变量,局部变量是在他当前的函数中产生作用,当该函数结束之后,该变量内存会被释放,全局变量的话会一直存在,直到浏览器关闭为止。

3.js垃圾回收方式

  • 有两种方式: 标记清除、引用计数
  • 标记清除:大部分浏览器使用这种垃圾回收,当变量进入执行环境(声明变量)的时候,垃圾回收器将该变量进行了标记,当该变量离开环境的时候,将其再度标记,随之进行删除。
  • 引用计数:这种方式常常会引起内存的泄露,主要存在于低版本的浏览器。它的机制就是跟踪某一个值得引用次数,当声明一个变量并且将一个引用类型赋值给变量得时候引用次数加1,当这个变量指向其他一个时引用次数减1,当为0时出发回收机制进行回收。

27、逐进增强和优雅降级

  • 逐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高版本浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
  • 优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容

28、队列、堆、栈的区别?
队列是先进先出:就像一条路,有一个入口和一个出口,先进去的就可以先出去。而栈就像一个箱子,后放的在上边,所以后进先出。堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。

栈(Stack)是操作系统在建立某个进程时或者线程为这个线程建立的存储区域。在编程中,例如C/C++中,所有的局部变量都是从栈中分配内存空间,实际上也不是什么分配,只是从栈顶向上用就行,在退出函数的时候,只是修改栈指针就可以把栈中的内容销毁,所以速度最快。
堆(Heap)是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。由于从操作系统管理的内存分配所以在分配和销毁时都要占用时间,所以用堆的效率低的多!但是堆的好处是可以做的很大,C/C++对分配的Heap是不初始化的。
在Java中除了简单类型(int,char等)都是在堆中分配内存,这也是程序慢的一个主要原因。但是跟C/C++不同,Java中分配Heap内存是自动初始化的。在Java中所有的对象(包括int的wrapper Integer)都是在堆中分配的,但是这个对象的引用却是在Stack中分配。也就是说在建立一个对象时从两个地方都分配内存,在Heap中分配的内存实际建立这个对象,而在Stack中分配的内存只是一个指向这个堆对象的指针(引用)而已。

29、什么是线程?进程和线程的关系是什么?
线程可定义为进程内的一个执行单位,或者定义为进程内的一个可调度实体。 在具有多线程机制的操作系统中,处理机调度的基本单位不是进程而是线程。一个进程可以有多个线程,而且至少有一个可执行线程。
打个比喻:进程好比工厂(计算机)里的车间,一个工厂里有多个车间(进程)在运转,每个车间里有一个或多个工人(线程)在协同工作,这些工人就可以理解为线程。
线程和进程的关系:

1.线程是进程的一个组成部分.
2.进程的多个线程都在进程地址空间活动.
3.系统资源是分配给进程的,线程需要资源时,系统从进程的资源里分配给线程.
4.处理机调度的基本单位是线程.

30、使用原生js实现ajax
创建一个 XMLHttpRequest 对象。如果不支持创建该对象的浏览器,则需要创建 ActiveXObject,具体方法如下:

var xmlHttpRequest;
function createXmlHttpRequest(){
  if(window.XMLHttpRequest)//非IE
    xmlHttpRequest = new XMLHttpRequest();
  else if(window.ActiveObject)//IE6+
    xmlHttpRequest = new ActiveObject("Msxml2.XMLHTTP");
  else//IE6-
    xmlHttpRequest = new ActiveObject("Microsoft.XMLHTTP");
}

提交请求的方法:

open(method,url);//分别为提交的方法(GET或者POST)和提交的url
send(content);
onreadystatechange(){
  if(xmlHttpRequest.readyState == 4){
    if(xmlHttpRequest.state == 200){
      //请求成功
    }  
  }else{
    //请求失败
  }
}

字符串的常用方法

  • indexOf() 查找某字符串对应的下标,如果找不到返回-1
  • split(sep) 将字符串按照指定的字符切割成数组元素,sep表示指定的字符
  • slice(start,end) 截取字符串,start开始的下标,end结束的下标,不包含end本身;如果end为空截取到最后,如果为负数表示倒数。
  • substr(start,count) 截取字符串,start开始的下标,count截取的长度,如果count为空截取到最后,如果start为负值表示倒数
  • substring(start,end) 截取字符串,start开始的下标,end结束的下标,不包含end本身,如果end为空截取到最后;如果下标为负数,自动转为0

*31、Set、Map、和Array的异同、用法
Set:创建类似数组的数据结构,但成员是唯一(基本数据类型无重复,应用数据类型可以重复)

常用方法:size()、add()、delete()、clear()、has()可以使用该方法求交集/差集、keys()、values()、entries()、forEach()

Map:以键值对的行书存储数据,key可以是任何数据类型

常用方法:size()、set(key,value)、get(key)、delete()、clear()、has()、keys()、values()、entries()、forEach()

Set/Map转Array:

Array.from(set)

const arr = [ ...set ]

const arr = [ ...map.values ]

宏任务微任务
js是单线程,但是它有个事件队列机制来处理异步操作,事件队列中有包含宏任务和微任务。像常用的setTimeout,setInterval就是宏任务,Promise()的.then(()=>{})/.catch(()=>{})/.finally(()=>{}) 回调都是微任务。js先执行主线程任务,然后看如果有可以执行的微任务就会被执行,再看如果有宏任务就被执行,执行完继续主线程任务-然后就一遍一遍这循环执行,这也就是它的事件循环机制

深拷贝、浅拷贝
js的数据类型分为基本数据类型(Number/String/Boolean/Null/undefind)和引用数据类型Object(包含Function
/Array/Date/Regex)。浅拷贝对基本数据类型来说拷贝的是值,但对引用数据类型来说拷贝的只是引用, 深拷贝针对的是引用数据类型,拷贝的是值。

我们常用的拷贝方法有:

  • Object.assgin() 仅第一层是深拷贝
  • ES6的扩展运算符(...)仅第一层是深拷贝
  • JSON.parse( JSON.stringify(target) ) 会丢失函数、会把时间对象变成字符串、会把正则对象变成空对象

利用递归手写深拷贝方法

function deepClone1(obj) {
  var objClone = Array.isArray(obj) ? [] : {};
  if (obj && typeof obj === "object") {
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (obj[key] && typeof obj[key] === "object") {
          objClone[key] = deepClone1(obj[key]);
        } else {
          objClone[key] = obj[key];
        }
      }
    }
  }
  return objClone;
}

数组去重

  • 利用对象访问属性的方法,判断对象中是否存在key
  • 利用reduce方法遍历数组,reduce第一个参数是遍历需要执行的函数,第二个参数是item的初始值
var obj={};
var arr=arr.reduce(function(item,next) {
obj[next.key]?'':obj[next.key]=true&&item.push(next);
returnitem;
 }, []);
  • 利用new Set() 去重,去重之后可以通过Array.from(set)或者 [...set] 把set转回数组

cookie sessionstorage localstorage 的异同

  • 相同点:都可以存储数据

  • 不同点:
    存储大小:cookie 4KB
    sessionstorage和localstorage 5MB

  • 生命周期:
    cookie 可以手动设置过期时间
    sessionstorage 当前会话,关闭窗口或浏览器就被删除
    localstorage 永久保存 除非手动删除

  • 使用api:
    cookie 操作的是字符串 比较麻烦需要手动封装方法
    sessionstorage和localstorang的话有自己的getItem()和setItem()、clear()方法,使用起来比较方便

apply()、call()、bind() 之间的异同

  • 相同点:三个都是改变this指向的。
    函数.call(对象,arg1,arg2....)函数.apply(对象,[arg1,arg2,...])var ss=函数.bind(对象,arg1,arg2,....)

  • 区 别:call()和apply()第一个参数是指定的对象,call()之后的参数是传入该函数的值
    apply()第二个参数是数组,数组中是函数执行需要的参数
    bind()和call()的参数相同,不同的是bind()改变this的指向后不会立即执行,其他两个是立即执行的

1.第一个参数都是指定函数内部中this的指向(函数执行时所在的作用域),然后根据指定的作用域,调用该函数。
2.都可以在函数调用时传递参数。call,bind方法需要直接传入,而apply方法需要以数组的形式传入。
3.call,apply方法是在调用之后立即执行函数,而bind方法没有立即执行,需要将函数再执行一遍。
4.改变this对象的指向问题不仅有call,apply,bind方法,也可以使用that变量来固定this的指向。

使用bind()的时候最好不要直接绑定在Dom上,避免当Dom变化时需要重新绑定

防抖、节流函数

  • 防抖:代码实现重在清零clearTimeout
function debounce(f, wait) {
    lettimer
    return (...args) = >{
        clearTimeout(timer) timer = setTimeout(() = >{
            f(...args)
        },
        wait) 
    }
}
  • 节流:代码实现重在开锁关锁timer=timeout; timer=null
function throttle(f, wait) {
    lettimer
    return (...args) = >{
        if (timer) {
            return
        }
        timer = setTimeout(() = >{
            f(...args)
            timer = null
        },
        wait)
    }
}

数组降维
Array.prototype.concat.apply([],targetArr);

判断数据类型

function toType(obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

箭头函数和普通function的区别
1、写法不同
2、this指向不同
function中的this执行环境的不同而不同
箭头函数的this是它自己执行环境最近非箭头函数的this
3、function可以被new 实例化,箭头函数不可以
4、function可以被声明提前,箭头函数不可以,必须先声明后使用不然会报错

数组的常用方法
改变原数组的:push()、pop()、unshift()、shift()、splice() 、sort()、reverse()
不改变原数组:join()、slice()、map()、filter()、forEach()、some()、every()、find()、reduce()

new 操作符具体做了什么
1、创建了一个空对象 let obj = {}
2、继承了该函数的原型 obj._ protp_= Fn.prototype
3、改变了该函数的this指向 let result = Fn.call(obj,...args)
4、判断该函数的返回值,如果该返回值是基本数据类型则 return obj ,否则 return result

Promise

  • 它用于异步操作,它是一个构造函数,接收一个回调函数,用于异步计算,可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果而且可以在对象之间传递和操作promise,帮助我们处理队列。
  • 有三个状态:
    1、pending[待定]初始状态
    2、fulfilled[实现]操作成功
    3、rejected[被否决]操作失败
  • 常用方法:
    1、then()、catch()、finally()
    2、all([])接收一个数组,当所有的异步请求完成之后才完成,一旦有某个异步请求报错,则直接catch
    3、race([])也接收一个数组,但它是抢占执行,一旦有一个异步请求完成就算完成了

函数柯里化
概念:把一个接收多个参数的函数变成接收单一参数 并且返回能够接收新参数的函数

add(1)(2)(3)(4) = 10;
function add(num) {  
    var sum = num;  
    var fn = function(v) {    sum += v;    
        return fn  
    };  fn.toString = function() {    
        return sum  
    };  
    return fn
}
console.log(add(1)(2)(3)(4)) // 10

斐波那契数列
eg:1、1、2、3、5、8、13...

function fibonacci(n) {
    if (n == 1 || n == 2) {
        return1
    };
    returnfibonacci(n - 2) + fibonacci(n - 1);
}
fibonacci(30)

ES5 和 ES6 分别几种方式声明变量

  • ES5 有俩种:var 和 function
  • ES6 有六种:增加四种,let、const、class 和 import

什么是事件代理/事件委托?
事件代理/事件委托是利用事件冒泡的特性,将本应该绑定在多个元素上的事件绑定在他们的祖先元素上,尤其在动态添加子元素的时候,可以非常方便的提高程序性能,减小内存空间。

什么是事件冒泡?什么是事件捕获?
冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。

捕获型事件:事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。

在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。

注意:IE浏览器用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。

如何阻止事件冒泡?
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true。例如:

window.event.cancelBubble = true;e.stopPropagation();

return false也可以阻止冒泡。

如何阻止默认事件?
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false,比如:

functionstopDefault(e) {
 //IE中阻止函数器默认动作的方式
    if (e && e.preventDefault) e.preventDefault();   
   else window.event.returnValue = false; 
}

return false也能阻止默认行为。

DOM 事件有哪些阶段?谈谈对事件代理的理解
分为三大阶段:捕获阶段--目标阶段--冒泡阶段

事件代理简单说就是:事件不直接绑定到某元素上,而是绑定到该元素的父元素上,进行触发事件操作时(例如'click'),再通过条件判断,执行事件触发后的语句(例如'alert(e.target.innerhtml)')

好处:(1)使代码更简洁;(2)节省内存开销

如何用原生js给一个按钮绑定两个onclick事件?

使用addEventListener的方式来绑定多个事件。例如

var btn = document.getElementById('btn') btn.addEventListener('click', fn1) btn.addEventListener('click', fn2) functionfn1() {
    console.log('我是方法1')
}
functionfn2() {
    console.log('我是方法2')
}

响应事件有哪些?
onclick鼠标点击某个对象;onfocus获取焦点;onblur失去焦点;onmousedown鼠标被按下等,常用的如下:

1、鼠标单击事件( onclick )
2、鼠标经过事件( onmouseover )
3、鼠标移开事件( onmouseout )
4、光标聚焦事件( onfocus )
5、失焦事件( onblur )
6、内容选中事件( onselect )
7、文本框内容改变事件( onchange )
8、加载事件( onload )
9、卸载事件( onunload )

造成内存泄露的原因
1、意外的全局变量(在函数内部没有使用var进行声明的变量)
2、console.log
3、闭包
4、对象的循环引用
5、未清除的计时器
6、DOM泄露(获取到DOM节点之后,将DOM节点删除,但是没有手动释放变量,拿对应的DOM节点在变量中还可以访问到,就会造成泄露)

javascript中this的指向
this永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。
普通的函数调用,函数被谁调用,this就是谁。
构造函数的话,如果不用new操作符而直接调用,那即this指向window。用new操作符生成对象实例后,this就指向了新生成的对象。
匿名函数或不处于任何对象中的函数指向window 。
如果是call,apply等,指定的this是谁,就是谁。

谈谈this的理解

  1. this总是指向函数的直接调用者(而非间接调用者)
  2. 如果有new关键字,this指向new出来的那个对象
  3. 在事件中,this指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window。

eval是做什么的?
它的功能是把对应的字符串解析成JS代码并运行;应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。

Javascript作用链域
作用域链的原理和原型链很类似,如果这个变量在自己的作用域中没有,那么它会寻找父级的,直到最顶层。

注意:JS没有块级作用域,若要形成块级作用域,可通过(function(){})();立即执行的形式实现

继承(6种方式)以及优缺点
1.原型链继承
2.构造函数继承
3.组合继承(原型链继承+构造函数继承)
4.原型式继承
5.寄生继承
6.组合寄生继承

请解释变量声明提升
通过var声明的变量会被提升至作用域的顶端。不仅仅是变量,函数声明也一样会被提升。
当同一作用域内同时出现变量和函数声明提升时,变量仍然在函数前面。

函数声明与函数表达式的区别?
在Javscript中,解析器在向执行环境中加载数据时,对函数声明和函数表达式并非是一视同仁的,解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问),至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行

什么是window对象? 什么是document对象?
window对象代表浏览器中打开的一个窗口。document对象代表整个html文档。实际上,document对象是window对象的一个属性。

document.onload和document.ready两个事件的区别
页面加载完成有两种事件
一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件)
二是onload,指示页面包含图片等文件在内的所有元素都加载完成。

Js的浅拷贝和深拷贝
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

浅拷贝
// 第一层为深拷贝Object.assign()Array.prototype.slice()扩展运算符 ...深拷贝
JSON.parse(JSON.stringify())递归函数

function cloneObject(obj) {
  var newObj = {} 
  //如果不是引用类型,直接返回
  if (typeof obj !== 'object') {return obj }
 //如果是引用类型,遍历属性
  else {for (var attr in obj) {
  //如果某个属性还是引用类型,递归调用 
  newObj[attr] = cloneObject(obj[attr]) } }
  return newObj
}

JavaScript里arguments究竟是什么?
Javascrip中国每个函数都会有一个Arguments对象实例arguments,它引用着函数的实参,可以用数组下标的方式"[]"引用arguments的元素。arguments.length为函数实参个数,arguments.callee引用函数自身。在函数代码中,使用特殊对象arguments,开发者无需明确指出参数名,通过使用下标就可以访问相应的参数。

function test() { 
  var s = ""; for (var i = 0; i < arguments.length; i++) { 
  alert(arguments[i]); s += arguments[i] + ","; }return s; 
} 
test("name", "age");//name,age arguments虽然有一些数组的性质,但其并非真正的数组,只是一个类数组对象。其并没有数组的很多方法,不能像真正的数组那样调用.jion(),.concat(),.pop()等方法。

**什么是"use strict";?使用它的好处和坏处分别是什么?**
在代码中出现表达式-"use strict"; 意味着代码按照严格模式解析,这种模式使得Javascript在更严格的条件下运行。

好处:
* 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
* 消除代码运行的一些不安全之处,保证代码运行的安全;
* 提高编译器效率,增加运行速度;
* 为未来新版本的Javascript做好铺垫。

坏处:
同样的代码,在"严格模式"中,可能会有不一样的运行结果;
一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行。

**解释什么是Json**
* JSON 是一种轻量级的数据交换格式。
* JSON 独立于语言和平台,JSON 解析器和 JSON 库支持许多不同的编程语言。
* JSON的语法表示三种类型值,简单值(字符串,数值,布尔值,null),数组,对象

**缓存策略**
1、强缓存:
强缓存两个相关字段:【Expires】-过期时间,【Cache-Control】-过期时长。
强缓存分为两种情况,一种是发送HTTP请求,一种不需要发送。
首先检查强缓存,这个阶段不需要发送HTTP请求,通过查找不同的字段来进行,不同的HTTP版本不同
http1.0版本,使用的是expires,http1.1使用的是cache-control
expires即过期时间,时间是相对于服务器的时间而言的,存在于服务端返回的响应头中,在这个过期时间之·        前可以直接从缓存里面获取数据,无需再次请求。
cache-control,http1.1版本中,使用的是这字段,这个字段采用的时间是过期时长,对应的是max-age
注意点:当expires和cache-control同时存在时,优先考虑cache-control。
当缓存资源失效了,也就是没有命中强缓存,接下来就进入协商缓存

2、协商缓存
强缓存失效后,浏览器在请求头中携带响应的缓存etag来向服务器发送请求,服务器根据对应的tag,来决定是否使用缓存。
分为两种,【last-modified】和【etag】。两者个有优势
last-modified:这个字段表示的是【最后修改时间】,在浏览器第一次个服务器发送请求后,服务器会在响应头中加上这个字段。浏览器接收到后,【如果再次请求】,会在请求头中携带 if-modified-since 这个字段,这个字段的值也就是服务器传来的最后修改时间。服务器拿到请求头中的 if-modified-since 的字段后,其实会和这个服务器中 该资源的最后修改时间 做对比:
如果请求头中的这个值小于最后修改时间,说明要更新了,返回新的资源,跟常规的http请求响应的流程一样,否则返回304,告诉浏览器直接使用缓存。

etag:etag是服务器根据当前文件的内容,对文件生成唯一的标识,比如md5算法,只要里面的内容有改动,这个值就会修改,服务器通过响应头把这个字段给浏览器。浏览器接收到etag值,会在下次请求的时候,将这个值作为【if-none-match】这个字段的内容,发送给服务器。服务器接收到这个【if-none-match】字段后,会跟服务器上该资源的【etag】进行比较。

如果两者一样的话,直接返回304,告诉浏览器直接使用缓存,如果不一样的话,说明内容更新了,返回新的资源,跟常规的http请求响应的流程一样。

**22、301、302、303、304状态码有什么区别**

301表示永久重定向,请求的资源分配了新的url
302表示临时重定向,请求的资源分配了新的url,本次暂且使用新的url,下次请求可能会改变
303表示请求的资源路径发生改变,使用GET方法请求新url。她与302的功能一样,但是明确指出使用GET方法请求新url。
304表示请求的资源未更新。该状态码不应该认为是一种错误,而是对客户端有缓存情况下服务端的一种响应。
tips:新url指的是,第一次请求返回的location

**深度优先、广度优先**
  深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。递归
  要特别注意的是,二叉树的深度优先遍历比较特殊,可以细分为先序遍历、中序遍历、后序遍历(我们前面使用的是先序遍历)。具体说明如下:
   先序遍历:对任一子树,先访问根,然后遍历其左子树,最后遍历其右子树。
   中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树。
   后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。
   广度优先遍历:又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止  遍历

**前端安全方面有没有了解?XSS和CSRF如何攻防?**  

> **XSS(Cross Site Scripting)**是跨站脚本攻击,为了区分CSS,所以缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
> 在网页的一些公共区域(例如,建议提交表单或消息公共板的输入表单)输入一些文本,这些文本被其它用户看到,但这些文本不仅仅是他们要输入的文本,同时还包括一些可以在客户端执行的脚本。如:

<script>alert(document.cookie);</script>


在文本框中输入以上代码,然后点击提交,就会把用户的cookie弹出来。

> **XSS漏洞修复**

1.将重要的cookies标记为HTTP ONLY。
2.只允许用户输入我们期望的数据。如年龄框只能输入数字。
3.对数据进行HTTP Encode处理。
4.过滤或者移除特殊的HTML标签。
5.过滤JS事件的标签。

> **CSRF(Cross-site request forgery)**是跨站请求伪造。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。其实就是攻击者盗用了你的身份,以你的名义发送恶意请求。

**CSRF攻击的思想**
用户浏览并登陆信任网站A;通过验证,在用户处产生X的cookie;用户在没有登出X的时候,浏览危险网站B;B要求访问第三方网站A,发出一个请求;根据这个请求,浏览器使用刚才产生的cookie直接访问A。
**一个简单的实例**
银行网站A,它以GET请求来完成银行转账的操作,如:[http://www.mybank.com/Transfer.php?toBankId=11&money=1000](http://www.mybank.com/Transfer.php?toBankId=11&money=1000)
危险网站B,它里面有一段HTML的代码如下:

<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>


首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块......
**CSRF的防御**
1.在表单里增加Hash值,以认证这确实是用户发送的请求,然后在服务器端进行Hash值验证。
2.验证码:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串。

#### 20、说说你对HTML5认识?(是什么,为什么)

> HTML5指的是包括 HTML 、 CSS 和 JavaScript 在内的一套技术组合。 HTML5 是 HTML 最新版本, 2014 年 10 月由万维网联盟( W3C )完成标准制定。

HTML4陈旧不能满足日益发展的互联网需要,特别是移动互联网。为了增强浏览器功能 Flash 被广泛使用,但安全与稳定堪忧,不适合在移动端使用(耗电、触摸、不开放)。
HTML5增强了浏览器的原生功能,符合 HTML5 规范的浏览器功能将更加强大,减少了 Web 应用对插件的依赖,让用户体验更好,让开发更加方便,另外 W3C 从推出 HTML4.0 到 5.0 之间共经历了 17 年, HTML 的变化很小,这并不符合一个好产品的演进规则。
 
**什么是WebGL,它有什么优点?**  

> WebGL(全写 Web Graphics Library )是一种 3D 绘图标准,这种绘图技术标准允许把 JavaScript 和 OpenGL ES 2.0 结合在一起,通过增加OpenGL ES 2.0 的一个 JavaScript 绑定, WebGL 可以为 HTML5 Canvas 提供硬件 3D 加速渲染,这样 Web 开发人员就可以借助系统显卡来在浏览器里更流畅地展示 3D 场景和模型了,还能创建复杂的导航和数据视觉化。显然, WebGL 技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂 3D 结构的网站页面,甚至可以用来设计 3D 网页游戏等等。
> **WebGL完美地解决了现有的 Web 交互式三维动画的两个问题:**
> **第一,它通过HTML脚本本身实现 Web 交互式三维动画的制作,无需任何浏览器插件支持 ;**
> **第二,它利用底层的图形硬件加速功能进行的图形渲染,是通过统一的、标准的、跨平台的OpenGL接口实现的。**
> **通俗说WebGL中 canvas 绘图中的 3D 版本。因为原生的 WebGL 很复杂,我们经常会使用一些三方的库,如 three.js 等,这些库多数用于HTML5 游戏开发。**

**说说你对SVG理解?**  

> SVG可缩放矢量图形( Scalable Vector Graphics )是基于可扩展标记语言( XML ),用于描述二维矢量图形的一种图形格式。 SVG 是W3C('World Wide Web ConSortium' 即 ' 国际互联网标准组织 ') 在 2000 年 8 月制定的一种新的二维矢量图形格式,也是规范中的网络矢量图形标准。 SVG 严格遵从 XML 语法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式。 SVG 于 2003 年 1 月14 日成为 W3C 推荐标准。
> **特点:**
> **(1)任意放缩**
> **用户可以任意缩放图像显示,而不会破坏图像的清晰度、细节等。**
> **(2)文本独立**
> **SVG图像中的文字独立于图像,文字保留可编辑和可搜寻的状态。也不会再有字体的限制,用户系统即使没有安装某一字体,也会看到和他们制作时完全相同的画面。**
> **(3)较小文件**
> **总体来讲,SVG文件比那些 GIF 和 JPEG 格式的文件要小很多,因而下载也很快。**
> **(4)超强显示效果**
> **SVG图像在屏幕上总是边缘清晰,它的清晰度适合任何屏幕分辨率和打印分辨率。**
> **(5)超级颜色控制**
> **SVG图像提供一个 1600 万种颜色的调色板,支持 ICC 颜色描述文件标准、 RGB 、线 X 填充、渐变和蒙版。**
> **(6)交互 X 和智能化。 SVG 面临的主要问题一个是如何和已经占有重要市场份额的矢量图形格式 Flash 竞争的问题,另一个问题就是 SVG 的本地运行环境下的厂家支持程度。**


**介绍一下webpack*
webpack是模块打包机(自动化构建工具),我们常用webpack构建我们的项目框架。在webpack中,包含entry,output,mode,module,plugin,module中我们一般会引入各种loader帮助我们翻译编译代码,(loader是从右往左执行)plugin会引入各种插件,优化构建出来的代码,mode是模式,一般分为development和production。entry是入口,output是出口。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 前言 针对面试的 JavaScript 知识点整理 1.介绍一下js的数据类型有哪些,值是如何存储的 JavaSc...
    Moon_f3e1阅读 227评论 0 0
  • 简介 ECMAScript是JavaScript的标准,JavaScript实现了ECMAScript,ECMAS...
    Zindex阅读 383评论 0 1
  • 1.数据类型 1.1概念篇 7种原始数据类型 引用类型 null是对象吗?为什么? 结论: null不是对象 解释...
    859z阅读 364评论 0 0
  • 1. 基础类型和类型检测 简单类型:Undefined, Null, boolean, number, strin...
    anearseeyou阅读 270评论 0 0
  • JS基础 页面由三部分组成:html:超文本标记语言,负责页面结构css:层叠样式表,负责页面样式js:轻量级的脚...
    小贤笔记阅读 593评论 0 5