package.json的字段说明
英文版的package.json介绍
https://heynode.com/tutorial/what-packagejson/
namename字段表示当前的文件名字,如果需要发布在npm上的话,作为唯一的标识。
versionversion当前项目的版本,决定了该版本的所有依赖的版本。
licenselicense许可证,发布在npm的时候,许可证规定哪些人可以使用,哪些人不可以使用。
author和contributors"author": "Jon Church jon@example.com https://www.osioslabs.com/#team",
"contributors": [{
"name": "Amber Matz",
"email": "example@example.com",
"url": "https://www.osiolabs.com/#team"
}]
作者和共享者,拥有name 、 email、 url字段。
description发布在npm上的时候对该包的描述说明。
keywords作用跟description差不多,就 ...
Nginx反向代理
正向代理和反向代理
正向代理
就是正常的客户端和服务端之间利用一部代理服务器来进行转发数据和缓存。但是这样有一个问题,就是服务端不知道请求是来自哪里?只有客户端知道。
反向代理
反向代理可以解决上述问题,服务器部分包括用于做反向代理的服务器和业务服务器,这样业务服务器就可以知道请求是来自代理服务器的,但是客户端不知道响应是来自哪里。
nginx解决跨域的原理例如:
前端server的域名为:fe.server.com
后端服务的域名为:dev.server.com
现在我在fe.server.com对dev.server.com发起请求一定会出现跨域。
现在我们只需要启动一个nginx服务器,将server_name设置为fe.server.com,然后设置相应的location以拦截前端需要跨域的请求,最后将请求代理回dev.server.com。如下面的配置:
server {
listen 80;
server_name fe.server.com;
location / {
...
HashMap
HashMap的作用HashMap哈希表,也叫做散列表。哈希表是一种比较特殊的数据结构,它遵循函数映射的思想,以Key: Value的方式存储数据。哈希表最大的特点是可以快速定位到要查找的数据,查询的时间复杂度接近O(1)。哈希表的原理并不复杂,简而言之就是根据Key来计算出存储位置,然后将数据放入该空间,查询时同样根据Key计算出存储位置后直接将相应的值取出。
哈希函数根据Key来计算存储位置的计算规则我们称之为哈希函数。优化哈希表的关键就是表大小和哈希函数的选择。
常用的哈希函数
除留取余法
这种方法应该是最常用的哈希定址方法了。H(x) = x % p假定哈希表长度为s,则p一般取不超过s的最大质数
直接定址法比较常用的方法H(x) = a * x + b
冲突哈希表还要解决的一个问题就是冲突,当选择了一个哈希函数之后,有可能不同的数据会计算出相同的key,比如H(x) = x % 5 这种算法,6 和 11 都会计算出1,此时就会产生冲突。如果不解决冲突,哈希表就无法构建出来。
解决冲突的方法
链接地址法将有冲突的数据放在一个链表里,当查询时会根据key查到链表的第一 ...
前端路由
前端路由的两个基本条件
改变url
页面不刷新
Hash 路由
hash只作用在浏览器,不会在请求中发送给服务器。
hash发生变化时,浏览器并不会重新给后端发送请求加载页面。
修改hash时会在浏览器留下历史记录,可以通过浏览器返回按钮回到上一个页面。
hash 发生变化时会触发 hashchange 事件,在该事件中可以通过 window.location.hash 获取到当前 hash 值。
在添加路由的时候添加一个对象,包括url和跳转该地址的处理函数。hashchange 事件可以监听url的变化。
History 路由利用H5的history.pushState()和history.replaceState(),分别可以添加和修改历史记录。它们是与 hash 一样具有修改url的功能,之后可以通过windows的onpopstate事件,来监听url的变化,进而处理该url的处理函数。
因为History路由改变的是浏览器的url,因为url改变了,此时如果手动的刷新页面,浏览器会认为是请求一个新的页面,但是新的页面是不存在的(因为url中显示的是通过pushst ...
尾调用
尾调用
尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。
需要注意的是最后一步不是指最后一行代码,甚至return fn() - 1,即使在同一行,也不是尾调用。
function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
上面代码中,如果函数g不是尾调用,函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后,函数f就结束了,所以执行到最后一步,完全可以删除f()的调用记录,只保留g(3)的调用记录。
这就叫做”尾调用优化”(Tail call optimization),即只保留内层函数的调用记录。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是”尾调用优化”的意义。
尾递归
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
递归非常耗费内存,因为需要同时保存成千上百个调用记录,很容易 ...
HTTP
传输流程
三次握手目的是为了保证客户端和服务端各自的可分发,就是为了确保对方是否确认收到,连接是否成功,也就是为啥TCP是可靠的连接
简要的说明就是利用TCP的标志SYN和ACK。发送端首先发送一个带SYN标志的数据包给对方。接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息。最后,发送端再回传一个带ACK标志的数据包,代表“握手”结束。若在握手过程中某个阶段莫名断。TCP 协议会再次以相同的顺序发送相同的数据包。
http无状态保存http协议自身不具备保存之前发送的请求和响应的功能。如果为了实现保存状态的功能,可以利用cookie技术,cookie与http配合,就可以管理状态了。
URL和URIURL统一资源定定位符,也就是在浏览器中输入的地址,URI统一资源标识符,用来标识服务器中具体的某一个资源,也就是请求体内容。URI包含URL
HEADHEAD方法和GET方法一样,只是不返回报文主体部分。用于确认URI的有效性及资源更新的日期时间等。
DELETEDELETE 方法用来删除文件,是与PUT相反的方法(上传文件)。DELETE方法按请求URI删除指定的 ...
JS中一些深入概念
原型原型对象(Person.prototype) 是通过Object构造函数生成的,而实例的__proto__指向构造函数的prototype。这就是为啥原型链中最后指向的是Object。null代表没有对象,也就是null在此处表明无原型。蓝色的线就是所谓的原型链
注意
constructor
function Person() {
}
var person = new Person();
console.log(person.constructor === Person); // true
当获取 person.constructor 时,其实 person 中并没有constructor属性,当不能读取到constructor 属性时,会从 person的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:
person.constructor === Person.prototype.constructor
__proto__
绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上 ...
防抖
防抖
你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,我才执行
解决两个问题:
this的指向
event对象
var count = 1;
var container = document.getElementById('container');
function getUserAction(e) {
console.log(e)
container.innerHTML = count++;
//console.log(this) // 此时的this指向的window,本来应该是<div id="container"></div>
};
// container.onmousemove = getUserAction;
container.onmousemove = debounce(getUserAction,1000)
function debounce(func,wai ...
call/apply/bind/new模拟实现
call的模拟实现模拟思路
call改变了this的指向,指向到foo
bar函数执行了
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
上面可以用类似逻辑实现
将函数设置为对象的属性
执行该函数
删除该属性(函数)
Function.prototype.call2 = function(context) {
// 首先要获取调用call的函数,用this可以获取,就是foo函数
context.fn = this;
context.fn();
delete context.fn;
}
// 测试一下
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call2(foo); // 1
最终版本
加了三个东西:
参数
this参数可以传null, 此时指向的是window
函数可以有返回 ...
设计模式之单例模式
介绍单例就是保证一个类只有一个实例,实例的方法一般先判断实例是否存在,如果存在直接返回出来,如果不存在就先创建了再返回出来。这就可以保证一个类只有一个实例。在JS中,单例是一个命名空间的提供者,从命名空间里提供唯一的访问点来访问该对象。
实现方式单例一般用在系统间各种模式的通信协调上,下面代码是单例的实践
let Single = (function(){
// 参数:传递给单例一个参数集合
function Signleton(args){
let args = args || {}
this.name = 'Signle'
this.pointX = args.pointX || 6
this.pointY = args.pointY || 10
}
let instance // 实例容器
let _static = {
name:'Signle',
// 获取实例的方法
// 返回Signleton实例
getInstanc ...