读古诗,是为了更好地做一个现代人。

1、js的数据类型有? 基本类型:undefined,null,Number,Boolean,String 引用类型:Object
2、typeof的返回值有? undefined,number,boolean,string, object, function
3、JS中除0会阻止代码的执行吗?不会,因为它返回了NaN。(0/0=NaN)
4、为何for…in循环输出的属性名不可预测?JS对象属性没有顺序 (ES6中规定了顺序) (for…in循环:只遍历对象自身的和继承的可枚举的属性)
5、数组ES5新增的方法:a、map():返回一个新的Array,每个元素为调用func的结果;b、filter():返回一个符合func条件的元素数组 c、forEach():没有返回值,只是针对每个元素调用func (every()是对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true;some()是对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true )
6、逗号操作符:逗号运算符是二元运算符,它的操作数可以是任意类型。它首先计算左操作数,然后计算右操作数,最后返回右操作数的值,用逗号运算符可以在一条语句中执行多个运算。(返回表达式最后一项)
7、错误异常类型:ReferenceError、TypeError、RangeError等。
8、ajax缺点:干掉了History功能。
9、多域名提供资源:突破浏览器并发限制,一般浏览器每个域名不超过6个。
10、为何要用严格模式?避免不确定行为和不安全的操作。
11、取min-max的随机数:Math.random()*(max - min) + min 。
12、如何确定属性是实例属性还是原型属性?同时使用hasOwnProperty()方法和in操作符。
13、使用对象字面量重写原型对象有何问题?其constructor属性指向Object了,需要特意将其显示的设置回特定的值,但会修改其枚举属性,所以最好使用Object.defineProperty()去单独设置。
14、闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见的方式,就是在一个函数内部创建另一个函数。闭包函数对象的作用域链和最近父函数的执行上下文作用域链相同。
15、当调用函数时,会为函数创建一个执行环境(Execution Context),然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。此后,又有一个活动对象(Activation Object)被创建并被推入执行环境作用域链的前端。一般来讲,当函数执行结束之后,就会销毁Execution Context,也就会销毁Execution Context的作用域链,当然也就会销毁Activation Object,内存中仅保存全局作用域。但闭包的情况不同。(Execution Context对象有自己的作用域链,在Execution Context创建时初始化,会将函数创建时的作用域链对象[[scope]]中的全部内容按照在[[scope]]作用域链中的顺序复制到Execution Context的作用域链中)

16、函数生命周期分为函数创建和函数调用阶段(函数调用又可分为建立阶段、执行阶段)。
17、全局对象(Global object)是在进入任何执行上下文之前就已经创建了的对象;这个对象只存在一份,它的属性在程序中任何地方都可以访问,全局对象的生命周期终止于程序退出那一刻。全局对象初始创建阶段将Math、String、Date、parseInt作为自身属性,等属性初始化,同样也可以有额外创建的其它对象作为属性。
18、[]==false //true Number(false)为0 Number([])为0 Number({})为NaN 空数组 [].toString() //“” 空对象 ({}).toString() //[object Object]
19、xss主要涉及到通过执行脚本读取cookie信息,解决就是转义;csrf主要涉及到跨站伪造请求,解决就是请求带有token(并非cookie里的token,而是键值对形式)并校验或验证码。XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。 如果说XSS是一个老虎,那么CSRF就是隐藏在暗处的蛇。‍‍‍‍‍‍(对后台管理系统威胁、cookie伪造)
20、X-DNS-Prefetch-Control头控制着浏览器的DNS预读取功能。 DNS预读取是一项使浏览器主动去执行域名解析的功能,其范围包括文档的所有链接,无论是图片的,CSS的,还是JavaScript等其他用户能够点击的URL。打开和关闭DNS预读取:<meta http-equiv=”x-dns-prefetch-control” content=”off”> 可以通过将content的参数设置为“on”来改变设置。强制查询特定主机名:<link rel=”dns-prefetch” href=”http://www.spreadfirefox.com/"&gt;
21、CORS:浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息(在头信息之中,增加一个Origin字段),有时还会多出一次附加的请求(“预检”请求preflight),但用户不会有感觉。
22、比较运算时,发生toPrimitive操作:1、使用valueOf方法的返回值 2、使用toString方法的返回值 3、如果都不返回基本类型值,报错。(上面说的并不严谨)

