原型
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象。
每个函数都有prototype ( 原型) 属性,这个属性是一个指针,指向一个对象,
这个对象的用途是包含特定类型的所有实例共享的属性和方法,即这个原型对象是用来给实例共享属性和方法的。
而每个实例内部都有一个指向原型对象的指针。
闭包
简单来说就是函数嵌套函数,内部函数引用来外部函数的变量,从而导致来垃圾回收机制没有生效,变量被保存来下来。
也就是所谓的内存泄漏,然后由于内存泄漏又会导致你项目逐渐变得卡顿等等问题。因此要避免内存泄漏。
垃圾回收机制(闭包的延伸)
js拥有特殊的垃圾回收机制,当一个变量在内存中失去引用,js会通过特殊的算法将其回收,并释放内存。
分为以下两个阶段:
标记阶段:垃圾回收器,从根对象开始遍历,访问到的每一个对象都会被标示为可到达对象。
清除阶段:垃圾回收器在对内存当中进行线性遍历,如果发现该对象没有被标记为可到达对象,那么就会被垃圾回收机制回收。
这里面牵扯到了引用计数法,每次引用都被会‘➕1 ’ 如果标记清零,那么就会被回收掉。
原型链
提到原型链就不得不提原型的继承,继承的完美实现方案是借助寄生组合继承,主要实现原理
PersonB . prototype = Object . create ( PersonA . prototype) 实现来继承PersonA 的原型
当我们通过new关键字实例化的对象身上就有了PersonB 自身的属性和方法,也有了PersonA 的原型方法
当实例化对象调用某个方法时会先在自身和原型上查找,然后是在_proto_上一层层查找,这种方式就是原型链。
vuex
Vuex 是一个专为 Vue . js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态
并以相应的规则保证状态以一种可预测的方式发生变化。
tate:Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。
mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
action: action 提交的是 mutation,而不是直接变更状态。action 可以包含任意异步操作。
getter: 相当于Vue 中的computed计算属性
vue-router
Vue Router 是 Vue . js 官方的路由管理器。它和 Vue . js 的核心深度集成,让构建单页面应用变得易如反掌
< router- link> 和< router- view> 和< keep- alive>
深拷贝浅拷贝
深拷贝:
通过利用JSON . parse ( JSON . stringify ( Object ) ) 来达到深拷贝的目的
但是JSON 深拷贝的缺点是undefined和function还有symbol类型是无法进行深拷贝的
如有需要可以自己手动封装函数来达到目的
浅拷贝:
通过ES6 新特性Object . assign ( ) 与扩展运算符来达到浅拷贝的目的
手写深拷贝
function deepClone ( source) {
const targetObj = source. constructor == = Array ? [ ] : { }
for ( let keys in source) {
if ( source. hasOwnProperty ( keys) ) {
if ( source[ keys] && typeof source[ keys] == = 'object ') {
targetObj[ keys] = source[ keys] . constructor == = Array ? [ ] : { }
targetObj[ keys] = deepClone ( source[ keys] )
} else {
targetObj[ keys] = source[ keys]
}
}
}
return targetObj
}
Vue通信
第一种:props和$emit
第二种:中央事件总线 EventBus ( 基本不用)
第三种:vuex(状态管理器)
第四种:$parent 和 $children
当然还有其他办法,但是基本不常用
webpack配置入口出口
module. exports= {
entry: { } ,
output: { } ,
module: { } ,
plugins: [ ] ,
devServer: { }
}
简单描述了一下这几个属性是干什么的。
陈述输入URL回车后的过程
1 . 读取缓存:
搜索自身的 DNS 缓存。( 如果 DNS 缓存中找到IP 地址就跳过了接下来查找 IP 地址步骤,直接访问该 IP 地址。)
2 . DNS 解析: 将域名解析成 IP 地址
3 . TCP 连接:TCP 三次握手,简易描述三次握手
客户端:服务端你在么?
服务端:客户端我在,你要连接我么?
客户端:是的服务端,我要链接。
连接打通,可以开始请求来
4 . 发送 HTTP 请求
5 . 服务器处理请求并返回 HTTP 报文
6 . 浏览器解析渲染页面
7 . 断开连接:TCP 四次挥手
关于第六步浏览器解析渲染页面又可以聊聊如果返回的是html页面
根据 HTML 解析出 DOM 树
根据 CSS 解析生成 CSS 规则树
结合 DOM 树和 CSS 规则树,生成渲染树
根据渲染树计算每一个节点的信息
根据计算好的信息绘制页面
陈述http
基本概念:
HTTP ,全称为 HyperText Transfer Protocol ,即为超文本传输协议。是互联网应用最为广泛的一种网络协议
所有的 www 文件都必须遵守这个标准。
http特性:
HTTP 是无连接无状态的
HTTP 一般构建于 TCP / IP 协议之上,默认端口号是 80
HTTP 可以分为两个部分,即请求和响应。
http请求:
HTTP 定义了在与服务器交互的不同方式,最常用的方法有 4 种
分别是 GET ,POST ,PUT , DELETE 。URL 全称为资源描述符,可以这么认为:一个 URL 地址
对应着一个网络上的资源,而 HTTP 中的 GET ,POST ,PUT ,DELETE
就对应着对这个资源的查询,修改,增添,删除4 个操作。
HTTP 请求由 3 个部分构成,分别是:状态行,请求头( Request Header ) ,请求正文。
HTTP 响应由 3 个部分构成,分别是:状态行,响应头( Response Header ) ,响应正文。
HTTP 响应中包含一个状态码,用来表示服务器对客户端响应的结果。
状态码一般由3 位构成:
1xx : 表示请求已经接受了,继续处理。
2xx : 表示请求已经处理掉了。
3xx : 重定向。
4xx : 一般表示客户端有错误,请求无法实现。
5xx : 一般为服务器端的错误。
比如常见的状态码:
200 OK 客户端请求成功。
301 Moved Permanently 请求永久重定向。
302 Moved Temporarily 请求临时重定向。
304 Not Modified 文件未修改,可以直接使用缓存的文件。
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized 请求未经授权,无法访问。
403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因。
404 Not Found 请求的资源不存在,比如输入了错误的URL 。
500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。
大概还有一些关于hhtp请求和响应头信息的介绍。
说说Vue原理
Vue 是采用数据劫持配合发布者- 订阅者模式,通过Object . defineProperty来( ) 来劫持各个属性的getter和setter
在数据发生变化的时候,发布消息给依赖收集器,去通知观察者,做出对应的回调函数去更新视图。
具体就是:
MVVM 作为绑定的入口,整合Observe , Compil 和Watcher 三者,通过Observe 来监听model的变化
通过Compil 来解析编译模版指令,最终利用Watcher 搭起Observe 和Compil 之前的通信桥梁
从而达到数据变化 => 更新视图,视图交互变化( input) => 数据model变更的双向绑定效果。
Vue路由守卫有哪些,怎么设置,使用场景等
常用的两个路由守卫:router. beforeEach 和 router. afterEach
每个守卫方法接收三个参数:
to: Route : 即将要进入的目标 路由对象
from: Route : 当前导航正要离开的路由
next: Function : 一定要调用该方法来 resolve 这个钩子。
在项目中,一般在beforeEach这个钩子函数中进行路由跳转的一些信息判断。
判断是否登录,是否拿到对应的路由权限等等。
数组去重
第一种:通过ES6 新特性Set ( )
例如:var arr = [ 1 , 2 , 3 , 1 , 2 ] ; var newArr= [ ... new Set ( arr) ]
第二种:封装函数利用 { } 和【】
function uniqueEasy ( arr) {
if ( ! arr instanceof Array ) {
throw Error ( '当前传入的不是数组')
}
let list = [ ]
let obj = { }
arr. forEach ( item => {
if ( ! obj[ item] ) {
list. push ( item)
obj[ item] = true
}
} )
return list
}
Set,Map解构
ES6 提供了新的数据结构 Set 。
它类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成 Set 数据结构。
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
对数组排序
第一种方法利用sort方法
第二种利用冒泡排序
说一说js是什么语言
js是一种运行在浏览器的脚本语言,这种语言主要的功能是可以制作出动态的页面的效果
我们可以通过js+ css+ html布局来形成我们现在可以访问展示的页面
js语言是弱语言类型, 因此我们在项目开发中当我们随意更改某个变量的数据类型后
有可能会导致其他引用这个变量的方法中报错等等。
原型
JavaScript 中的对象都有一个特殊的 prototype 内置属性,其实就是对其他对象的引用
几乎所有的对象在创建时 prototype 属性都会被赋予一个非空的值,我们可以把这个属性当作一个备用的仓库
当试图引用对象的属性时会触发get操作,第一步时检查对象本身是否有这个属性,如果有就使用它,没有就去原型中查找。一层层向上直到Object . prototype顶层
基于原型扩展描述一下原型链,什么是原型链,原型的继承,ES5 和ES6 继承与不同点。
ES6新特性
1 . ES6 引入来严格模式
变量必须声明后在使用
函数的参数不能有同名属性, 否则报错
不能使用with语句 ( 说实话我基本没用过)
不能对只读属性赋值, 否则报错
不能使用前缀0 表示八进制数, 否则报错 ( 说实话我基本没用过)
不能删除不可删除的数据, 否则报错
不能删除变量delete prop, 会报错, 只能删除属性delete global[ prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments. caller ( 说实话我基本没用过)
不能使用arguments. callee ( 说实话我基本没用过)
禁止this指向全局对象
不能使用fn . caller和fn . arguments获取函数调用的堆栈 ( 说实话我基本没用过)
增加了保留字(比如protected、static 和interface)
2 . 关于let 和const 新增的变量声明
3 . 变量的解构赋值
4 . 字符串的扩展
includes ( ) :返回布尔值,表示是否找到了参数字符串。
startsWith ( ) :返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith ( ) :返回布尔值,表示参数字符串是否在原字符串的尾部。
5 . 数值的扩展
Number . isFinite ( ) 用来检查一个数值是否为有限的(finite)。
Number . isNaN ( ) 用来检查一个值是否为NaN 。
6 . 函数的扩展
函数参数指定默认值
7 . 数组的扩展
扩展运算符
8 . 对象的扩展
对象的解构
9 . 新增symbol数据类型
10 . Set 和 Map 数据结构
ES6 提供了新的数据结构 Set 。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成 Set 数据结构。
Map 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
11 . Proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问
都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
Vue3 . 0 使用了proxy
12 . Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
特点是:
对象的状态不受外界影响。
一旦状态改变,就不会再变,任何时候都可以得到这个结果。
13 . async 函数
async 函数对 Generator 函数的区别:
(1 )内置执行器。
Generator 函数的执行必须靠执行器,而async 函数自带执行器。也就是说,async 函数的执行,与普通函数一模一样,只要一行。
(2 )更好的语义。
async 和await ,比起星号和yield ,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。
(3 )正常情况下,await 命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。
(4 )返回值是 Promise 。
async 函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。
14 . Class
class跟let 、const 一样:不存在变量提升、不能重复声明...
ES6 的class可以看作只是一个语法糖,它的绝大部分功能
ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
15 . Module
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict" ; 。
import和export命令以及export和export default的区别
Css3新特性
1 . 过渡 transition
2 . 动画 animation
3 . 形状转换 transform
4 . 阴影 box - shadow
5 . 滤镜 Filter
6 . 颜色 rgba
7 . 栅格布局 gird
8 . 弹性布局 flex
等等还多...
说一说什么是跨域,怎么解决
因为浏览器出于安全考虑,有同源策略。也就是说,如果协议、域名或者端口有一个不同就是跨域,Ajax 请求会失败。
为来防止CSRF 攻击
1 . JSONP
JSONP 的原理很简单,就是利用 < script> 标签没有跨域限制的漏洞。
通过 < script> 标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。
< script src= "http://domain/api?param1=a¶m2=b&callback=jsonp" > < / script>
< script>
function jsonp ( data) {
console. log ( data)
}
< / script>
JSONP 使用简单且兼容性不错,但是只限于 get 请求。
2 . CORS
CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。
3 . document. domain
该方式只能用于二级域名相同的情况下,比如 a. test. com 和 b. test. com 适用于该方式。
只需要给页面添加 document. domain = 'test . com' 表示二级域名都相同就可以实现跨域
4 . webpack配置proxyTable设置开发环境跨域
首先需要明白webpack proxy跨域只能用作与开发阶段,临时解决本 地请 求服务器产生的跨域问题。
并不适合线上环境。配置在webpack的devServer属性中。
webpack中的devsever配置后,打包阶段在本地临时生成了一个node服务器,浏览器请求服务器相当于请求本地服务。
5 . nginx代理跨域
6 . iframe跨域
7 . postMessage
这种方式通常用于获取嵌入页面中的第三方页面数据。一个页面发送消息,另一个页面判断来源并接收消息
说一说SessionStorage和localStorage还有cookie
共同点:都是保存在浏览器端、且同源的
不同点:
1 . cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下
sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
2 . 存储大小限制也不同,cookie数据不能超过4K,sessionStorage和localStorage可以达到5M
3 . sessionStorage:仅在当前浏览器窗口关闭之前有效;
localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;
cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
4 . 作用域不同
sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面;
localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在
cookie: 也是在所有同源窗口中都是共享的. 也就是说只要浏览器不关闭,数据仍然存在
说一说前端性能优化方案
三个方面来说明前端性能优化
一:webapck优化与开启gzip压缩
1 . babel- loader用 include 或 exclude 来帮我们避免不必要的转译,不转译node_moudules中的js文件
其次在缓存当前转译的js文件,设置loader: 'babel - loader? cacheDirectory= true '
2 . 文件采用按需加载等等
3 . 具体的做法非常简单,只需要你在你的 request headers 中加上这么一句:
accept- encoding: gzip
4 . 图片优化,采用svg图片或者字体图标
5 . 浏览器缓存机制,它又分为强缓存和协商缓存
二:本地存储——从 Cookie 到 Web Storage 、IndexedDB
说明一下SessionStorage 和localStorage还有cookie的区别和优缺点
三:代码优化
1 . 事件代理
2 . 事件的节流和防抖
3 . 页面的回流和重绘
4 . EventLoop 事件循环机制
5 . 代码优化等等
Promise是什么,解决了什么,之前怎么实现的
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
解决来之前在请求中回调请求产生的回调地狱,使得现在的代码更加合理更加优雅,也更加容易定位查找问题。
浏览器缓存
缓存可以减少网络 IO 消耗,提高访问速度。浏览器缓存是一种操作简单、效果显著的前端性能优化手段
很多时候,大家倾向于将浏览器缓存简单地理解为“HTTP 缓存”。
但事实上,浏览器缓存机制有四个方面,它们按照获取资源时请求的优先级依次排列如下:
Memory Cache
Service Worker Cache
HTTP Cache
Push Cache
缓存它又分为强缓存和协商缓存。优先级较高的是强缓存,在命中强缓存失败的情况下,才会走协商缓存
实现强缓存,过去我们一直用 expires。
当服务器返回响应时,在 Response Headers 中将过期时间写入 expires 字段,现在一般使用Cache - Control 两者同时出现使用Cache - Control
协商缓存,Last - Modified 是一个时间戳,如果我们启用了协商缓存,它会在首次请求时随着 Response Headers 返回:每次请求去判断这个时间戳是否发生变化。
从而去决定你是304 读取缓存还是给你返回最新的数据
css的重绘与回流
重绘:当节点需要更改外观而不会影响布局。
回流:DOM 结构的修改引发DOM 几何尺寸变化的时候,发生回流。
常见的几何属性有width、height、padding、margin、left、top、border 或者是DOM 节点发生增减移动。
减少重绘和回流的办法。
使用css3新增属性:translate替代top等方向值。
避免频繁使用style,而是采用class。
箭头函数和普通函数的区别是什么
普通函数this:
this总是代表它的直接调用者。
在默认情况下,没找到直接调用者,this指的是window。
在严格模式下,没有直接调用者的函数中的this是undefined。
使用call, apply, bind绑定,this指的是绑定的对象。
箭头函数this:
在使用=> 定义函数的时候,this的指向是 定义时所在的对象,而不是使用时所在的对象;
不能够用作构造函数,这就是说,不能够使用new命令,否则就会抛出一个错误;
不能够使用 arguments 对象;
不能使用 yield 命令;
讲一下let、var、const的区别
var 没有块级作用域,支持变量提升。
let 有块级作用域,不支持变量提升。不允许重复声明,暂存性死区。不能通过window. 变量名进行访问.
const 有块级作用域,不支持变量提升,不允许重复声明,暂存性死区。声明一个变量一旦声明就不能改变,改变报错。
继承
原理是:复制父类的属性和方法来重写子类的原型对象
原型继承
构造函数继承
组合继承
寄生继承
寄生组合继承
class
等等
function Father ( ... arr) {
this. some = '父类属性';
this. params = arr;
}
Father . prototype. someFn = function ( ) {
console. log ( 1 ) ;
}
Father . prototype. someValue = '2' ;
function Son ( ) {
Father . call ( this, 'xxxx ') ;
this. text = '2222 ';
}
Son . protptype = Object . create ( Father . prototype) ;
Son . prototype. constructor = Son ;
Object,create做了什么
Object . _create = function ( obj) {
function F ( ) { } ;
F . prototype = obj;
return new F ( ) ;
}
函数的防抖
防抖函数:将多次触发变成最后一次触发;
function debounce ( fn , wait) {
let timer = null;
return function ( ) {
let arg = arguments;
if ( timer) {
clearTimeout ( timer) ;
timer = null;
}
timer = setTimeout ( ( ) => {
fn . apply ( this, arg)
} , wait)
}
}
function clg ( ) {
console. log ( 'clg ')
}
window. addEventListener ( 'resize ', debounce ( clg, 1000 ) )
函数的节流
节流函数:将多次执行变成每隔一个时间节点去执行的函数
function throttle ( fn , time) {
let lastTime = null;
return function ( ) {
let nowTime = Date . now ( ) ;
if ( nowTime - lastTime > time || ! lastTime) {
fn ( ) ;
last = nowTime
}
}
}
function sayHi ( ) {
console. log ( 'hi ')
}
setInterval ( throttle ( sayHi, 1000 ) , 500 )
call、apply区别
相同点:都是重定向this指针的方法。
不同点:call和apply的第二个参数不相同,call是若干个参数的列表。apply是一个数组
手写call方法
let mock = { value : 1 } ;
function mockNum ( ) {
console. log ( 'value ', this. value)
}
mockNum. call ( mock)
转换一下实现方法就是
let mock = {
value: 1 ;
mockNum: function ( ) {
console. log ( 'value ', this. value)
}
}
mock. mockNum ( ) ;
所以经过上面这个操作的演化而来的结果就是如下步骤:
1 . 将函数设为一个对象的属性
2 . 并将这个函数的属性调用
3 . 删除该函数
Function . prototype. Mycall = function ( context) {
let obj = context || window;
obj. fn = this;
let args = [ ... arguments] . slice ( 1 ) ;
let result = obj. fn ( ... args) ;
delete obj. fn ;
return result;
}
let mock = { value : 1 } ;
function mockNum ( ) {
console. log ( 'value ', this. value) ;
}
mockNum. Mycall ( mock)
手写apply方法
Function . prototype. Myapply = function ( context) {
let obj = context || window;
obj. fn = this;
let result = arguments[ 1 ] ? obj. fn ( arguments[ 1 ] ) : obj. fn ( [ ] ) ;
delete obj. fn ;
return result;
}
let mock3 = {
arr: [ 1 , 2 , 3 , 4 , 5 ] ,
} ;
function arrx2 ( arr) {
return this. arr. concat ( arr) . map ( ( x) => x * 2 ) ;
}
console. log ( "arrx2" , arrx2. myApply ( mock3) ) ;
手写bind方法
bind方法是直接返回一个新的函数,需要手动去调用才能执行。
创建一个新函数,当这个新函数被调用时,bind ( ) 方法的第一个参数将作为运行他的this,之后的一系列参数将会在传递的实参传入作为他的参数;
特点:1 . 返回一个函数。 2 . 可以传入参数;
手写一个bind方法
例如:
let foo = { value : 1 } ;
function bar ( ) {
console. log ( 'bindFoo ', this. value) ;
}
let bindFoo = bar. bind ( foo) ;
bindFoo ( )
Function . prototype. Mybind = function ( obj) {
if ( typeof this != = 'function ') throw new Error ( 'not a function') ;
let self = this;
let args = [ ... arguments] . clice ( 1 ) ;
return function F ( ) {
if ( this instanceof F ) {
return new self ( ... args, ... arguments) ;
}
return self . apply ( obj, args. concat ( [ ... arguments] ) ) ;
}
}
关于函数的调用
作为一个正常的函数调用
函数作为方法调用
使用构造函数调用函数
作为函数方法调用函数
捕获和冒泡
捕获:就是从根元素开始向目标元素递进的一个关系;从上而下
冒泡:是从目标元素开始向根元素冒泡的过程;想象一下水里的泡泡从下而上。
⚠️stopPropagation 通常理解它是用来阻止事件冒泡的,其实该函数也可以阻止捕获事件。
instanceof原理
instanceOf用来判断右边的prototype是否在左边的原型链上,告诉我们左边是否是右边的实例。
function instanceof ( left, right) {
let prototype = right. prototype
left = left. __proto__
while ( true ) {
if ( left == = null) {
return false
}
if ( prototype == = left) {
return true
}
left = left. __proto__
}
}
typeof
typeof 检测对象,除开函数是function类型之外。像常见的数组,对象或者是正则, 日期等等都是object;
需要注意一下:
typeof Symbol ( )
typeof null
typeof undefined
typeof null检测输出object因为js最初版本,使用的是32 位系统,类型的标签存储在每个单元的低位中000 是object类型。null全是0 ,所以当我们使用typeof 进行检测的时候js错误的判断位object
深度优先和广度优先
广度优先:尝试访问尽可能靠近它的目标节点,然后逐层向下遍历,直至最远的节点层级。
深度优先:从起始节点开始,一直向下找到最后一个节点,然后返回,又继续下一条路径。知道找遍所有的节点。
浏览器禁用cookie该如何处理
一般会用到url重写的技术来进行会话跟踪,每一次的交互,都会在url后面加上sid= xxx类似的参数。服务端根据这种方式来识别用户。
setTimeout与setInterval的区别
setTimeout表示间隔一段时间之后执行一次调用,而setInterval是每隔一段时间循环调用,直至清除。
内存方面,setTimeout只需要进入一次宏队列,setInterval不计算代码执行时间,有可能多次执行多次代码
实现一个new的伪代码
创建一个对象
连接原型
绑定this
返回该对象
function _new ( ) {
let obj = new Object ( ) ;
let Con = [ ] . shift. call ( arguments) ;
obj. __proto__ = Con . prototype;
let result = Con . apply ( obj, arguments) ;
return typeof result == = 'object ' ? result : obj
}