文章目录
- 1、原始值和引用值类型及区别
- 2、判断数据类型typeof、instanceof、Object.prototype.toString.call()、constructor
- 3、类数组与数组的区别与转换
- 4、 数组的常见API
- 5、bind、call、apply的区别
- 6、new的原理
- 7、如何正确判断this(区别箭头函数)
- 8、严格模式与非严格模式的区别
- 9、原型和原型链
- 10、prototype与__proto__的关系与区别
- 11、继承的实现方式及比较
- 12、作用域和作用域链、执行上下文
- 13、闭包及其作用
- 14、深拷贝与浅拷贝
- 15、防抖和节流
- 16、Js事件绑定时,函数名加括号和不加括号区别
- 17、DOM常见的操作方式
- 18、 Array.sort()方法与实现机制
- 19、 Ajax的请求过程
- 20、JS的垃圾回收机制
- 21、JS中的String、Array和Math方法
- 22、addEventListener(DOM2级事件处理程序)和onClick()(DOM0级事件处理程序)的区别
- 23、立即执行函数
- 24、整个HTML解析过程与JS脚本解析和执行顺序
- 25、new和Object.create的区别
- 26、DOM的location对象
- 27、浏览器从输入URL到页面渲染的整个流程
- 28、跨域、同源策略及跨域实现方式和原理
- 29、浏览器的回流(Reflow)和重绘(Repaints)
- 30、 JavaScript中的arguments
- 31、EventLoop事件循环(js运行机制)
- 32、宏任务与微任务
- 33、BOM属性对象方法
- 34、浅谈JS变量提升
- 35、JS的map()和reduce()方法
- 36、“ == ”和“===”的区别
- 37、 函数柯里化及其通用封装
- 38、前端缓存
- 39、前端安全
- 31、事件捕获事件冒泡
- 32、js对象属性遍历方法
1、原始值和引用值类型及区别
在ECMAScript 中,变量可存放里两种类型的值,即原始值和引用值。
-
原始值(5种):
- Undefined,
- Null
- Boolean
- Number
- String
原始值指的是代表原始数据类型的值,也叫基本数据类型,是存储在栈(stack)中的简单数据段,也就是说,他们的值是直接存储在变量访问的位置
- 引用值:
- Object
- Function
- Array
- Date
- RegExp
引用类型通常叫做类(class),也就是说,遇到引用值,所处理的就是对象。存储在堆(heap)中的对象,存储在变量处的值是一个指针,指向存储对象的内存处
为变量赋值时,ECMAScript 的解释程序必须判断该值是原始类型,还是引用类型。要实现这一点,解释程序则需尝试判断该值是否为 ECMAScript 的原始类型之一,即 Undefined、Null、Boolean、Number 和 String 型。由于这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 - 栈中。这样存储便于迅速查寻变量的值。
在许多语言中,字符串都被看作引用类型,而非原始类型,因为字符串的长度是可变的。ECMAScript 打破了这一传统
如果一个值是引用类型的,那么它的存储空间将从堆中分配。由于引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响
说来也是形象,栈,线性结构,后进先出,便于管理。堆,一个混沌,杂乱无章,方便存储和开辟内存空间
2、判断数据类型typeof、instanceof、Object.prototype.toString.call()、constructor
3、类数组与数组的区别与转换
4、 数组的常见API
5、bind、call、apply的区别
他们都是是函数的一个方法,作用是改变函数的调用对象,即改变函数运行时this的指向
6、new的原理
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
- 以上参考自 红宝书的第145页
7、如何正确判断this(区别箭头函数)
简单来说,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定)
- 全局作用域或者普通函数中 this 指向全局对象 window。
- 方法调用中谁调用 this 指向谁
- 在构造函数或者构造函数原型对象中 this 指向构造函数的实例
- call谁就是谁,apply谁就是谁,bind谁就指向谁,其实bind就是通过call和apply实现的
- 箭头函数中指向外层作用域的 this
8、严格模式与非严格模式的区别
9、原型和原型链
10、prototype与__proto__的关系与区别
JS中的prototype、__proto__与constructor
11、继承的实现方式及比较
12、作用域和作用域链、执行上下文
看 《红宝书》 第4章 73 页、178 页
JavaScript作用域、上下文、执行期上下文、作用域链、闭包
13、闭包及其作用
什么是闭包:
闭包就是指有权访问另一个函数作用域中的变量的函数,简单来说就是函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包。
闭包特点:
- 函数嵌套函数
- 函数内部可以引用外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
闭包作用:
- 读取函数内部的变量
- 这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除,通常,函数的作用域及其所有变量都会在函数执行结束后被销毁,但是当函数返回到一个闭包时,这个函数的作用域将会一直在内存中存在到闭包不存在为止
闭包优点:
- 避免全局变量的污染;
- 变量长期驻扎在内存中
- 私有成员的存在 ;
闭包缺点:
常驻内存 会增大内存的使用量 使用不当会造成内存泄露
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
- 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值
JavaScript中匿名函数循环传参数(不触发函数的执行)
14、深拷贝与浅拷贝
浅拷贝、深拷贝本身只针对较为复杂的object类型数据。
15、防抖和节流
16、Js事件绑定时,函数名加括号和不加括号区别
17、DOM常见的操作方式
18、 Array.sort()方法与实现机制
19、 Ajax的请求过程
20、JS的垃圾回收机制
看 《红宝书》 第 78 页
21、JS中的String、Array和Math方法
JavaScript中String、Array、Math、Number、Math属性和方法汇总
22、addEventListener(DOM2级事件处理程序)和onClick()(DOM0级事件处理程序)的区别
看 《红宝书》 第 350 页
-
DOM0级事件处理程序:每个元素(包括 window 和 document)都有自己的事件处理程序属性,所以他 是将 事件(比如onclick)当作 dom 节点的一个属性来看待,将这个属性的值设置为一个函数,就可以给相应的 dom 节点指定事件处理程序
-
DOM2级事件处理程序:定义了两个方法 addEventListener() 和 removeEventListener() 所有 dom节点都包含这两个方法。区别于 DOM0 级事件处理程序,他可以为 dom 节点添加多个事件处理程序,相应的程序会按照添加他们的顺序依次触发。通过 addEventListener() 添加的事件处理程序只能使用 removeEventListener() 来移除,移除时传入的参数与添加处理程序时使用的参数相同,因此通过 addEventLisenter() 添加匿名函数将无法移除
Dom0 和 DOM2 事件出来了程序都是在其依附的元素的作用域中运行的,此时 this 指向当前元素,但是IE中使用的 attachEvent() 事件处理程序会在全局作用域中运行,因此 this 指向 window
23、立即执行函数
24、整个HTML解析过程与JS脚本解析和执行顺序
HTML解析过程:
通常来说,浏览器对于Javascript的运行有两大特性:
- 载入后马上执行
- 执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)。
于是,如果有多个js文件被引入,那么对于浏览器来说,这些js文件被被串行地载入,并依次执行。
因为javascript可能会来操作HTML文档的DOM树,所以,浏览器一般都不会像并行下载css文件并行下载js文件,因为这是js文件的特殊性造成的。所以,如果你的javascript想操作后面的DOM元素,基本上来说,浏览器都会报错说对象找不到。因为Javascript执行时,后面的HTML被阻塞住了,DOM树时还没有后面的DOM结点。所以程序也就报错了。基本上来说,head里的
javascript 代码运行分两个阶段:
- 预解析阶段—把所有的函数定义提前,所有的变量声明提前,变量的赋值不提前(预处理会跳过执行语句,只处理声明语句,同样也是按从上到下按顺序进行的。包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。即使声明是在调用的下方进行的,但浏览器仍然先声明再调用(执行),这个现象叫做“提升”。所以,即便一个函数的声明在下方,在前面仍然可以正常执行这个函数。赋值或其他逻辑运算是在执行阶段进行的,在预处理阶段会被忽略。
注意:
(1)函数声明的提升优先于变量声明的提升;
(2)重复的var声明会被忽略掉,但是重复的function声明会覆盖掉前面的声明。
在预处理阶段,声明的变量的初始值是undefined, 采用function声明的函数的初始内容就是函数体的内容。
- 执行阶段—从上到下执行(按照js运行机制)
25、new和Object.create的区别
26、DOM的location对象
27、浏览器从输入URL到页面渲染的整个流程
28、跨域、同源策略及跨域实现方式和原理
前端常见跨域解决方案(全)
跨域的几种常见的解决方式
为什么要有跨域限制
29、浏览器的回流(Reflow)和重绘(Repaints)
浏览器对页面的呈现的处理流程:
-
浏览器把获取到的HTML代码解析成一棵DOM树,HTML中的每个标签(tag)都是DOM树中的一个节点,根节点就是我们常用的document对象。DOM树里包含了HTML所有标签,包括display:none隐藏,还有用JS动态添加的元素等;
-
浏览器把所有样式(用户定义的css和用户代理)解析成样式结构体,在解析过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式,而Firefox会去掉_开头的样式;
-
DOM树和样式结构体组合后构建render tree(渲染树),render tree类似于DOM树,但区别很大,render tree 能识别样式,render tree的每一个节点都有自己的样式,而且render tree中不包含隐藏的节点(比如display:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现。
注意:visibility:hidden隐藏的元素还是会包含到render tree中,因为visibility:hidden会影响布局(layout),会占有空间。根据css2的标准,render tree中的每个节点都称为Box(Box demensions),理解页面元素为一个具有填充,边距,边框和位置的盒子。
结合上面的解释,引起DOM树结构变化,页面布局变化的行为叫回流,且回流一定伴随重绘。
只是样式的变化,不会引起DOM树变化,页面布局变化的行为叫重绘,且重绘不一定会便随回流。回流往往伴随着布局的变化,代价较大,重绘只是样式的变化,结构不会变化
浅析 网页中的回流(reflow)和重绘(repaints)
30、 JavaScript中的arguments
31、EventLoop事件循环(js运行机制)
javascript 代码运行分两个阶段:
- 预解析—把所有的函数定义提前,所有的变量声明提前,变量的赋值不提前
- 执行—从上到下执行(按照js运行机制)
简言之就是JS只有一个主线程,主线程执行完执行栈的任务后去检查异步的任务队列,如果异步事件触发,则将其加到主线程的执行栈。
阮一峰的JavaScript 运行机制详解:再谈Event Loop
32、宏任务与微任务
33、BOM属性对象方法
34、浅谈JS变量提升
var str; //这个属于变量声明
str = "hhh"; //这个属于变量定义
另
var str2="fff";
这样的其实是两个过程,可以看成
var str2;
str2="fff";
而变量声明是会被提升的
35、JS的map()和reduce()方法
36、“ == ”和“===”的区别
37、 函数柯里化及其通用封装
-
柯里化,其实就是高阶函数的一种特殊用法,柯里化是指这样一个函数(假设叫做createCurry),他接收函数A作为参数,运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数。
-
柯里化函数的运行过程其实是一个参数的收集过程,我们将每一次传入的参数收集起来,并在最里层里面处理。在实现createCurry时,可以借助这个思路来进行封装
-
柯里化确实是把简答的问题复杂化了,但是复杂化的同时,我们使用函数拥有了更加多的自由度。而这里对于函数参数的自由处理,正是柯里化的核心所在
-
举一个非常常见的例子。
当我们需要验证电话、邮箱、身份证等等用户信息的时候,按照普通的思路就是写一个一个的验证函数,稍微好一点的,我们就会封装一个更为通用的函数,将用于验证的正则与将要被验证的字符串作为参数传入。但是这样封装之后,在使用时又会稍微麻烦一点,因为会总是输入一串正则,这样就导致了使用时的效率低下
这个时候,我们就可以借助柯里化,在之前封装函数的基础上再做一层封装,以简化使用
然这个案例本身情况还算简单,但是柯里化在面对复杂情况下的灵活性却让我们不得不爱。
38、前端缓存
浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
强缓存
命中 200
存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果
- Expires : Wed, 11 May 2018 07:20:00 GMT, http1.0 绝对时间
- Cache-Control: max-age=315360000 http1.1相对时间 【避免客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确)发生误差】
- no-cache :客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
- no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- private :所有内容只有客户端可以缓存,Cache-Control的默认取值
协商缓存
命中304
存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存,携带该资源的缓存标识发起http请求。
-
Last-Modified表示本地文件最后修改日期,浏览器会在request header加上If-Modified-Since(上次返回的Last-Modified的值),询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回,有以下缺点:
- 如果在本地打开缓存文件,就会造成 Last-Modified 被修改
- 如果在时间粒度内修改 则不会改变
-
HTTP / 1.1 出现了 ETag
- ETag就像一个指纹,资源变化都会导致ETag变化,跟最后修改时间没有关系,ETag可以保证每一个资源是唯一的
- 包含有If-None-Match的header会将上次返回的Etag发送给服务器,询问该资源的Etag是否有更新,有变动就会发送新的资源回来
39、前端安全
XSS
XSS 跨站脚本攻击(Cross Site Scripting)简单点来说,就是攻击者想尽一切办法将可以执行的代码注入到网页中。
类型:
- 持久型:就是攻击的代码被服务端写入进数据库中,这种攻击危害性很大
- 非持久型:一般通过修改 URL 参数的方式加入攻击代码,诱导用户访问链接从而进行攻击。
防御对策:
- 转义字符:对于用户的输入应该是永远不信任的。最普遍的做法就是转义输入输出的内容,对于引号、尖括号、斜杠进行转义
- CSP(Content Security Policy): 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行,在http头部设置
CSRF
跨站请求伪造,原理就是攻击者构造出一个后端请求地址,诱导用户点击或者通过某些途径自动发起请求。如果用户是在登录状态下的话,后端就以为是用户在操作,从而进行相应的逻辑。(银行钓鱼网站)
防御对策:
防范 CSRF 攻击可以遵循以下几种规则:
- get请求不对数据进行修改
- cookie同源,不让第三方网站访问到用户cookie:对 Cookie 设置 SameSite 属性。该属性表示 Cookie 不随着跨域请求发送,可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。
- 阻止第三方网站请求接口:通过判断http请求header中Origin referer判断
- 请求时附带验证信息,比如验证码或者token:服务器下发一个随机 Token,每次发起请求时将 Token 携带上,服务器验证 Token 是否有效
点击劫持
点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击。
防御:
- 推荐:X-FRAME-OPTIONS禁止内嵌(IE8以上) 服务器返回html页面的时候,设置X-Frame-Options: DENY
- 目标网站JS禁止内嵌
- 目标网站前端使用js: top(顶层环境) == window(当前环境)
- 相等则表示目标网站在顶层
- 不等则表示目标网站被iframe内嵌 使用top.location跳转到window.loacation
缺点:攻击者网站禁用目标网站js =>sandbox=”allow-forms”
31、事件捕获事件冒泡
事件捕获和事件冒泡都是为了解决页面中的事件流(事件触发的顺序)
- 事件冒泡:
微软提出了事件冒泡事件流,即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档) - 事件捕获:
网景公司提出了事件捕获事件流,刚好和事件冒泡相反,事件会从最不具体,即最外层的那个元素开始发生,层层递进,直到最具体的那个元素。
32、js对象属性遍历方法
来源:CSDN
作者:鹏鱼雁
链接:https://blog.csdn.net/CEO___/article/details/103840908