1
2
3
4
5
6
7
const a = {
valueOf () {
return 95
}
}

console.log('' + a) // '95'


23、如果跨域的服务器没有设置跨域header,那么任何XMLHttpRequest/Fetch甚至Canvas(可以思考一下我为什么提这个)都不能从对方服务器抓取任何信息(JSONP是用运行JS来跳过这个限制),这是非常基本的Web安全策略。
24、Service Worker可以完成:1、Mock数据请求 2、主动拉取资源文件,并将其缓存 3、当请求数据时候服务器404,自动降级成兜底数据 4、将离线时的打点数据存起来,等到联网后再传输
25、我们都知道要手动安装一个包时,执行npm install 命令即可。但在npm的世界里,除了简单的指定包名, package还可以是一个指向有效包名的http url/git url/文件夹路径。
26、查看项目依赖树的方式:npm ls。npm 5增加了package-lock.json文件,package-lock.json的作用是锁定依赖安装结构。如果查看这个json的结构,会发现与node_modules目录的文件层级结构是一一对应的。
27、依赖包安装完并不意味着就万事大吉了,版本的维护和更新也很重要。npm update总是会把包更新到符合package.json中指定的semver(语义化版本)的最新版本号。最佳实践:1、升级依赖包–升级小版本:本地执行npm update升级到新的小版本、升级大版本:本地执行npm install @升级到新的大版本 本地验证升级后新版本无问题后,提交新的package.json, package-lock.json文件 2、降级依赖包–npm install @验证无问题后,提交package.json和package-lock.json文件 3、删除依赖包–npm uninstall 并提交package.json 和 package-lock.json。任何时候有人提交了package.json, package-lock.json更新后,团队其他成员应在svn update/git pull拉取更新后执行npm install脚本安装更新后的依赖包
28、npm run命令执行时,会把./node_modules/.bin/目录添加到执行环境的PATH变量中,因此如果某个命令行包未全局安装,而只安装在了当前项目的node_modules中,通过npm run一样可以调用该命令。最佳实践:将项目依赖的命令行工具安装到项目依赖文件夹中,然后通过npm scripts调用;而非全局安装。
29、/node_modules/.bin目录,保存了依赖目录中所安装的可供调用的命令行包。何谓命令行包?例如webpack就属于一个命令行包。如果安装webpack时不加–global参数,我们会在node_modules/.bin目录里看到名为webpack的文件,如果在终端直接输入./node_modules/.bin/webpack命令,一样可以执行。这是因为webpack在package.json文件中定义了bin字段为:”bin”: {“webpack”: “./bin/webpack.js”},bin字段的配置格式为: <command>:lgt;file>, 即命令名:可执行文件。npm执行install时,会分析每个依赖包的package.json中的bin字段,并将其包含的条目安装到./node_modules/.bin目录中,文件名为<command>。因此,./node_modules/.bin/webpack文件在通过命令行调用时,实际上就是在执行node ./node_modules/webpack/bin/webpack.js命令。
30、npx的使用很简单,就是执行npx <command>即可,这里的<command>默认就是./node_modules/.bin/目录中安装的可执行脚本名。例如本地安装好的webpack包,我们可以直接使用npx webpack执行即可。
31、除了使用CLI的npm config命令显示更改npm配置,还可以通过项目级.npmrc文件。可以很好地隔离公司的工作项目、在家学习研究项目两种不同的环境。
32、node版本约束:node环境版本不一致带来潜在问题,通过package.json的engines属性声明应用运行所需的版本运行时要求。(engines属性是仅供参考的、使用npm:>=5.2版本)
33、parseInt(string, radix)函数可解析一个字符串,并返回一个整数。radix表示要解析的数字的基数。该值介于2~36之间。如果省略该参数或其值为0,则数字将以10为基础来解析。如果该参数小于2或者大于36,则parseInt()将返回NaN。
34、fun.bind(thisArg[, arg1[, arg2[, …]]])方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值。arg1, arg2, …:当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。(偏函数的使用、柯里化)
35、在node.js中的event模块中,event模块只有一个对象就是EventEmitter,EventEmitter是对事件触发和事件监听功能的封装。EventEmitter实例对象支持的方法列表如下:1、emitter.on(name,f) //对事件name指定监听函数f 2、emitter.once(name,f) //与on方法类似,但是监听函数f是一次性的,使用后自动移除 3、emitter.listeners(name) //返回一个数组,成员是事件name所有监听函数 4、emitter.removeListener(name,f) //移除事件name的监听函数f 5、emitter.removeAllListeners(name) //移除事件name的所有监听函数 6、event.emit(name,args) //触发事件name,第一个参数是定义的事件,后面其他参数回作为参数传递到监听器的回调函数中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
'use strict'
class EmitterEvent {
constructor() {
//构造器。实例上创建一个事件池
this._event = {}
}
//on 订阅
on(eventName, handler) {
// 根据eventName,事件池有对应的事件数组,就push添加,没有就新建一个。
// 严谨一点应该判断handler的类型,是不是function
if (this._event[eventName]) {
this._event[eventName].push(handler)
} else {
this._event[eventName] = [handler]
}
}
emit(eventName) {
// 根据eventName找到对应数组
var events = this._event[eventName];
// 取一下传进来的参数,方便给执行的函数
var otherArgs = Array.prototype.slice.call(arguments, 1)
var that = this
if (events) {
events.forEach((event) => {
event.apply(that, otherArgs)
})
}
}
// 解除订阅
off(eventName, handler) {
var events = this._event[eventName]
if (events) {
this._event[eventName] = events.filter((event) => {
return event !== handler
})
}
}
// 订阅以后,emit 发布执行一次后自动解除订阅
once(eventName, handler) {
var that = this
function func() {
var args = Array.prototype.slice.call(arguments, 0)
handler.apply(that, args)
this.off(eventName, func)
}
this.on(eventName, func)
}
}
var event = new EmitterEvent()
function a(something) {
console.log(something, 'aa-aa')
}
function b(something) {
console.log(something)
}
event.once('dosomething', a)
event.emit('dosomething', 'chifan')
//event.emit('dosomething')
// event.on('dosomething',a)
// event.on('dosomething',b)
// event.emit('dosomething','chifan')
// event.off('dosomething',a)
// setTimeout(() => {
// event.emit('dosomething','hejiu')
// },2000)

