本文参考文章《一名【合格】前端工程师的自检清单》, 并对其中的部分题目进行了解答,如有遗漏或错误之处望你们指出纠正,共同进步。(点击题目展开答案!) javascript
此文章 Markdown 源文件地址:github.com/zxpsuper/bl…css
前端工程师吃饭的家伙,深度、广度同样都不能差。html
JavaScript中的每个值都有它本身的类型,JavaScript规定了七种语言类型,他们是:前端
Undefined Null Boolean String Number Symbol Object
vue
对象数据被存储于堆中 (如对象、数组、函数等,它们是经过拷贝和new出来的)。html5
引用类型的数据的地址指针是存储于栈中的,当咱们想要访问引用类型的值的时候,须要先从栈中得到对象的地址指针,而后,在经过地址指针找到堆中的所须要的数据。java
ES6
引入了一种新的原始数据类型 Symbol
,表示独一无二的值。node
symbol
类型的 key
不能被 Object.keys
和 for..of
循环枚举。所以可看成私有变量使用。react
let mySymbol = Symbol('key');
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
复制代码
JavaScript
中的变量分为基本类型和引用类型:webpack
基本类型: 保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,经过按值访问
引用类型: 保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript
不容许直接访问堆内存中的位置,所以操做对象时,实际操做对象的引用
String(), Number(), Boolean()
装箱:就是把基本类型转变为对应的对象。装箱分为隐式和显示
// 隐式装箱: 每当读取一个基本类型的值时,后台会建立一个该基本类型所对应的对象。
// 在这个基本类型上调用方法,实际上是在这个基本类型对象上调用方法。
// 这个基本类型的对象是临时的,它只存在于方法调用那一行代码执行的瞬间,执行方法后马上被销毁。
let num=123;
num.toFixed(2); // '123.00'//上方代码在后台的真正步骤为
var c = new Number(123);
c.toFixed(2);
c = null;
// 显式装箱: 经过内置对象 Boolean、Object、String 等能够对基本类型进行显示装箱。
var obj = new String('123');
复制代码
拆箱: 拆箱与装箱相反,把对象转变为基本类型的值。
Number([1]); //1
// 转换演变:
[1].valueOf(); // [1];
[1].toString(); // '1';Number('1'); //1
复制代码
JavaScript中的变量分为基本类型和引用类型:
基本类型: 保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,经过按值访问
引用类型: 保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript
不容许直接访问堆内存中的位置,所以操做对象时,实际操做对象的引用
Number
转换的值不一样,Number(null)
输出为 0
, Number(undefined)
输出为 NaN
null
表示一个值被定义了,可是这个值是空值
undefined
表示缺乏值,即此处应该有值,可是尚未定义
typeof
—— 返回给定变量的数据类型,可能返回以下字符串:'undefined'——Undefined
'boolean'——Boolean
'string'——String
'number'——Number
'symbol'——Symbol
'object'——Object / Null (Null 为空对象的引用)
'function'——Function
// 对于一些如 error() date() array()没法判断,都是显示object类型
复制代码
instanceof
检测 constructor.prototype
是否存在于参数 object
的原型链上,是则返回 true
,不是则返回 false
。alert([1,2,3] instanceof Array) // true
alert(new Date() instanceof Date) // true
alert(function(){this.name="22";} instanceof Function) //true
alert(function(){this.name="22";} instanceof function) //false // instanceof 只能用来判断两个对象是否属于实例关系,而不能判断一个对象实例具体属于哪一种类型。 复制代码
constructor
—— 返回对象对应的构造函数。alert({}.constructor === Object); => true
alert([].constructor === Array); => true
alert('abcde'.constructor === String); => true
alert((1).constructor === Number); => true
alert(true.constructor === Boolean); => true
alert(false.constructor === Boolean); => true
alert(function s(){}.constructor === Function); => true
alert(new Date().constructor === Date); => true
alert(new Array().constructor === Array); => true
alert(new Error().constructor === Error); => true
alert(document.constructor === HTMLDocument); => true
alert(window.constructor === Window); => true
alert(Symbol().constructor); => undefined
// null 和 undefined 是无效的对象,没有 constructor,所以没法经过这种方式来判断。
复制代码
Object.prototype.toString()
默认返回当前对象的 [[Class]]
。这是一个内部属性,其格式为 [object Xxx]
,是一个字符串,其中 Xxx
就是对象的类型。Object.prototype.toString.call(new Date);//[object Date]
Object.prototype.toString.call(new String);//[object String]
Object.prototype.toString.call(Math);//[object Math]
Object.prototype.toString.call(undefined);//[object Undefined]
Object.prototype.toString.call(null);//[object Null]
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(123) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用
// 比较全面
复制代码
隐式转换通常说的是 Boolean
的转换
在 if
语句中,null
,""
,undefinded
, 0
, false
都会被转化为 false
通常应用于对接口数据判空时使用
精度丢失缘由,说是 JavaScript
使用了 IEEE 754
规范,二进制储存十进制的小数时不能完整的表示小数
可以表示的最大数字 Number.MAX_VALUE
等于 1.7976931348623157e+308
,最大安全数字 Number.MAX_SAFE_INTEGER
等于 9007199254740991
避免精度丢失
100
或 1000
,变成整数再运算BigInt
大整数,它能够表示任意大小的整数,注意只能表示整数,而不受安全整数的限制A. 全部的引用类型(数组、对象、函数),都具备对象特性,便可自由扩展属性;
B. 全部的引用类型(数组、对象、函数),都有一个`__proto__`属性(隐式原型),属性值是一个普通的对象;
C. 全部的函数,都具备一个 `prototype`(显式原型),属性值也是一个普通对象;
D. 全部的引用类型(数组、对象、函数),其隐式原型指向其构造函数的显式原型;`(obj._proto_ === Object.prototype)`;
E. 当试图获得一个对象的某个属性时,若是这个对象自己没有这个属性,那么会去它的 `__proto__` (即它的构造函数的 `prototype`)中去寻找;
复制代码
简单说就是判断实例对象的__proto__
是否是强等于对象的prototype
属性,若是不是继续往原型链上找,直到 __proto__
为 null
为止。
function instanceOf(obj, object) {//obj 表示实例对象,object 表示对象
var O = object.prototype;
obj = obj.__proto__;
while (true) {
if (obj === null)
return false;
if (O === obj) // 这里重点:当 O 严格等于 obj 时,返回 true
return true;
obj = obj.__proto__;
}
}
复制代码
执行上下文 就是当前 JavaScript
代码被解析和执行时所在环境的抽象概念, JavaScript
中运行任何的代码都是在执行上下文中运行。
执行上下文总共有三种类型:全局执行上下文, 函数执行上下文, Eval
函数执行上下文
执行栈,在其余编程语言中也被叫作调用栈,具备 LIFO(后进先出)结构,用于存储在代码执行期间建立的全部执行上下文。
详情请点击:《继承的几种实现方式》
new
一个对象的详细过程:function Test() {}
const test = new Test();
复制代码
建立一个对象 const obj = {}
设置新对象的 constructor
属性为构造函数的名称,设置新对象的__proto__
属性指向构造函数的 prototype
对象
obj.constructor = Test;
obj.__proto__ = Test.prototype;
复制代码
使用新对象调用函数,函数中的 this 被指向新实例对象 Test.call(obj)
将初始化完毕的新对象地址,保存到等号左边的变量中
new
操做符function myNew(Obj,...args){
var obj = Object.create(Obj.prototype);//使用指定的原型对象及其属性去建立一个新的对象
Obj.apply(obj,args); // 绑定 this 到obj, 设置 obj 的属性
return obj; // 返回实例
}
复制代码
ES6
类的底层仍是经过构造函数去建立的。// es6 Parent类实现
class Parent {
constructor(name,age){
this.name = name;
this.age = age;
}
speakSomething(){
console.log("I can speek chinese");
}
}
// 转化为
var Parent = function () {
function Parent(name, age) {
_classCallCheck(this, Parent); // 判断实例 Parent instanceof Parent(函数)是否为true
this.name = name;
this.age = age;
}
// 此方法经过使用 Object.defineProperty 为 function Parent 的 prototype 添加属性值
_createClass(Parent, [{
key: "speakSomething",
value: function speakSomething() {
console.log("I can speek chinese");
}
}]);
return Parent;
}();
复制代码
ES6
的继承实现//定义子类,继承父类
class Child extends Parent {
static width = 18
constructor(name,age){
super(name,age);
}
coding(){
console.log("I can code JS");
}
}
// 转化为
var Child = function (_Parent) {
_inherits(Child, _Parent);
function Child(name, age) {
_classCallCheck(this, Child);
return _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name, age));
}
_createClass(Child, [{
key: "coding",
value: function coding() {
console.log("I can code JS");
}
}]);
return Child;
}(Parent);
复制代码
这里其实就是多了一个 _inherits(Child, _Parent);
方法,实现了如下功能,具体可看文章《ES6类以及继承的实现原理》
//实现的结果是:
subClass.prototype.__proto__ = superClass.prototype
subClass.__proto__ = superClass // 实现静态属性的继承
复制代码
词法做用域也称静态做用域,javascript
采用静态做用域
静态做用域 —— 函数的做用域基于函数建立的位置。
动态做用域 —— 函数的做用域基于函数的使用位置。
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar(); // 输出 1 。JavaScript 采用的是词法做用域,也称为静态做用域。相同的,动态做用域此代码应该输出 2
复制代码
做用域(scope)就是变量访问规则的有效范围。
在 JavaScript
中全局变量的做用域是全局的,在代码的任何地方都是有定义的。然而函数的参数和局部变量只在函数体内有定义。另外局部变量的优先级要高于同名的全局变量,也就是说当局部变量与全局变量重名时,局部变量会覆盖全局变量。
原理:闭包就是可以读取其余函数内部变量的函数。因为在Javascript语言中,只有函数内部的子函数才能读取局部变量,所以能够把闭包简单理解成"定义在一个函数内部的函数"。
因此,在本质上,闭包就是将函数内部和函数外部链接起来的一座桥梁。
做用:闭包能够用在许多地方。它的最大用处有两个,一个是前面提到的能够读取函数内部的变量,另外一个就是让这些变量的值始终保持在内存中。
应用:1. 匿名自执行函数 2. 结果缓存 3. 封装局部变量
堆栈溢出 的产生是因为过多的函数调用,致使调用堆栈没法容纳这些调用的返回地址,通常在递归中产生。堆栈溢出极可能由无限递归(Infinite recursion)产生,但也可能仅仅是过多的堆栈层级.
参考连接:《内存泄漏与避免》
在 try
语句中,在执行 return
语句时,要返回的结果已经准备好了,就在此时,程序转到 finally
执行了。
在转去以前,try
中先把要返回的结果存放到局部变量中去,执行完 finally
以后,在从中取出返回结果。
所以,即便finally
中对返回的结果进行了改变,可是不会影响返回结果。
它应该使用栈保存返回值。
JavaScript
如何实现异步编程:
callback
(回调函数) 回调函数表明着,当某个任务处理完,而后须要作的事。好比读取文件,链接数据库,等文件准备好,或数据库链接成功执行编写的回调函数,又好比像一些动画处理,当动画走完,而后执行回调。
发布订阅模式 顾名思义,即是先订阅了事件,有人一发布事件你就知道了,接着执行后面的操做。
Promise
Promise
,简单说就是一个容器,里面保存着某个将来才会结束的事件的结果,相比回调函数,Promise
提供统一的 API
,各类异步操做均可以用一样的方法进行处理。
Generator
(生成器)函数 Generator
函数是 ES6
提供的一种异步编程解决方案,其行为相似于状态机。
async/await
async/await
本质上仍是基于 Generator
函数,能够说是 Generator
函数的语法糖,async
就至关于以前写的run函数(执行Generator
函数的函数),而 await
就至关于 yield
,只不过 await
表达式后面只能跟着 Promise
对象,若是不是 Promise
对象的话,会经过 Promise.resolve
方法使之变成 Promise
对象。async
修饰 function
,其返回一个 Promise
对象。
宏任务: setTimeout,setInterval,setImmediate (Node独有),requestAnimationFrame (浏览器独有),I/O,UI rendering (浏览器独有)
微任务: process.nextTick (Node独有),Promise,Object.observe,MutationObserver
// 执行顺序,先微队列,后宏队列。
console.log(1);
setTimeout(() => {
console.log(2);
setTimeout(() => {
console.log(8);
})
Promise.resolve().then(() => {
console.log(3)
});
});
new Promise((resolve, reject) => {
console.log(4)
setTimeout(() => {
console.log(10);
})
resolve()
}).then(() => {
console.log(5);
Promise.resolve().then(() => {
console.log(11)
});
setTimeout(() => {
console.log(13);
})
})
setTimeout(() => {
Promise.resolve().then(() => {
console.log(9)
});
console.log(6);
setTimeout(() => {
console.log(12);
})
})
console.log(7);
复制代码
从头到尾执行一次代码,根据上面分类规则分至不一样队列, new promise( function )
也是当即执行。setTimeout
的回调函数属于宏队列(macrotask)
,resolve
的回调函数属于微队列
// 栈区(stack)
console.log(1);
console.log(4);
console.log(7);
复制代码
// 宏队列
() => {
console.log(2);
setTimeout(() => {
console.log(8);
})
Promise.resolve().then(() => {
console.log(3)
});
}
() => {
console.log(10);
}
() => {
Promise.resolve().then(() => {
console.log(9)
});
console.log(6);
setTimeout(() => {
console.log(12);
})
}
复制代码
// 微队列
() => {
console.log(5);
Promise.resolve().then(() => {
console.log(11)
});
setTimeout(() => {
console.log(13);
})
}
复制代码
优先执行微队列,微队列执行过程当中产生的微队列和宏队列置于队列末尾排序执行,而宏队列产生的微队列和宏队列于新的队列中等待。。
执行微队列:(分类)
// 栈区(stack)
console.log(1);
console.log(4);
console.log(7);
//////////
console.log(5);
复制代码
// 微队列
() => {
console.log(11)
});
复制代码
// 宏队列
() => {
console.log(2);
setTimeout(() => {
console.log(8);
})
Promise.resolve().then(() => {
console.log(3)
});
}
() => {
console.log(10);
}
() => {
Promise.resolve().then(() => {
console.log(9)
});
console.log(6);
setTimeout(() => {
console.log(12);
})
}
() => {
console.log(13);
}
复制代码
此时新增了一个微队列console.log(11)
,由于是微队列产生的,继续执行:
// 栈区(stack)
console.log(1);
console.log(4);
console.log(7);
//////////
console.log(5);
/////////
console.log(11)
复制代码
// 微队列-空
复制代码
// 宏队列
() => {
console.log(2);
setTimeout(() => {
console.log(8);
})
Promise.resolve().then(() => {
console.log(3)
});
}
() => {
console.log(10);
}
() => {
Promise.resolve().then(() => {
console.log(9)
});
console.log(6);
setTimeout(() => {
console.log(12);
})
}
() => {
console.log(13);
}
复制代码
执行完微队列后执行宏队列:
// 栈区(stack)
console.log(1);
console.log(4);
console.log(7);
//////////
console.log(5);
/////////
console.log(11);
/////////
console.log(2);
console.log(10);
console.log(6);
console.log(13);
复制代码
// 微队列
() => {
console.log(3)
}
() => {
console.log(9)
}
复制代码
// 宏队列
() => {
console.log(8);
}
() => {
console.log(12);
}
复制代码
接下来执行微队列后宏队列,即:
// 栈区(stack)
console.log(1);
console.log(4);
console.log(7);
//////////
console.log(5);
/////////
console.log(11);
/////////
console.log(2);
console.log(10);
console.log(6);
console.log(13);
////////
console.log(3)
console.log(9)
////////
console.log(8);
console.log(12);
复制代码
// 一个 promise 的 function
function delay(time) {
return new Promise((resolve, reject) => {
console.log(`wait ${time}s`)
setTimeout(() => {
console.log('execute');
resolve()
}, time * 1000)
})
}
const arr = [3, 4, 5];
复制代码
reduce
arr.reduce((s, v) => {
return s.then(() => delay(v))
}, Promise.resolve())
复制代码
async
+ 循环 + await
(
async function () {
for (const v of arr) {
await delay(v)
}
}
)()
复制代码
let p = Promise.resolve()
for (const i of arr) {
p = p.then(() => delay(i))
}
复制代码
function dispatch(i, p = Promise.resolve()) {
if (!arr[i]) return Promise.resolve()
return p.then(() => dispatch(i + 1, delay(arr[i])))
}
dispatch(0)
复制代码
window.requestAnimationFrame
和 document.createDocumentFragment()
实现, 可参考文章【如何解决页面加载海量数据而不冻结前端UI】DOM
结构最简单化。可参考文章【大数据如何在前端流畅展现】,不过他的 Demo
有点问题.ECMAScript
是 JavaScript
的规范,JavaScript
是 ECMAScript
的实现。
在使用 setInterval
方法时,每一次启动都须要对 setInterval
方法返回的值作一个判断,判断是不是空值,若不是空值,则要中止定时器并将值设为空,再从新启动,若是不进行判断并赋值,有可能会形成计时器循环调用,在同等的时间内同时执行调用的代码,并会随着代码的运行时间增长而增长,致使功能没法实现,甚至占用过多资源而卡死奔溃。所以在每一次使用setInterval方法时,都须要进行一次判断。
let timer = setInterval(func, 1000)
// 在其余地方再次用到setInterval(func, 1000)
if (timer !== null) {
clearInterval(timer)
timer = null
}
timer = setInterval(func, 1000)
复制代码
setIntervalFunc = () =>{
console.log(1) //使用递归
setTimeout(setIntervalFunc, 1000);
};
setInterval()
复制代码
邮箱校验:
function isEmail(emailStr) {
return /^[a-zA-Z0-9]+([._-]*[a-zA-Z0-9]*)*@[a-zA-Z0-9]+.[a-zA-Z0-9{2,5}$]/.test(emailStr);
}
复制代码
URL解析:
function isUrl(urlStr) {
return /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\*\+,;=.%]+$/.test(value)
}
复制代码
数组去重:
// set结构
let arr = [1, 1, 2, 2, 3, 3]
arr2 = [...new Set(arr)]
console.log(arr2) // [1,2,3]
// Object.keys(), 利用属性 key 的惟一性
let arrObj = [1, 1, 2, 2, 3, 3]
arrObj2 = {}
for (i in arrObj) {
arrObj2[arrObj[i]] = true
}
let arrObj3 = Object.keys(arrObj2)
console.log(arrObj3)
// 利用 indexOf() 查询数组内是否已经包含该元素
var arrIndexOf = ['a','c','b','d','a','b']
var arrIndexOf2 = [];
for(var i = 0;i<arrIndexOf.length;i++){
if(arrIndexOf2.indexOf(arrIndexOf[i])<0){
arrIndexOf2.push(arrIndexOf[i]);
}
}
console.log(arrIndexOf2)// ['a', 'c', 'b', 'd']
复制代码
语义化标签:<header> <footer> <nav> <section> <article> <aside> 等
标签分类:
文档标签(10 个):<html>、<head>、<body>、<title>、<meta>、<base> 、<style>、<link>、<script>、<noscript>
表格标签(10 个):<table>、<thead>、<tbody>、<tfoot>、<tr>、<td>、<th> 、<col>、<colgroup>、<caption>
表单标签(10 个):<from>、<input>、<textarea>、<button>、<select> 、<optgroup>、<option>、<label>、<fieldset>、<legend>
列表标签(6个):<ul>、<ol>、<li>、<dl>、<dt>、<dd>
多媒体标签(5个):<img>、<map>、<area>、<object>、<param>
文章标签:<h1> - <h6> 、<p>、<br>、<span>、<bdo>、<pre>、<acronym>、<abbr>、<blockquote>、<q>、<ins>、<del>、<address>
字体样式标签:<tt>、<i>、<b>、<big>、<small>、<em>、<strong>、<dfn>、<code>、<samp>、<kbd>、<var>、<cite>、<sup>、<sub>
在不一样的场景使用不一样的标签,更能显示清晰的结构。
<head>
标签用于定义文档的头部,它是全部头部元素的容器。<head>
中的元素能够引用脚本、指示浏览器在哪里找到样式表、提供元信息等等。能够包含的标签有: <base>, <link>, <meta>, <script>, <style>, 以及 <title>。
<title>
定义文档的标题,它是 head 部分中惟一必需的元素。
<meta>
元素可提供有关页面的元信息(meta-information),好比针对搜索引擎和更新频度的描述和关键词。使用方法参考【meta标签详解】
w3c
盒子模型的范围包括 margin、border、padding、content
,而且 content
部分不包含其余部分ie
盒子模型的范围也包括 margin、border、padding、content
,和标准 w3c
盒子模型不一样的是:ie
盒子模型的 content
部分包含了 border
和 pading
。不一样级别优先级: !important > 行内样式 > ID选择器 > 类选择器 > 元素 > 通配符 > 继承 > 浏览器默认属性
相同级别优先级: 内联(行内)样式 > 内部样式表 > 外部样式表 > 导入样式(@import)。
可继承属性:
字体系列属性, font-family, font-weight, font-size, font-style...
文本系列属性, text-indent, text-align, line-heigh, word-spacing, letter-spacing, text-transform, color
元素可见性:visibility, 光标属性:cursor
复制代码
AT rule:
1、什么是 at-rules
eg:@charset "utf-8";
at-rule
是 CSS
样式声明,以 @
开头,紧跟着是标识符(charset)
,最后以分号(;)结尾。
2、几个 at-rules
一、@charset
—定义被样式表使用的字符集
二、@import
——告诉 CSS
引擎包含外部的 CSS
样式表
三、@namespace
——告诉 CSS
引擎全部的内容都必须考虑使用 XML
命名空间前缀
四、嵌套at-rules
(1)@media
——条件组规则。若是设备符合标准定义的条件查询则使用该媒体
(2)@font-face
——描述了一个将从外部下载的字体
(3)@keyframes
——描述了中间步骤在 CSS
动画的序列
(4)@page
——描述了文件的布局变化,当要打印文档时。
(5)@supports
——条件组规则,若是浏览器知足给出的规则,则把它应用到内容中
(6)@document
——条件组规则,若是被用到文档的 CSS
样式表知足了给定的标准,那么将被应用到全部的内容中。
伪类:用于向某些选择器添加特殊的效果. :active, :focus, :link, :visited, :hover, :first-child
伪元素:用于将特殊的效果添加到某些选择器. :before, :after, :first-line, :first-letter
伪类和伪元素的根本区别在于:它们是否创造了新的元素(抽象)。从咱们模仿其意义的角度来看,若是须要添加新元素加以标识的,就是伪元素,反之,若是只须要在既有元素上添加类别的,就是伪类。
HTML 文档流的排版规则: 把元素按从上而下,从左到右的顺序默认排列。不在一行的元素从上而下,在一行的从左到右排列。
CSS 几种定位的规则:
static
定位(普通流定位)float
定位(浮动定位), 有两个取值:left
(左浮动)和 right
(右浮动)。浮动元素会在没有浮动元素的上方,效果上看是遮挡住了没有浮动的元素,有float样式规则的元素是脱离文档流的,它的父元素的高度并不能有它撑开。
relative
定位(相对定位), 相对本元素的左上角进行定位,top,left,bottom,right
均可以有值。虽然通过定位后,位置可能会移动,可是本元素并无脱离文档流,还占有原来的页面空间。absolute
定位(绝对定位), 相对于祖代中有 relative
(相对定位)而且离本元素层级关系上是最近的元素的左上角进行定位,若是在祖代元素中没有有 relative
定位的,就默认相对于body
进行定位。绝对定位是脱离文档流的fixed
定位(固定定位),这种定位方式是相对于整个文档的,只需设置它相对于各个方向的偏移值,就能够将该元素固定在页面固定的位置,一般用来显示一些提示信息,脱离文档流;雪碧图实现原理: CSS Sprite
,是一种 CSS
图像合并技术,该方法是将小图标和背景图像合并到一张图片上,而后利用 css
的背景定位来显示须要显示的图片部分。
参考文章: 【CSS实现水平垂直居中的1010种方式】
BFC(Block formatting context)
直译为"块级格式化上下文"。它是一个独立的渲染区域,只有块级元素参与, 它规定了内部的块级元素如何布局,而且与这个区域外部绝不相干。
BCF 能够解决的问题:浮动定位,消除外边距折叠,清除浮动,自适应多栏布局
BFC的建立:根元素或包含根元素的元素,浮动元素(float
不为none
),绝对定位元素( position
为 absolute
或者 fixed
),display
为 inline-block,table-cell,table-caption,overflow
值不为 visible
,弹性元素( flex
布局),网格元素( grid
布局)
CSS模块化方案: 文件细化,命名约定,CSS Modules , css in js
如何防止 CSS 阻塞渲染:
CSS
是阻塞渲染的资源。须要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间。
有一些 CSS
样式只在特定条件下(例如显示网页或将网页投影到大型显示器上时)使用,咱们能够经过 CSS
“媒体类型”和“媒体查询”来解决这类用例:
<link href="print.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">
首屏相关的关键 `CSS` 使用阻塞渲染的方式加载,全部的非关键 `CSS` 在首屏渲染完成后加载。
复制代码
参考文章:【瀑布流布局的实现】
// 圆形
.circle{
width:100px;
height:100px;
border-radius:50%;
background:blue;
}
// 三角形
.triangle {
width: 0;
height: 0;
border: 50px solid blue;
/* 经过改变边框颜色,能够改变三角形的方向 */
border-color: blue transparent transparent transparent;
}
// 扇形,扇形是由一个圆形和一个矩形进行组合获得的,用矩形遮住圆形的一部分就造成了扇形。
.sector {
width: 142px;
height: 142px;
background: #fff;
border-radius: 50%;
background-image: linear-gradient(to right, transparent 50%, #655 0);
}
.sector::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
width: 100%;
background-color: inherit;
transform-origin: left;
/*调整角度,改变扇形大小*/
transform: rotate(230deg);
}
// 菱形
.rhombus {
width: 200px;
height: 200px;
transform: rotateZ(45deg) skew(30deg, 30deg);
background: blue;
}
复制代码
CSS3 新增了 transition-timing-function 属性,它的取值就能够设置为一个三次贝塞尔曲线方程。
圣杯布局, 两边顶宽,中间自适应的三栏布局。
关于编译原理,不须要理解很是深刻,可是最基本的原理和概念必定要懂,这对于学习一门编程语言很是重要
代码就是程序员用开发工具所支持的语言写出来的源文件,是一组由字符、符号或信号码元以离散形式表示信息的明确的规则体系。
计算机源代码最终目的是将人类可读文本翻译成为计算机可执行的二进制指令,这种过程叫编译,它由经过编译器完成。
parseInt(str, radix)
将一个 radix 进制的 str 转化为十进制,parseInt('23',8) // 19
,将八进制的‘23’转化为10进制的‘19’
number.toString(radix)
将一个数字转化为 radix 进制的数字字符串
0x11.toString(8) // 21
0x11.toString(10) // 17
0x11.toString(2) // 10001
复制代码
协议,网络协议的简称,网络协议是通讯计算机双方必须共同听从的一组约定。如怎么样创建链接、怎么样互相识别等。只有遵照这个约定,计算机之间才能相互通讯交流。它的三要素是:语法、语义、时序。
TCP/IP 网络协议族的构成: TCP/IP
协议是 Internet
最基本的协议。由传输层的 TCP
协议和网络层的 IP
协议组成。
TCP
负责发现传输的问题,一有问题就发出信号,要求从新传输,直到全部数据安全正确地传输到目的地。而 IP
是给因特网的每一台联网设备规定一个地址。
应用层
应用层决定了向用户提供应该服务时通讯的活动。
TCP/IP
协议族内预存了各种通用的应用服务。好比,FTP
(File Transfer Protocol,文件传输协议)和 DNS
(Domain Name System,域名系统)服务就是其中的两类。HTTP
协议也处于该层。
传输层
传输层对上层应用层,提供处于网络链接中两台计算机之间的数据传输。
在传输层有两个性质不一样的协议:TCP
(Transmission Control Protocol,传输控制协议)和 UDP
(User Data Protocol,用户数据报协议)。
网络层(又名网络互连层)
网络层用来处理在网络上流动的数据包。数据包是网络传输的最小数据单位。该层规定了经过怎样的路径(所谓的传输路线)到达对方计算机,并把数据包传送给对方。
与对方计算机之间经过多台计算机或网络设备进行传输时,网络层所起的所用就是在众多的选项内选择一条传输路线。
链路层(又名数据链路层,网络接口层)
用来处理链接网络的硬件部分。包括控制操做系统、硬件的设备驱动、NIC(Network Interface Card,网络适配器,即网卡),及光纤等物理可见部分(还包括链接器等一切传输媒介)。硬件上的范畴均在链路层的做用范围以内。
三次握手和四次挥手详细原理:
三次握手:避免链接请求的数据包丢失,数据传输过程由于网络并发量很大在某结点被阻塞
四次挥手: TCP链接是全双工通道,须要双向关闭。
参考文章: 【TCP/IP协议族】
TCP
的协议:FTP
(文件传输协议)、Telnet
(远程登陆协议)、SMTP
(简单邮件传输协议)、POP3
(和 SMTP
相对,用于接收邮件)、HTTP
协议等。
TCP
提供可靠的、面向链接的数据传输服务。使用 TCP
通讯以前,须要进行“三次握手”创建链接,通讯结束后还要使用“四次挥手”断开链接。
DNS 的做用:DNS是互联网的一项服务。它做为将域名和IP地址相互映射的一个分布式数据库,可以令人更方便地访问互联网。
DNS解析过程:
一、在浏览器中输入 www.qq.com
域名,操做系统会先检查本身本地的 hosts
文件是否有这个网址映射关系,若是有,就先调用这个 IP
地址映射,完成域名解析。
二、若是 hosts
里没有这个域名的映射,则查找本地 DNS解析器缓存
,是否有这个网址映射关系,若是有,直接返回,完成域名解析。
三、若是 hosts
与 本地DNS解析器缓存
都没有相应的网址映射关系,首先会找 TCP/ip
参数中设置的 首选DNS服务器
,在此咱们叫它 本地DNS服务器
,此服务器收到查询时,若是要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具备权威性。
四、若是要查询的域名,不禁 本地DNS服务器区域解析
,但该服务器已缓存了此网址映射关系,则调用这个 IP
地址映射,完成域名解析,此解析不具备权威性。
五、若是 本地DNS服务器
本地区域文件与缓存解析都失效,则根据 本地DNS服务器
的设置(是否设置转发器)进行查询,若是未用转发模式,本地 DNS
就把请求发至 13
台根 DNS
,根 DNS
服务器收到请求后会判断这个域名 (.com)
是谁来受权管理,并会返回一个负责该顶级域名服务器的一个IP
。本地DNS服务器
收到 IP
信息后,将会联系负责 .com
域的这台服务器。这台负责 .com
域的服务器收到请求后,若是本身没法解析,它就会找一个管理 .com
域的下一级 DNS
服务器地址(http://qq.com)
给 本地DNS服务器
。当 本地DNS服务器
收到这个地址后,就会找 http://qq.com
域服务器,重复上面的动做,进行查询,直至找到 www.qq .com
主机。
六、若是用的是转发模式,此 DNS
服务器就会把请求转发至上一级 DNS
服务器,由上一级服务器进行解析,上一级服务器若是不能解析,或找根 DNS
或把转请求转至上上级,以此循环。无论是 本地DNS服务器
用是是转发,仍是根提示,最后都是把结果返回给 本地DNS服务器
,由此 DNS
服务器再返回给客户机。
DNS 优化:减小DNS的请求次数;进行DNS预获取 。
减小DNS的请求次数————在项目中减小不一样域名的http请求,尽可能少的域名减小DNS的请求数
DNS预获取————减小用户的等待时间,提高用户体验 。
默认状况下浏览器会对页面中和当前域名(正在浏览网页的域名)不在同一个域的域名进行预获取,而且缓存结果,这就是隐式的 DNS Prefetch。若是想对页面中没有出现的域进行预获取,那么就要使用显示的 DNS Prefetch 了。
<meta http-equiv="x-dns-prefetch-control" content="on">
<link rel="dns-prefetch" href="//www.itechzero.com">
<link rel="dns-prefetch" href="//api.share.baidu.com">
<link rel="dns-prefetch" href="//bdimg.share.baidu.com">
复制代码
CDN
的全称是 Content Delivery Network
,即内容分发网络。其基本思路是尽量避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。
通常状况下,浏览器都会对单个域名下的并发请求数(文件加载)进行限制,一般最多有 4
个,那么第 5
个加载项将会被阻塞,直到前面的某一个文件加载完毕。由于 CDN
文件是存放在不一样区域(不一样 IP
)的,因此对浏览器来讲是能够同时加载页面所需的全部文件(远不止 4
个),从而提升页面加载速度。
二、文件可能已经被加载过并保存有缓存
一些通用的 js
库或者是 css
样式库,如 jQuery
,在网络中的使用是很是广泛的。当一个用户在浏览你的某一个网页的时候,颇有可能他已经经过你网站使用的 CDN
访问过了其余的某一个网站,恰巧这个网站一样也使用了 jQuery
,那么此时用户浏览器已经缓存有该 jQuery
文件(同 IP
的同名文件若是有缓存,浏览器会直接使用缓存文件,不会再进行加载),因此就不会再加载一次了,从而间接的提升了网站的访问速度。
三、分布式的数据中心
假如你的站点布置在北京,当一个香港或者更远的用户访问你的站点的时候,他的数据请求势必会很慢很慢。而 CDN
则会让用户从离他最近的节点去加载所需的文件,因此加载速度提高就是理所固然的了。
参考文章:【HTTP 请求详解】
HTTP协议的六种请求方法:
GET: 发送请求来得到服务器上的资源,请求体中不会包含请求数据,请求数据放在协议头中
POST: 和 get
同样很常见,向服务器提交资源让服务器处理,好比提交表单、上传文件等,可能致使创建新的资源或者对原有资源的修改。提交的资源放在请求体中。不支持快取。非幂等
HEAD: 本质和 get
同样,可是响应中没有呈现数据,而是 http
的头信息,主要用来检查资源或超连接的有效性或是否能够可达、检查网页是否被串改或更新,获取头信息等,特别适用在有限的速度和带宽下。
PUT: 和 post
相似,html
表单不支持,发送资源与服务器,并存储在服务器指定位置,要求客户端事先知道该位置;好比 post
是在一个集合上(/province)
,而 put
是具体某一个资源上(/province/123)
。因此 put
是安全的,不管请求多少次,都是在 123
上更改,而 post
可能请求几回建立了几回资源。幂等
DELETE: 请求服务器删除某资源。和 put
都具备破坏性,可能被防火墙拦截
CONNECT: HTTP/1.1
协议中预留给可以将链接改成管道方式的代理服务器。就是把服务器做为跳板,去访问其余网页而后把数据返回回来,链接成功后,就能够正常的 get
、post
了。
7: OPTIONS: 获取 http
服务器支持的 http
请求方法,容许客户端查看服务器的性能,好比 ajax
跨域时的预检等。 8: TRACE: 回显服务器收到的请求,主要用于测试或诊断。通常禁用,防止被恶意攻击或盗取信息。
1XX:信息状态码
2XX:成功状态码
3XX:重定向
4XX:客户端错误
5XX: 服务器错误
缓存处理,在 HTTP1.0
中主要使用 header
里的 If-Modified-Since,Expires
来作为缓存判断的标准,HTTP1.1
则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match
等更多可供选择的缓存头来控制缓存策略。
带宽优化及网络链接的使用,HTTP1.0
中,存在一些浪费带宽的现象,例如客户端只是须要某个对象的一部分,而服务器却将整个对象送过来了,而且不支持断点续传功能,HTTP1.1
则在请求头引入了 range
头域,它容许只请求资源的某个部分,即返回码是 206(Partial Content)
,这样就方便了开发者自由的选择以便于充分利用带宽和链接。
错误通知的管理,在 HTTP1.1
中新增了24
个错误状态响应码,如 409(Conflict)
表示请求的资源与资源的当前状态发生冲突;410(Gone)
表示服务器上的某个资源被永久性的删除。
Host头处理,在 HTTP1.0
中认为每台服务器都绑定一个惟一的 IP
地址,所以,请求消息中的 URL
并无传递主机名 (hostname)
。但随着虚拟主机技术的发展,在一台物理服务器上能够存在多个虚拟主机(Multi-homed Web Servers)
,而且它们共享一个 IP
地址。HTTP1.1
的请求消息和响应消息都应支持 Host
头域,且请求消息中若是没有 Host
头域会报告一个错误(400 Bad Request)
。
长链接,HTTP 1.1
支持长链接(PersistentConnection)
和请求的流水线(Pipelining)
处理,在一个 TCP
链接上能够传送多个 HTTP
请求和响应,减小了创建和关闭链接的消耗和延迟,在 HTTP1.1
中默认开启 Connection: keep-alive
,必定程度上弥补了 HTTP1.0
每次请求都要建立链接的缺点。
HTTP2.0和HTTP1.X相比的新特性
新的二进制格式(Binary Format),HTTP1.x
的解析是基于文本。基于文本协议的格式解析存在自然缺陷,文本的表现形式有多样性,要作到健壮性考虑的场景必然不少,二进制则不一样,只认 0
和 1
的组合。基于这种考虑 HTTP2.0
的协议解析决定采用二进制格式,实现方便且健壮。
多路复用(MultiPlexing)
,即链接共享,即每个 request
都是是用做链接共享机制的。一个 request
对应一个 id
,这样一个链接上能够有多个 request
,每一个链接的 request
能够随机的混杂在一块儿,接收方能够根据 request
的 id
将 request
再归属到各自不一样的服务端请求里面。
header
压缩,如上文中所言,对前面提到过 HTTP1.x
的 header
带有大量信息,并且每次都要重复发送,HTTP2.0
使用 encoder
来减小须要传输的 header
大小,通信双方各自 cache
一份 header fields
表,既避免了重复 header
的传输,又减少了须要传输的大小。
服务端推送(server push),HTTP2.0
具备 server push
功能。
参考文章:【一个故事讲完 https】
参考文章:【设计模式】
观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。
// 观察者模式
class Subject{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub);
}
notify(){
this.subs.forEach(sub=> {
sub.update();
});
}
}
class Observer{
update(){
console.log('update');
}
}
let subject = new Subject();
let ob = new Observer();
//目标添加观察者了
subject.addSub(ob);
//目标发布消息调用观察者的更新方法了
subject.notify(); //update
复制代码
// 发布订阅者模式
class PubSub {
constructor() {
this.subscribers = {}
}
subscribe(type, fn) {
if (!Object.prototype.hasOwnProperty.call(this.subscribers, type)) {
this.subscribers[type] = [];
}
this.subscribers[type].push(fn);
}
unsubscribe(type, fn) {
let listeners = this.subscribers[type];
if (!listeners || !listeners.length) return;
this.subscribers[type] = listeners.filter(v => v !== fn);
}
publish(type, ...args) {
let listeners = this.subscribers[type];
if (!listeners || !listeners.length) return;
listeners.forEach(fn => fn(...args));
}
}
let ob = new PubSub();
ob.subscribe('add', (val) => console.log(val));
ob.publish('add', 1);
复制代码
据我了解的大部分前端对这部分知识有些欠缺,甚至抵触,可是,若是突破更高的天花板,这部分知识是必不可少的,并且我亲身经历——很是有用!
参考文章:【递归实现深拷贝】
参考文章:【函数的防抖与节流】
function sleep(time) {
return new Promise((resolve,reject) => setTimeout(resolve, time))
}
sleep(3000).then(() => {console.log('沉睡3000ms')})
复制代码
this
是否为函数,防止 Function.prototype.myCall()
直接调用context
为可选参数,若是不传的话默认上下文为 window
context
建立一个 Symbol
(保证不会重名)属性,将当前函数赋值给这个属性Symbol
属性Function.prototype.myCall = function(context = window, ...args) {
if (this === Function.prototype) {
return undefined; // 用于防止 Function.prototype.myCall() 直接调用
}
context = context || window;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
};
复制代码
apply
实现相似 call
,参数为数组
Function.prototype.myApply = function(context = window, args) {
if (this === Function.prototype) {
return undefined; // 用于防止 Function.prototype.myCall() 直接调用
}
const fn = Symbol();
context[fn] = this;
let result;
if (Array.isArray(args)) {
result = context[fn](...args);
} else {
result = context[fn]();
}
delete context[fn];
return result;
};
复制代码
由于 bind()
返回一个方法需手动执行,所以利用闭包实现。
Function.prototype.myBind = function(context, ...args1) {
if (this === Function.prototype) {
throw new TypeError('Error');
}
const _this = this;
return function F(...args2) {
// 判断是否用于构造函数
if (this instanceof F) {
return new _this(...args1, ...args2);
}
return _this.apply(context, args1.concat(args2));
};
};
复制代码
参考文章:【手动实现 promise】
function EventEmitter() {
this._events = Object.create(null);
}
// 向事件队列添加事件
// prepend为true表示向事件队列头部添加事件
EventEmitter.prototype.addListener = function (type, listener, prepend) {
if (!this._events) {
this._events = Object.create(null);
}
if (this._events[type]) {
if (prepend) {
this._events[type].unshift(listener);
} else {
this._events[type].push(listener);
}
} else {
this._events[type] = [listener];
}
};
// 移除某个事件
EventEmitter.prototype.removeListener = function (type, listener) {
if (Array.isArray(this._events[type])) {
if (!listener) {
delete this._events[type]
} else {
this._events[type] = this._events[type].filter(e => e !== listener && e.origin !== listener)
}
}
};
// 向事件队列添加事件,只执行一次
EventEmitter.prototype.once = function (type, listener) {
const only = (...args) => {
listener.apply(this, args);
this.removeListener(type, listener);
}
only.origin = listener;
this.addListener(type, only);
};
// 执行某类事件
EventEmitter.prototype.emit = function (type, ...args) {
if (Array.isArray(this._events[type])) {
this._events[type].forEach(fn => {
fn.apply(this, args);
});
}
};
// 测试一下
var emitter = new EventEmitter();
var onceListener = function (args) {
console.log('我只能被执行一次', args, this);
}
var listener = function (args) {
console.log('我是一个listener', args, this);
}
emitter.once('click', onceListener);
emitter.addListener('click', listener);
emitter.emit('click', '参数');
emitter.emit('click');
emitter.removeListener('click', listener);
emitter.emit('click');
复制代码
参考文章:【Vue 双向数据绑定原理】
let Myjson = {
parse: function(jsonStr) {
return eval('(' + jsonStr + ')');
},
stringify: function(jsonObj) {
var result = '',
curVal;
if (jsonObj === null) {
return String(jsonObj);
}
switch (typeof jsonObj) {
case 'number':
case 'boolean':
return String(jsonObj);
case 'string':
return '"' + jsonObj + '"';
case 'undefined':
case 'function':
return undefined;
}
switch (Object.prototype.toString.call(jsonObj)) {
case '[object Array]':
result += '[';
for (var i = 0, len = jsonObj.length; i < len; i++) {
curVal = JSON.stringify(jsonObj[i]);
result += (curVal === undefined ? null : curVal) + ",";
}
if (result !== '[') {
result = result.slice(0, -1);
}
result += ']';
return result;
case '[object Date]':
return '"' + (jsonObj.toJSON ? jsonObj.toJSON() : jsonObj.toString()) + '"';
case '[object RegExp]':
return "{}";
case '[object Object]':
result += '{';
for (i in jsonObj) {
if (jsonObj.hasOwnProperty(i)) {
curVal = JSON.stringify(jsonObj[i]);
if (curVal !== undefined) {
result += '"' + i + '":' + curVal + ',';
}
}
}
if (result !== '{') {
result = result.slice(0, -1);
}
result += '}';
return result;
case '[object String]':
return '"' + jsonObj.toString() + '"';
case '[object Number]':
case '[object Boolean]':
return jsonObj.toString();
}
}
};
复制代码
参考文章:【图片懒加载】
参考文章:【输入URL至页面渲染】
现代 JavaScript
教程:zh.javascript.info/
阮一峰的 ECMAScript 6
教程:es6.ruanyifeng.com/
HTML meta
标签总结与属性使用介绍:segmentfault.com/a/119000000…
CSS
编码指导:github.com/chadluo/CSS…
大前端开发者须要了解的基础编译原理和语言知识:fullstack.blog
正则表达式 30 分钟入门教程:deerchao.net/tutorials/r…
用动画的形式呈现解 LeetCode
题目的思路:github.com/MisterBooo/…
JavaScript
数据结构和算法:github.com/ConardLi/aw…
30-seconds-of-code
(里面有不少 js
代码很是巧妙,我正在将它翻译成中文):github.com/ConardLi/30…
《重学前端》中的浏览器原理章节:time.geekbang.org/column/arti…
图解浏览器的基本工做原理:zhuanlan.zhihu.com/p/47407398
七天学会 NodeJS
:github.com/nqdeng/7-da…
Node.js
模块加载与运行原理:efe.baidu.com/blog/nodejs…
TypeScript Handbook
:zhongsp.gitbooks.io/typescript-…
React.js
小书:huziketang.mangojuice.top/books/react…
React
深刻系列:juejin.im/post/5cad39…
Webpack React
小书:fakefish.github.io/react-webpa…
Vue.js
技术揭秘:github.com/ustbhuangyi…
Vuex
在 Vue
中管理状态:sabe.io/tutorials/g…
你须要 Mobx
仍是 Redux
?:juejin.im/post/5a7fd7…
Underscore
源码分析:yoyoyohamapi.gitbooks.io/undersercor…
微信小程序开发资源汇总:github.com/justjavac/a…
腾讯移动 Web
前端知识库:github.com/AlloyTeam/M…
一口(很长的)气了解babel
:zhuanlan.zhihu.com/p/43249121
Webpack
傻瓜式指南:zhuanlan.zhihu.com/p/20367175
Webpack
原理:segmentfault.com/a/119000001…
廖雪峰的 git
教程:www.liaoxuefeng.com/wiki/001373…
前端开发者必备的 Nginx
知识:juejin.im/post/5c85a6…
使用 Jenkins
进行持续集成:www.liaoxuefeng.com/article/001…
常见六大 Web
安全攻防解析:github.com/ljianshu/Bl…
新人如何快速融入技术实力强的前端团队:juejin.im/post/5cb860…
印记中文(各类中文开发文档):www.docschina.org/
前端学习方法:github.com/helloqingfe…
如何在工做内外得到持续的技术成长:juejin.im/post/5cbd74…
优秀的前端博客汇总:github.com/foru17/fron…
冴羽的博客:github.com/mqyqingfeng…
大深海的博客:github.com/chenshenhai…
木易杨的博客: github.com/yygmind/blo…
MuYunyun的博客: github.com/MuYunyun/bl…
互联网术语大全:www.jianshu.com/p/9a7ca206c…
互联网沟通、问答、学习的艺术:zhuanlan.zhihu.com/p/41431775
常常加班至深夜,怎样才能保持身体健康:www.zhihu.com/question/21…
此文章 Markdown 源文件地址:github.com/zxpsuper/bl…