Open FrankKai opened 5 years ago
1 year before: cookies,需要与后端协作,一种认证方式,expires失效时间 sessionStorage,当前会话有效 localStorage,本地缓存,expires失效时间
today:
注意:这在vue单页应用的foo.vue和新tabbar.vue之间进行通信,使用vuex,vue-router,event-bus或者eventEmitter都是不适用的。因为在新的tab,根vue实例是完全两个新的实例,emitter也是完全两个新的emitter,无法通信。但是监听window的storage事件可以做到这种复杂情况的通信。
如何清空?
localStorage.clear();
sessionStorage.clear();
<script>
、<script async>
和<script defer>
区别1 year before: 常见的同步;异步;延迟加载。
today:
<script async>
控制浏览器同异步加载脚本。若设置async为false,那么浏览器在HTML解析期间同步加载脚本。一般来说通过代码document.creatElement()
插入脚本是异步的,设置async为false可以将其控制为同步。<script defer>
defer属性用来控制script是否在HTML完成解析之后再执行,但是会在DOMContentLoad
燃烧之前完成。拓展:
1.什么是DOMContentLoaded
事件?
DOMContentLoaded事件,会在初始化HTML document完成加载和解析触发,无需等待stylesheets,images,以及字frame结束加载。Load
事件和DOMContentLoaded
事件很类似,经常有人混淆2个事件。
2.什么是Load
事件?
load事件,会在完成一次完全加载之后再触发。
3.如何解决同步js阻塞DOM渲染的问题,最快速度渲染DOM?
异步化js,优化stylesheets加载。
4.如何检查document是否完成加载?
document.readyState
。
所以一次加载文档资源的状态有3个,loading``interactive
和complete
。
<head></head>
之间,而将js<script></script>
放置在</body>
之前?1 year before: 防止阻塞浏览器渲染,先执行CSSOM,再绘制DOM,再操作DOM。主线程单线程渲染UI。 today 从技术实现的角度讲,先加载stylesheets并且绘制,DOM渲染结束后再加载并执行可能涉及DOM操作的js文件,避免js的执行导致渲染阻塞。 从用户体验的角度讲,优先加载样式表减少用户面对空白网页的时间,提升用户体验。
1 year before ①ID优先级高 ②ID唯一标识,不能重复 today ①语法不同,#idname, .classname ②影响元素不同,#idname作用单个元素,.classname作用所有元素 ③选择器权重不同,#idname权值高于.classname
1 year before
today [译]如何隐藏DOM元素?
*{ box-sizing: border-box }
的作用,并且说明使用它有什么好处?1 year before 怪异盒模型。 计算方便,width包含了border,响应式百分比布局。 today box-sizing的值有2种,一个是content-box,一个是border-box,content-box仅仅包含content。 border-box的width会将content, padding和border包含在内,例如width:100%指的是包含了content,padding和border的宽度,布局时更好控制。
例如子元素继承了父元素的width:100%,此时设置了子元素padding,border,若子元素的box-sizing是content-box,会导致溢出,而border-box的话,width:100%会很舒服地包含了padding和border。
因为这样的应用场景很多,所以索性就为所有标签都设置成border-box,有特殊情况的再手动设置成content-box。
有一篇墙推IE怪异盒模型的文章:把所有元素的box-sizing都设置成border-box吧!
1 year before
<div style=""></div>
每个选择器都有权值,权重为和,#foo>.class::before 三者和为权重,权值id>标签>class>伪类。
today 优先级由高到低
<span style=""></span>
一个很优秀的说明css选择器优先级的图:https://specifishity.com/
通用选择器(*),组合符(+,>,〜,'',||)和否定伪类(:not())对权重没有影响。
1 year before absolute
减少了计算,translate()不影响其他元素,性能更好,GPU计算次数更少
today 在我的这篇博问中有答案:CSS3动画卡顿性能优化解决方案
translate()涉及到的是合成器线程,与主线程是相互独立的,所以会比较快。 而absolute positioning涉及到的是主线程,会导致主线程负责的布局重绘和js执行,所以会比较慢。
1 year before
today 关于这个问题曾经产出2篇博客: 从规范去看Function.prototype.apply到底是怎么工作的? 从规范去看Function.prototype.call到底是怎么工作的? call是索取,apply是付出。 从call和apply的字面意思就可以看出,call调用,apply应用,调用函数,应用参数。 call和apply的主要区别在于,call仅仅切换this上下文到其他类,从而调用自己不存在的方法;而apply主要是为了将其他类型的参数传递到自己内部,再调用自己的方法。
假设有foo,bar。
foo.call(bar)
bar调用foo的方法,实例Object.toString([1,2,3])->"[object Array]",数组实例调用了Object类的toString方法。
foo.apply(null, bar)
foo的方法应用bar的参数,Math.max.apply(null, [1,2,3])->3,Math的max方法应用了[1,2,3]中的每个参数。
1 year before
JSONP
原理:异步插入一个<script></script>
,会有XSS问题
原因:没有调用XMR对象
today
一种比较古老的不安全的跨域请求访问方式,没有调用XMR对象,服务器允许浏览器在query parameter中传递浏览器内定义的函数,而这个函数是有概率被XSS攻击改写的。
来自StackOverflow高票答案:https://stackoverflow.com/questions/2067472/what-is-jsonp-and-why-was-it-created
JSONP不是一个很复杂的问题。
假设我们在example.com
域名下,此时我们想给example.net
域名发送一个请求。为了请求成功,需要跨越域名边界,这对于浏览器来说是禁忌。
绕开这个限制的一种方式是<script>
标签。当你使用script标签的时候,域名限制会被忽略,但是对结果不能做任何处理,脚本是被评估过的。
开始进入JSONP。当你发送一个请求到支持JSONP的服务器,你会传一些特殊的关于你的页面的数据给服务器。这种方式下,服务器会以你的浏览器处理起来方便的方式包装响应。
例如,服务器需要一个叫做callback的参数去开启JSONP功能。然后你的请求会想下面这样:
http://www.example.net/sample.aspx?callback=mycallback
没有JSONP的情况下,这可以返回一些基本的JS对象,例如:
{foo: 'bar'}
然而,在支持JSONP的情况下,服务器接收到callback参数,它包裹结果的方式是不一样的,会返回下面这样的数据:
mycallback({foo: 'bar'});
就如你缩减,他会调用浏览器端的方法。所以,在你的页面上callback的定义如下:
mycallback = function(data){
alert(data.foo);
};
现在的话,在脚本加载成功后,它会被评估,然后函数执行。cross-domain请求成功!
所以JSONP存在一个很严重的问题:你失去了对请求的控制。例如,无法得知错误代码的返回。可以使用定时器去监控请求,但是这不是很好。JSONRequest是一个非常好的跨域脚本执行的方式,安全,并且获得更多对请求的控制。
2015年,CORS是一个与JSONRequest可以抗衡的方案。JSONP在老式浏览器下仍旧有用,但是不安全。 CORS是做跨域请求访问的更安全、更高效的一种方式。
1 year before
jade
vue angular react
{ ... }
或者{{ ... }}
today: 一些好用的模板引擎库
常用的还是前端框架自带的以及pug,由于我只对vue.js的比较熟悉所以就没有罗列react和angular的demo。
1 year before 这个问题写过博客,看过规范。 ①===是==的子集 ②==有类型转换 ③规范内实现机制不同 today 你真的理解==和===的区别吗?
1 year before 浏览器安全机制
today 如何理解same-origin policy?
1 year before axios
today
1 year before 解决了callback hell问题。
today 以一个图片资源加载绘制canvas。
class CanvasImage {
constructor(url, width, height) {
this.width = width || 500;
this.height = height || 500;
this.url = url || '';
this.element = new Image(this.width, this.height);
}
get imageElement() {
return this.element;
}
}
callback hell方式
source.onload = function() {
const target = new CanvasImage(url, 80, 80).imageElement;
target.onload = function() {
const main = new MainCanvas(source, target, 'right').canvasElement;
context.drawImage(main, 0, 0, 500, 500);
};
};
Promise方式
const sourcePromise = new Promise((resolve) => {
setTimeout(() => {
const target = new CanvasImage(url, 80, 80).imageElement;
resolve(target);
}, 0);
});
source.onload = function() {
sourcePromise.then((target) => {
const main = new MainCanvas(source, target, 'right').canvasElement;
context.drawImage(main, 0, 0, 500, 500);
});
};
async/await方式
function sourceCanvasImage() {
return new Promise((resolve) => {
setTimeout(() => {
const target = new CanvasImage(url, 80, 80).imageElement;
resolve(target);
}, 0);
});
}
async function mergeCanvas() {
const targetElement = await sourceCanvasImage();
const main = new MainCanvas(source, targetElement, 'right').canvasElement;
context.drawImage(main, 0, 0, 500, 500);
}
source.onload = function() {
mergeCanvas();
};
1 year before
today 官方的解释更加权威:https://nodejs.org/de/docs/guides/event-loop-timers-and-nexttick/
什么是Event Loop?event loop允许Node.js执行非阻塞的I/O操作-----尽管JS是单线程的-----它尽可能地通过把操作卸载到系统内核(kernel)。
因为大多数现代的内核(kernel)是多线程的,它们可以在后台处理多个操作。当其中之一完成后,kernel会告诉Node.js一个适当的callback可以被添加到poll queue(轮询队列)中并且执行。
更多原理上的内容,可以参考:[译]Node.js Event Loop,Timers和 process.nextTick()
event loop,原理细节包括以下内容
其中前三部分属于main thread,可以阅读node源码一探究竟。最后的background thread属于libuv的部分,可以去深入libuv源码(这是一个专门处理异步的c语言库)理解其实现机制。
但是阅读源码需要非常好的基础。这里推荐一篇囊括了以上知识点的非常走心的文章:https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/
var foo = 10 + '20';
1 year before:
30
today:
"1020"
add(2, 5);// 7
add(2)(5);// 7
1 year before 通过arguments类数组对象。
function foo(){
var sum = 0;
for(var i = 0; i<arguments.length; i++){
sum += arguments[i]
}
if(arguments.length>=2){
return sum;
}else{
return foo;
}
}
add(2)(5)运行失败。 today
const add = (a, b) => {
const result =
a && b
? a + b
: function(b) {
return a + b;
};
return result;
};
var foo = "Hello";
(function() {
var bar = " world";
alert(foo + bar);
})();
alert(foo + bar);
1 year before "undefined World" "Hello undefined"
today "Hello world" // 立即执行函数作用域可以访问全局变量 Uncaught ReferenceError: bar is not defined // 全局作用域不可以访问局部变量
console.log('one');
setTimeout(function() {
console.log('two');
}, 0);
console.log('three');
1 year before one three two today one three two 原因:优先执行函数调用栈中任务,setTimeout排入宏任务队列延后执行。 event loop包括call stack,(宏)任务队列,微任务队列和background thread,而call stack中的普通代码优先执行,setTimeout会经由background thread进入宏任务队列,宏任务队列间隙执行微任务队列。
function getResult(value, time){
return new Promise((resolve)=>{
setTimeout(()=>{
console.log(value);
resolve();
}, time);
});
}
(async () => {
const a = getResult(1, 300);
const b = getResult(2, 200);
await a;
await b;
})();
(async () => {
await getResult(1, 300);
await getResult(2, 200);
})();
1 year before 1 2 today 2 1 1 2 这是一道考察async的题目:如何理解async函数?
var obj = {
a: 1,
name: 'world',
objSayName: function(fn) {
fn();
}
}
var name = 'hello';
var arr = [1, 2, 3, 4, 5];
function foo(o) {
var bar = arr || [6, 7, 8];
var arr = [4, 2, 9];
var baz = o;
baz.a = 2;
console.log(bar, obj.a);
}
function sayName() {
return console.log(this.name);
}
foo(obj);
obj.objSayName(sayName);
1 year later [4,2,9] 2 'hello' today [6,7,8] 2 'hello' 原因: 变量提升。
var bar,arr,baz;
bar = arr || [6, 7, 8];// 此时arr是undefined,因此bar得到了[6, 7, 8]赋值
arr = [4, 2, 9];
baz获得了obj的引用,所有修改baz相当于修改obj,所以打印出2.
因为闭包,全局的sayName函数内的this指向全局,所以是hello。
现东家的面试题,是我最欣赏的一套面试题,在这里已经工作了接近1年时间,成长许多。
题目主要分为4个部分:
答案已验证准确性并更新。 我将按照“1 year before”和“today”的角度去进行解答,也是对自己成长的一个记录。