36、逻辑运算符里面 优先级高到低 :!> &&> ||。Date.now():返回当前的毫秒数
37、函数节流的目的:从字面上就可以理解,函数节流就是用来节流函数从而一定程度上优化性能的。函数节流的原理:某些代码不可以在没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行过了,这个操作就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的是只有在执行函数的请求停止了一段时间之后才执行。(函数节流的核心是,让一个函数不要执行得太频繁,减少一些过快的调用来节流)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//函数节流的基本模式
var processor = {
timeoutId: null,
//实际进行处理的方法
performProcessing: function(){
//实际执行的代码
},
//初始处理调用的方法
process: function(){
clearTimeout(this.timeoutId);
var that = this;
this.timeoutId = setTimeout(function(){
that.performProcessing();
}, 100);
}
};
//尝试开始执行
processor.process();
// 参照underscore.js
//1、Debounce (fire after pause)
function debounce(fn, delay) {
var timer = null;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
};
}
$('input.search').keypress(debounce(function (event) {
// do the ajax call
}, 250));

//2、Throttle (keep firing with pauses)
function throttle(fn, threshhold, scope) {
threshhold || (threshhold = 250);
var last, deferTimer;
return function () {
var context = scope || this;
var now = +new Date, args = arguments;
if (last && now < last + threshhold) {
// hold on to it
clearTimeout(deferTimer);
deferTimer = setTimeout(function () {
last = now;
fn.apply(context, args);
}, threshhold);
} else {
last = now;
fn.apply(context, args);
}
};
}
$('body').on('mousemove', throttle(function (event) {
console.log('tick');
}, 1000));

