@pspgbhu
2018-11-09T07:11:05.000000Z
字数 12076
阅读 884
Basic
个人感觉 border-box 的设计更合理,尤其是当你需要为一个 width: 100% 的盒子添加一个内边距的时候,border-box 的优势就显示了出来。
flex: flex-grow flex-shrink flex-basis
flex: 1; === 1 1 0%
flex: auto; === 1 1 auto
flex: none; === 0 0 auto
{ width: 100%; padding-bottom: 100%}
Box 是 CSS 布局的基本单位,直观的来说一个页面是由很多不同的 Box 组成的,不同类型的 Box 会参与不同的 Formatting Context,因此 Box 内的元素会以不同的方式来渲染
它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素将如何定位,以及和其他元素的相互作用。
CSS2.1 中只有 BFC 和 IFC,CSS3 中添加了 GFC, FFC
布局规则
@media (-webkit-min-device-pixel-ratio: 2) {
div {
border-width: 0.5px
}
}
<div onclick="clickHandle">
document.querySelector('#target').onclick = function() {
}
var el = document.querySelector('#target');
el.addEventListener('click', handleFn);
同一元素绑定多次事件
是浏览器用于定时循环的一个接口,主要用途是按帧对网页进行重绘。
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
console.log('hidden')
} else {
console.log('shown')
}
})
IE 9
HTTP 报文分为三个部分:请求行,请求头,请求体
结构如下:
<method> <request-url> <version>
<headers>
<body>
统一资源标识符 URI (Uniform Resource Identifier) 用于标识互联网上资源地址。
Restful API 风格下的 HTTP 最基本的四种请求方式
关于 POST 和 PUT 的创建资源的不同:
HTTP 响应报文和 HTTP 请求报文相似,是由状态行,响应头,响应体组成的。
注意:TCP 并不能保证数据一定会被对方接收到,因为这是不可能的。TCP 能够做到的是,如果有可能,就把数据递送到接收方,否则就(通过放弃重传并且中断连接这一手段)通知用户。因此准确说 TCP 也不是 100% 可靠的协议,它所能提供的是数据的可靠递送或故障的可靠通知。
三次握手目的是连接服务器端指定窗口,建立 TCP 连接
第一次握手 (SYN=1, seq=x)
客户端发出一个 TCP 的 SYN 标置位 1 的包,指明连接的端口号。以及初始序号 ISN(Initial Sequence Number ) x。
发送完毕后,客户端进入 SYN_SEND
第二次握手 (SYN=1, ACK=1, seq=y, ACKnum=x+1)
服务端发回确认包 (ACK) 应答,即 SYN 和 ACK 的标志位都为 1,服务端选择自己的 ISN 序列号放到 seq 域里面,同时将确认序列号(Acknowledgement Number)设置为客户端的 ISN + 1 即 x + 1。
发送完毕后,服务端进入 SYN_RCVD
状态
第三次握手(ACK=1, ACKnum=y+1)
客户端再次发送确认包 (ACK),SYN 的标置位 0,ACK 的标志位为 1,同时将确认序列号设置为服务端的 ISN + 1,即 y + 1。
发送完毕后,客户端进入 ESTABLISHED
状态,服务端收到这个包后,也进入 ESTABLISHED
状态。
中断 TCP 连接需要经过四次挥手,客户端或服务器均可主动发起挥手动作
第一次挥手(FIN=1, seq=x)
假设是客户端先发起挥手,客户端发出 FIN 包表示自己已经没有数据可以传输了,但还是可以接受数据。
客户端进入 FIN_WAIT_1
状态
第二次挥手 (ACK=1, ACKnum=x+1)
服务端发出 ACK 包作为应答,表明自己收到了客户端发起关闭连接的请求,但还没有做好关闭连接的准备。
发送完毕后,服务端进入 COLSE_WAIT
状态,客户端接收到确认包后,进入到 FIN_WAIT_2
状态,等待服务端关闭连接。
第三次挥手 (FIN=1, seq=y)
服务端做好关闭连接的准备时,向客户端发送结束连接请求,并将 FIN 置为 1。
发送完毕后服务端进入 LAST_ACK
状态,等待来自客户端的最后一次 ACK
第四次挥手 (ACK=1, ACKnum=y+1)
客户端接收到来自服务端的关闭请求后,发出最后一个 ACK 包,并进入 TIME_WAIT
,等待可能出现的要求重传的 ACK 包。
服务端接受到这个请求后,关闭连接,进入 CLOSED
状态。
客户端等待了某个固定的时间 (两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务端的 ACK,认为服务端已经正常关闭,于是自己也关闭连接,并进入 CLOSED
状态。
它不同于 HTTP 的 keep-alive,TCP 连接建立之后,连接的双方并不知道彼此是否还存活着,在一方掉线后,另一方却还维持着 TCP 连接。为了避免这种情况,当超过一定的时间没有发送数据后,TCP 会自动发送一个数据为空的报文给对方,来探测对方的是否存活,如果连续发送多次后都没有回应,则认为连接丢失,没有必要保持连接。
HTTP + SSL = HTTPS
先建立 SSL 通信,SSL 建立成功的基础上再建立 HTTP 协议。
建立通讯的时候,采用公开秘钥加密(非对称加密),通讯建立成功后采用共享秘钥加密(对称加密)。因为非对称加密成本大,因此 HTTPS 采用这种混合加密的形式。
为了保证在建立连接时,客户端使用的公钥就是服务器发送出去的公钥,而非被中间人替换过的,因此引进了证书机制来验证公钥的合法性。
跨站脚本攻击(Cross Site Scripting)
欺骗用户在浏览器上访问一个自己曾经认证过的网站并执行一些操作。
例子
假如一家银行用以执行转账操作的URL地址如下:
http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName
那么,一个恶意攻击者可以在另一个网站上放置如下代码:
<img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">
如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。
这种恶意的网址可以有很多种形式,藏身于网页中的许多地方。此外,攻击者也不需要控制放置恶意网址的网站。例如他可以将这种地址藏在论坛,博客等任何用户生成内容的网站中。这意味着如果服务器端没有合适的防御措施的话,用户即使访问熟悉的可信网站也有受攻击的危险。
透过例子能够看出,攻击者并不能通过CSRF攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息。他们能做到的,是欺骗用户浏览器,让其以用户的名义执行操作。
防御:
webpack 的热更新
使用 webpack-dev-server 开发项目
devtool: 'inline-source-map',
devServer: {
hot: true
},
loader 的原理无非就是输入与输出
// base loader
module.exports = function(source) {
return source;
};
loader 之前可以链式处理,但还是要求 loader 之间彼此独立。
因为 babel 实现一些最新的语法往往需要一些工具函数,不使用 transform-runtime 的话,babel 会在每一个使用新语法的地方生成对应的工具函数,而 transform-runtime 就统一的提供了这些公用的工具函数,而再遇见新语法的地方,直接引用这些工具函数就可以了,这样可以起到减小文件体积的作用。
任何人都可以向标准委员会(又称 TC39 委员会)提案,要求修改语言标准。
一种新的语法从提案到变成正式标准,需要经历五个阶段。每个阶段的变动都需要由 TC39 委员会批准。
一个提案只要能进入 Stage 2,就差不多肯定会包括在以后的正式标准里面。ECMAScript 当前的所有提案,可以在 TC39 的官方网站
module.exports = {
resolve: {
extensions: ['.js', '.vue', '.json'],
modules: [
resolve('src'),
resolve('node_modules')
],
alias: {
'vue$': 'vue/dist/vue.common.js',
'src': resolve('src'),
'assets': resolve('src/assets'),
'components': resolve('src/components'),
// ...
'store': resolve('src/store')
}
},
}
同域, 同协议, 同端口.
JSONP:
利用了 script 标签 src 属性没有跨域的限制,地址指向API地址,并提供一个回调函数名来接受数据,浏览器会返回一个执行包含json数据的回调函数的脚本。
JSONP只能满足GET请求
图片ping
只能get,同时不能收取数据
CORS
跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。
概念非常简单,就是某个函数的最后一步是对另一个函数的调用。
function f(x) {
return g(x);
}
以下的情况不属于尾调用
// 情况一
function f(x){
let y = g(x);
return y;
}
// 情况二
function f(x){
return g(x) + 1;
}
函数中调用函数,会保留所有的调用记录,形成一个调用栈。
尾调用由于是函数的最后一步,调用位置,内部变量等信息都不会再用到了,直接使用内层的调用记录取代外层的调用记录就可以了。
function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
尾调用对递归非常重要,如果不适用尾调用,就会导致所有的调用记录都被保存,有可能造成栈溢出。
ES6的尾调用优化只在严格模式下开启,正常模式是无效的。
这是因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈。
尾调用优化发生时,函数的调用栈会改写,因此上面两个变量就会失真。严格模式禁用这两个变量,所以尾调用模式仅在严格模式下生效。
Node.js Event Loop:
setTimeout
每一轮事件循环都会检查 setTimeout 是否到时,到时则回调函数会被调用
process.nextTick
会将其回调函数放入队列,在下一轮的 tick 中被消费。如果只是用 setTimeout 来进行异步执行的话,nextTick 则更高效
setImmediate(浏览器端暂未实现)
回调会放置在一个链表中,每一轮 tick 只调用链表中的一个回调,这样能保证每一轮 tick 能较快的结束,防止 CPU 占用过多影响后面的 I/O 操作
调用顺序 nextTick > promise > setTimeout > Immeditate
async 本质上还是可以理解为 promise。
async function async1() {
console.log("a");
await async2(); //执行这一句后,await会让出当前线程,将后面的代码加到任务队列中,然后继续执行函数后面的同步代码
console.log("b");
}
async function async2() {
console.log( 'c');
}
console.log("d");
setTimeout(function () {
console.log("e");
},0);
async1();
new Promise(function (resolve) {
console.log("f");
resolve();
}).then(function () {
console.log("g");
});
console.log('h');
macrotask 和 microtask,这表示异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。
setTimeout(function() {
console.log('timeout1');
Promise.resolve().then(() => {
console.log('promise1');
});
});
setTimeout(function() {
console.log('timeout2');
Promise.resolve().then(() => {
console.log('promise2');
});
});
Promise.resolve().then(() => console.log('promise3'));
Promise.resolve().then(() => console.log('promise4'));
var fn = target.bind(ctx);
if (!Function.prototype.bind) {
Function.prototype.bind = function() {
if (typeof this !== 'function') {
throw new Error();
}
var fn = this;
var ctx = arguments[0];
var args = [].slice.call(arguments, 1);
var fNOP = function() {};
var fBound = function() {
// this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
var context = this instanceof fBound
? this
: ctx;
return fn.apply(context, args.concat([].slice.call(arguments)));
}
// 维护原型关系
if (this.prototype) {
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
}
}
将原型链和借用构造函数的技术组合在一起,从而发挥二者长处的一种继承模式
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() {
alert(this.name);
}
function SubType(name, age) {
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
但是,这里调用了两次超类的构造函数
function object(o) {
function F() {};
F.prototype = o;
return new F();
}
var person = {
name: 'hc';
friends: ['a', 'b']
}
var anotherPerson = object(person);
anotherPerson.name = 'zz';
object 方法将传入的 o 对象变成了新实例的原型对象。并且所有使用 o 和 object 创建出来的对象都将共享一个原型对象。
ES5 新增了 Object.create()
方法规范化了原型式继承。Object.create 接受两个参数,第一个参数是用作新对象的原型对象,第二个参数是一个为新对象定义额外属性的对象。当只传入第一个参数时,其作用于上面的 object 方法相同。
function createAnother (original) {
var clone = object(original); // Object.create
clone.sayHi = function() {
alert('hi');
}
return clone;
}
function SuperType(name) {
this.name = name
}
SuperType.prototype.sayName = function() {
alert(this.name);
}
function SubType(name, age) {
Super.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType) // 继承原型
SubType.prototype.sayAge = function() {}
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype) // 创建对象
prototype.constructor = subType; // 增强对象
subType.prototype = prototype; // 指定对象
}
[...new Set(arr)]
// or
Array.from(new Set(arr))
[arr].filter((item, index, array) => index === array.indexOf(item));
3.
function quchong(arr) {
var rst = [];
for (var i = 0; i < arr.length; i ++) {
var repeat = false;
for (var j = 0; j < rst.length; i ++) {
if (arr[i] === rst[j]) {
repeat = true;
break;
}
}
if (!repeat) {
rst.push(arr[i]);
continue;
}
}
return rst;
}
仅可遍历对象可用
CommonJS: Node 采用的是 CommonJS 模块规范
加载模块是同步的,所以只有加载完成才能执行后面的操作
AMD:加载是异步的
//c.js 依赖a.js b.js
define(['a', 'b'], function(a, b) {
....
});
AMD规范允许输出模块兼容CommonJS规范,这时define方法如下
define(function (require, exports, module) {
var reqModule = require("./a.js");
requModule.mix();
exports.asplode = function () {
...
}
});
CMD规范
对于依赖的模块AMD是提前执行,CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行(根据写法不同,处理方式不通过)
CMD推崇依赖就近,AMD推崇依赖前置
//AMD写法
define(['./a','./b'], function (a, b) {
//依赖一开始就写好
a.mix();
b.show();
});
//CMD写法
define(function (requie, exports, module) {
//依赖可以就近书写
var a = require('./a');
a.mix();
if (...) {
var b = requie('./b');
b.show();
}
});
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS-like
module.exports = factory(require('jquery'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// methods
function myFunc(){};
// exposed public method
return myFunc;
}));
应用UMD规范的js文件其实就是一个立即执行函数。函数有两个参数,第一个参数是当前运行时环境,第二个参数是模块的定义体。在执行UMD规范时,会优先判断是当前环境是否支持AMD环境,然后再检验是否支持CommonJS环境,否则认为当前环境为浏览器环境( window )
比如百度的一个服务不想让京东用,如果识别是京东的请求就会跳转到404或者其他,如何解决?