38、深拷贝和浅拷贝:1.深拷贝和浅拷贝只针对象Object, Array这样的引用类型数据。2.浅拷贝是对对象引用地址进行拷贝,拷贝后,改其中一个对象的属性,则另一个对象的属性也会改变。3.深拷贝会新开一个引用地址进行拷贝,拷贝后,修改一个对象的属性,不会改变另一个对象的属性。4.浅的只拷贝一层,深的会不断往下找对象,找到对象就浅拷贝一次。4.浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。Object.assign()是浅拷贝。 
//jquery有提供一个$.extend可以用来做Deep Copy。
//函数库lodash,有提供_.cloneDeep用来做Deep Copy。

// JSON.parse(JSON.stringify(obj))看起来很不错,不过MDN文档的描述有句话写的很清楚:undefined、任意的函数以及symbol值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成null(出现在数组中时)
obj1 = { a: 0 , b: { c: 0 } };
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

// 递归 一个非常特殊的场景:循环引用,会陷入一个循环的递归过程,从而导致爆栈。
function deepCopy(obj) {
// 创建一个新对象
let result = {}
let keys = Object.keys(obj),
key = null,
temp = null;

for (let i = 0; i < keys.length; i++) {
key = keys[i];
temp = obj[key];
// 如果字段的值也是一个对象则递归操作
if (temp && typeof temp === 'object') {
result[key] = deepCopy(temp);
} else {
// 否则直接赋值给新对象
result[key] = temp;
}
}
return result;
}

39、在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,public:所有内容都将被缓存(客户端和代理服务器都可缓存)、private:所有内容只有客户端可以缓存,Cache-Control的默认取值。
40、在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。
41、协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:1、协商缓存生效,返回304 2、协商缓存失效,返回200和请求结果结果。
42、定时函数setTimeout和setInterval都可以接受字符串作为它们的第一个参数。 这个字符串总是在全局作用域中执行。
43、bind后函数不会执行,而只是返回一个改变了上下文的函数副本,而call和apply是直接执行函数。
44、二分查找-JS实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function binary-search(arr,key){
var low=0,
high=arr.length-1;
while(low<=high){
mid=Math.floor((low+high)/2);
if(key==arr[mid]){
return mid;
}else if(key<arr[mid]){
high=mid-1;
}else{
low=mid+1;
}
}
return -1;
}

45、Quicksort的Javascript实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var quickSort = function(arr) { // 它的参数是一个数组 
  if (arr.length <= 1) { return arr; } // 检查数组的元素个数,如果小于等于1,就返回

  var pivotIndex = Math.floor(arr.length / 2) ; // 选择中间的元素作为"基准"
  var pivot = arr.splice(pivotIndex, 1)[0]; // 并将其与原数组分离

  var left = []; // 再定义两个空数组,用来存放一左一右的两个子集
  var right = [];

for (var i = 0; i < arr.length; i++){ // 开始遍历数组,小于"基准"的元素放入左边的子集,大于基准的元素放入右边的子集
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }

return quickSort(left).concat([pivot], quickSort(right)); // 使用递归不断重复这个过程,就可以得到排序后的数组
};

46、splice()方法向/从数组中添加/删除项目,然后返回包含被删除项目的新数组,如果有的话。该方法会改变原始数组。
47、最常用的路由分为Hash路由及History路由。
48、HTTP协议中采用keep-alive模式,keep-alive模式下,如果内容定长,可以通过Content-Length的长度来确定数据是否接受完毕。
49、Content-Encoding是一个实体消息首部,用于对特定媒体类型的数据进行压缩。当这个首部出现的时候,它的值表示消息主体进行了何种方式的内容编码转换。这个消息首部用来告知客户端应该怎样解码才能获取在Content-Type中标示的媒体类型内容。一般建议对数据尽可能地进行压缩,因此才有了这个消息首部的出现。Content-Encoding的值有gzip、compress、deflate、deflate、br。
50、Transfer-Encoding消息首部指明了将entity安全传递给用户所采用的编码形式。chunked值表示数据以一系列分块的形式进行发送。Content-Length首部在这种情况下不被发送。在每一个分块的开头需要添加当前分块的长度,以十六进制的形式表示,后面紧跟着’\r\n’,之后是分块本身,后面也是’\r\n’。终止块是一个常规的分块,不同之处在于其长度为0。
51、JSONP的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var getJSONP = function(url, callback) {
//创建一个唯一函数名称。
var cbname = 'jsonp' + (new Date()).getTime();
var i = 0;
//替换
url = url.replace(/\?/g, function(old) {
if(++i === 2) {
return cbname;
} else {
return old;
}
});
//创建回调函数。
window[cbname] = function(response){
try{
callback(response); //处理响应
} finally {
//删除该函数, 并移除相应script元素
delete window[cbname];
script.parentNode.removeChild(script);
}
}
//创建script标签并添加到DOM中去
var script = document.createElement("script");
script.src = url;
document.body.appendChild(script);
}
//获取数据
getJSONP('https://api.douban.com/v2/book/1220562?callback=?', function(data) {
console.log(data);
//do something;
});

52、em和strong的区别–首先看HTML4.01中的说明:EM: Indicates emphasis。STRONG: Indicates stronger emphasis。em 表示强调,strong表示更强烈的强调。言简意赅,表明了em和strong的命名来历。并且在浏览器中,em默认用斜体表示,strong用粗体表示。
53、HTTP/2:

54、渐进增强和优雅降级–在传统软件开发中,经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容。
渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。
55、给定一个a值和一个b值,如何在不使用任何辅助空间的情况下,交换a和b的值? var a=1;var b=2; a=a+b;b=a-b;a=a-b;console.log(a,b);
56、Event对象相关属性与方法:currentTarget返回其事件监听器触发该事件的元素;target返回触发此事件的元素;preventDefault()通知浏览器不要执行与事件关联的默认动作;stopPropagation()不再派发事件。
57、Fetch API:1、当接收到一个代表错误的HTTP状态码时,从fetch()返回的Promise不会被标记为reject,即使该HTTP响应的状态码是404或500。相反,它会将Promise状态标记为resolve(但是会将resolve的返回值的ok属性设置为false),仅当网络故障时或请求被阻止时,才会标记为reject。 2、默认情况下,fetch不会从服务端发送或接收任何cookies, 如果站点依赖于用户session,则会导致未经认证的请求(要发送cookies,必须设置credentials选项)
58、斐波那契数列相关:斐波那契数列:1、1、2、3、5、8、13、21、34……;使用公式f[n]=f[n-1]+f[n-2],依次递归计算,递归结束条件是f[1]=1,f[2]=1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//求第n个项的值
function fn(n){
if(n==1|n==2){
return 1;
}
return fn(n-1)+fn(n-2); //不断调用自身函数,n-1是传进去的参数的前一次,就是最后n的前一个数字。所以n-2是最后传入参数的前两个数字。
}

// 求前n个数列
function fibona(end){ //end是多少数内的斐波那契数列
var num1 = 0,num2 = 1,num3;
var arr = [];
for(var i = 3;i<=end;i++){
num3 = num1 + num2;
num1 = num2;
num2 = num3;

if(num3>=end){
break;
}

arr.push(num3);
}
return arr;
}
console.log(fibona(20)); //[1, 2, 3, 5, 8, 13]

59、循环引用导致内存泄漏问题以及规避。浏览器的垃圾回收机制:引用计数、标记清除(mark-and-sweep)。(引用计数不太常用,标记清除较为常用;没有清理的DOM元素引用)
60、input输入框的onchange事件,要在input失去焦点的时候才会触发;onchange属性可以使用于:<input>、<select>、<textarea> input事件在用户输入时触发,它是在元素值发生变化时立即触发,不需要等到元素失去焦点,是实时的。它是HTML5的事件。
61、实现vue中的on、emit、off、once。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 参照 vue 源码实现
var EventEmiter = function (){
this._events = {};
};
EventEmiter.prototype.on = function (event, cb){
if (Array.isArray(event)){
for (let i = 0, l = event.length; i < l; i++){
this.on(event[i], cb);
}
} else {
(this._events[event] || (this._events[event] = [])).push(cb);
}
return this;
};
EventEmiter.prototype.once = function (event, cb){
function on () {
this.off(event, cb);
cb.apply(this, arguments);
}
on.fn = cb;
this.on(event, on);
return this;
};
EventEmiter.prototype.off = function (event, cb){
if (!arguments.length){
this._events = Object.create(null);
return this;
}
if (Array.isArray(event)){
for (let i = 0, l = event.length; i < l; i++){
this.off(event[i],cb);
}
return this;
}
if (!cb){
this._events[event] = null;
return this;
}
if (cb){
let cbs = this._events[event];
let i = cbs.length;
while(i--){
if (cb === cbs[i] || cb === cbs[i].fn){
cbs.splice(i, 1);
break;
}
}
return this;
}
};
EventEmiter.prototype.emit = function (event){
let cbs = this._events[event];
let args = Array.prototype.slice.call(arguments, 1);
if (cbs){
for (let i = 0, l = cbs.length; i < l; i++){
cbs[i].apply(this,args);
}
}
};

62、在浏览器的多个tab页中共享sessionStorage:1、在浏览器中的多个tab页中共享数据,可以通过cookie或localStorage实现 2、某些情况下,需要在浏览器关闭后即清除该数据,可以通过sessionStorage完成 3、但sessionStorage仅保存在当前tab页中,想要在多个tab中共享该数据,可通过localStorage实现。 ( Storage发生变化(增加、更新、删除)时的触发,同一个页面发生的改变不会触发,只会监听同一域名下其他页面改变Storage。event对象的属性:oldValue:更新前的值。如果该键为新增加,则这个属性为null;newValue:更新后的值。如果该键被删除,则这个属性为null;url:原始触发storage事件的那个网页的网址)
63、在使用css3动画中,会有需要监听动画是否已经结束并对事件进行处理,最好的方法就是使用animationend。我们通过JavaScript来监听动画的开始、进行和结束,这样子方便我们随时控制运动中的元素。CSS动画播放时,会发生以下三个事件:a、animationstart–CSS 动画开始后触发 b、animationiteration–CSS动画重复播放时触发 c、animationend–CSS动画完成后触发。关于过渡transition的事件只有一个,是transitionend事件,它发生在过渡事件完成后。(事件对象包含的属性)
64、某些特殊的渲染层会被认为是合成层(Compositing Layers),合成层拥有单独的GraphicsLayer,而其他不是合成层的渲染层,则和其第一个拥有GraphicsLayer父层公用一个。(1、每个GraphicsLayer都有一个GraphicsContext,GraphicsContext会负责输出该层的位图,位图是存储在共享内存中,作为纹理上传到GPU中,最后由GPU将多个位图进行合成,然后draw到屏幕上。 2、在某些特定条件下,浏览器会主动将渲染层提至合成层,那么影响composite的因素有哪些? 3、提升合成层的最好方式是使用CSS的will-change属性。而will-change设置为opacity、transform、top、left、bottom、right可以将元素提升为合成层 )
65、var a = b = 3;的简写其实是:b = 3;var a = b;
66、写一个sum方法,当使用下面的语法调用时它将正常工作:console.log(sum(2,3))、console.log(sum(2)(3))

1
2
3
4
5
6
7
function sum(x) {
if (arguments.length == 2) {
return arguments[0] + arguments[1];
} else {
return function(y) { return x + y; };
}
}

67、如果数组列表太大,以下递归代码将导致堆栈溢出。你如何解决这个问题,仍然保留递归模式?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
// process the list item...
nextListItem();
}
};

// 通过修改nextListItem函数可以避免潜在的堆栈溢出,堆栈溢出被消除,因为事件循环处理递归,而不是调用堆栈。
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
// process the list item...
setTimeout( nextListItem, 0);
}
};

68、如何在数组的开头添加元素?最后如何添加一个? 使用ES6,可以使用扩展运算符:myArray = [‘start’, …myArray]、myArray = […myArray, ‘end’]、myArray = [‘start’, …myArray, ‘end’]。
69、setInterval的时间17ms,希望1s内有60帧。
70、对于Cookie,处于安全性考虑,它有一个作用域问题,这个作用域由属性Domain和Path共同决定的。也就是说,如果浏览器发送的请求不在此Cookie的作用域范围内,请求是不会带上此Cookie的。

Comments

去留言
2017-08-18

⬆︎TOP