0%

同步加载、异步加载、延迟加载和预加载

同步加载

默认的是同步加载

1
<script src="http://yourdomain.com/script.js"></script>

同步模式又称阻塞模式,会阻止浏览器的后续操作,相当于阻止了后续的文件的解析,执行等。

流览器之所以会采用同步模式,是因为加载的js文件中有对dom的操作,重定向,输出document等默认行为,所以同步才是最安全的。

通常加载js文件或者放<script>标签都在结构最后面,也是因为它会阻止浏览器后续操作的原因,所以放在后面,当页面结构和样式全部渲染完成再执行js,提升用户体验

阅读全文 »

SVG Path 属性

<path> 标签

<path> 标签用来定义路径。

path元素的形状是通过属性d定义的,属性d的值是一个“命令+参数”的序列。字符结束后,解析器就会去读下一段命令。每一个命令都有两种表示方式,一种是用大写字母,表示采用绝对定位。另一种是用小写字母,表示采用相对定位(例如:从上一个点开始,向上移动10px,向左移动7px)。

因为属性d采用的是用户坐标系统,所以不需标明单位。

阅读全文 »

简介

对于是盒子的元素,如果没有特殊设置,其默认总是占独立的一行,宽度为浏览器窗口的宽度,在其前后的元素不管是不是盒子,都只能排列在它的上面或者下面,即上下累加着进行排列。HTML文档中的每个盒子都可以看成是由从内到外的四个部分构成,即内容区(content)、填充(padding)、边框(border)和空白边(margin)。 CSS 为四个部分定义了一系列相关属性,通过对这些属性的设置可以丰富盒子的表现效果。

阅读全文 »

墨卡托投影坐标系(Mercator Projection)

墨卡托投影是一种“等角正切圆柱投影”,荷兰地图学家墨卡托(Mercator)在1569年拟定:假设地球被围在一个中空的圆柱里,其赤道与圆柱相接触,然后再假想地球中心有一盏灯,把球面上的图形投影到圆柱体上,再把圆柱体展开,这就是一幅标准纬线为零度(即赤道)的“墨卡托投影”绘制出的世界地图。
  墨卡托投影在今天对于航海事业起着极为重要的作用,目前世界各国绘制海洋地图时仍广泛使用墨卡托投影,国际水路局(IHB)规定:“除特殊情况外,各国都要用墨卡托投影绘制海图”。国际水路局发行的《大洋水深总图》是把全世界分成24幅编辑的,在南北纬72度之间就是使用墨卡托投影绘成的。

投影原理

用一个平面包围成圆柱体,正好与地球相接,地球近似成正球体处理。从球内打射线,跟球面和圆柱面都有唯一的交点。如下图,从球内放置灯光,光线向外,跟球面交点为P,与外接圆柱面的交点为P1,P的经纬度分别为λ,φ。

反畸变处理

转换算法

设地球表面A点经纬坐标为(λ,Φ),对应的投影坐标为(x,y),基准纬线设置为赤道,则R为地球半径;墨卡托投影方程式为:

参考 & 引用

https://www.cnblogs.com/DHUtoBUAA/p/6706642.html
https://blog.csdn.net/xiliuhu/article/details/52075408

babel入门

本文主要内容

一些babel基础知识、一个可工作的极简babel案例、一个简单的babel插件案例、以及对应的资源。

babel是什么

**本质上:**babel是一个JavaScript的编译器,输入一些code将这些code进行编译,输出一些code。
**主要工作:**将ES2015及更新版本解析成浏览器可执行的低版本代码,将jsx等自定义的编码规范解析成浏览器通用的代码。
**原理:**babel 利用 babylon 解析器进行语法解析。解析成 AST(抽象语法树)后,经过一定的规则对这个树进行处理后再生成新的语法树。最终新的语法树在生成对应的合法的 Javascript 语法。

阅读全文 »

ReactHook

简略记录版,本文仅提供一些基础内容作为学习和回忆之用,入门学习请查看React Hook官方文档

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

阅读全文 »

层包(Pack)

图使用嵌套来表示层次结构。最里层表示叶节点的圆的大小用来编码定量的维度值。每个圆都表示当前节点的近似累计大小,因为有空间浪费以及变形;仅仅只有叶节点可以准确的比较。尽管 circle packing 不能高效的利用空间,但是能更突出的表示层次结构。

该模块利用层级布局的数据进行包布局[坐标计算](# 核心代码)。为层级布局数据添加[布局信息](# 布局信息)用于绘制图形。以及一些内置[API](# API)来设置或获取一些参数来辅助图形的坐标计算。

阅读全文 »

层级布局(Hierarchy)

一个好的层次结构可视化能促进快速的促进多尺度推理: 对单个单元的微观观察和对整体的宏观观察.

许多数据集从从本质上是嵌套结构的。例如一个[族谱结构](# 族谱结构)。
该模块实现了对层级结构的[基础数据计算](# 基础数据计算)。

该模块构建了一个[新的结构](# Node节点)来存储层级结构的一些[基本数据](# 基本数据)。以及一些[内置方法](# 内置方法)来进行层级间的计算。

阅读全文 »

哈希表(HashTable)

定义

哈希表是基于键值对的一种数据存储结构,key值不可以重复,value可以重复,后面添加的重复的key值的时候,会把之前key值对应的value给覆盖掉,JavaScript中的对象具有天然的哈希特性

哈希表的常用方法:

  • put(key, value):向哈希映射中插入(键,值)的数值对。如果键对应的值已经存在,更新这个值。
  • get(key):返回给定的键所对应的值,如果映射中不包含这个键,返回 undefined。
  • remove(key):如果映射中存在这个键,删除这个数值对。

设计

hash表的实现普遍基于数组,将给出key值映射到一个数组的一个地址,这里用一个hash函数来解决映射问题,hash函数存在两个问题,一个是性能问题,在大规模写入和查询时每次都会用到hash函数,另一个是冲突问题,key值可能是无限的,数组空间是有限的必然会出现多个key值对应同一个地址的情况,称为hash冲突。我们来看一个简单的hashTable设计。

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
function HashTable () {
this.table = new Array(137);
this.simpleHash = simpleHash;
this.showAll = showAll;
this.put = put;
// this.get = get; 后面添加get
}

function simpleHash (data) {
var total = 0;
for (var i = 0; i < data.length; i++) {
// 获取 并 累加 key值 字符串中的每一个字符的 unicode 值
total += data.charCodeAt(i);
}

// 对 数组长度 取余 映射到数组长度范围内
return total % this.table.length;
}

function put (key, data) {
var pos = this.simpleHash(key);
this.table[pos] = data;
}

function showAll () {
var n = 0;
for (var i = 0; i < this.table.length; i++) {
if (this.table[i] != undefined) {
console.log(i + ': ' + this.table[i]);
}
}
}

运行一下代码测试:

1
2
3
4
5
6
const hash = new HashTable();
hash.put("Preshine","Preshine"),
hash.put("Clayton","Clayton"),
hash.showAll()// 8: Preshine 45: Clayton
hash.put("Raymond","Raymond"),
hash.showAll()// 8: Preshine 45: Raymond

这里发现 我往哈希表中put了两个不同的key值 ‘Clayton’和’Raymond’,但这时候后者把前者的值给覆盖了,而且在数组中的存储坐标也一致,说明发生了哈希碰撞。

下面我们就稍微改进下散列函数:

1
2
3
4
5
6
7
8
9
10
function betterHash (str, arr) {
var H = 37;
var total = 0;
for (var i = 0; i < str.length; i++) {
total += H * total + str.chatCodeAt(i);
}
total = total % arr.length;

return parseInt(total);
}

为了避免碰撞,首先要确保散列表中用来存储数据的数组其大小是个质数。这一点很关键,这和计算散列值时使用的取余运算有关。

这里定义了一个常量 H = 37;  这个质数37是一个比较好的数字适合我们的哈希算法来参与哈希键值运算,并且使生成的键值在哈希表中均匀分布。
并且加一个 get方法:

应用新的散列键值函数后 就没有发生 碰撞了。

1
2
3
4
5
const hash = new HashTable();
hash.put("Preshine","Preshine");
hash.put("Clayton","Clayton");
hash.put("Raymond","Raymond");
hash.showAll()// 22: Preshine 58: Clayton 99: Raymond

即使再高效的散列键值生成函数也是有可能发生碰撞了,处理碰撞方法有很多中,这里我介绍2种方法。

开链法

当碰撞发生时,我们仍然希望将键存储到通过散列算法产生的索引位置上,但实际上,不可能将多份数据存储到一个数组单元中。开链法是指实现散列表的底层数组中,每个数组元素又是一个新的数据结构,比如另一个数组,这样就能存储多个键了。即使两个键散列后的值相等,依然被保存在同样的位置,只不过它们在第二层数组中的位置不一样罢了,如图:

首先要初始化一下HashTable的数据存储结构:

1
2
3
4
5
function buildchains () {
for (var i = 0; i < this.table.length; i++) {
this.table[i] = [];
}
}

下面给出put和get方法的代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function put (key, data) {
var pos = this.betterHash(key);
var index = 0;
if (!this.table[pos][index]) {
this.table[pos][index] = key;
this.table[pos][index + 1] = data;
} else {
index++;
while (this.table[pos][index]) {
index++;
}
this.table[pos][index] = key;
this.table[pos][index + 1] = data;

}
}

put的时候先算出哈希键值,然后在哈希表中查看是否有重复的哈希键值,如果没有重复的,则把值放入该位置,这时候数据是占用了数组的2个位置,是把key值存放之后,立即把值紧跟着存在后面;如果哈希键值有重复,则寻找到当前哈希键所在的哈希表的位置,然后在当前位置的数组中找到还没有利用的空间,然后把key值和value一起连续存储(其实就是JS数组的push()操作-_ - )。
这里的二维数组存储类似于一维数组中每个元素都是一个链表,Java中的HashTable类就是这样的存储结构。

get的时候就很简单了,就是一个把put过程取反的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

function get (key) {
var pos = this.betterHash(key);
var index = 0;
if (this.table[pos][index] === key) {
return this.table[pos][index + 1];
} else {
index += 2;
while (this.table[pos][index]) {
index++;
}
this.table[pos][index] = key;
this.table[pos][index + 1] = data;

}
}

2.线性探测法
线性探测法属于一种更一般化的散列技术:开发寻址散列。当发生碰撞时,线性探测发检测散列表中的下一个位置是否为空。如果为空,就将数据存入该位置;如果不为空,则继续检查下一个位置,直到找到一个空的位置为止。该技术是基于这样一个事实:每个散列表都会有很多空的单元格,可以使用它们来存储数据。

如果数组的大小是待存储数据个数的1.5倍,那么使用开链法;如果数组的大小是待存储的数据的2倍及两倍以上,那么使用线性探测法。

采用线性探测法的时候,先给HashTable类初始化一个存储值的数组values = []; 存储键值使用table = [];

1
2
3
4
...
this.values = [];
...

上面分析了怎么存储数据之后,我们来重写下put和get方法:

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
function put (key, data) {
var pos = this.betterHash(key);
if (!this.table[pos]) {
this.table[pos] = key;
this.values[pos] = data;
} else {
while (this.table[pos]) {
pos++;
}
this.table[pos] = key;
this.values[pos] = data;
}
}

function get (key) {
var pos = -1;
pos = this.betterHash(key);
if (pos > -1) {
for (var i = pos; this.table[pos]; i++) {
if (this.table[pos] === key) {
return this.values[pos];
}
}
}

return undefined;
}

照着前面的思路把数组给存进去之后,在拿的时候,只需要算出键的哈希值,在table中从pos坐标开始遍历,找到存储key值的坐标后直接用当前return values[pos];就拿到存入的数据了。

最后要注意哈希表哈希算法的计算复杂度和计算时间,哈希函数也正是哈希表的精髓所在。基于key-value数据结构存储的应用非常广泛,因为使用它非常方便,效率和很高,常见的有很多基于key-value存储的应用,比如redis数据库等。

实现

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
function HashTable() {
this.hashKey = 33;
this.hashLength = 137;
this.key = new Array(this.hashLength);
this.value = new Array(this.hashLength);
}
HashTable.prototype._showAll = function() {
for (let i = 0; i < this.hashLength; i++) {
if (this.key[i] !== undefined) {
console.log(`${i} ${this.key[i]}:${this.value[i]}`);
}
}
};
HashTable.prototype.hash = function(key) {
var index = 0;
for (var i = 0; i < key.length; i++) {
index += this.hashKey * index + key[i].charCodeAt();
}
index = index % this.value.length;
return parseInt(index);
};
HashTable.prototype.get = function(key) {
let index = this.hash(key);
while (this.key[index] !== undefined && this.key[index] !== key) index++;
return this.value[index];
};
HashTable.prototype.set = function(key, value) {
let index = this.hash(key);
while (this.key[index] !== undefined) index++;
this.key[index] = key;
this.value[index] = value;
};
HashTable.prototype.remove = function(key) {
let index = this.hash(key);
while (this.key[index] !== key) index++;
this.key[index] = undefined;
this.value[index] = undefined;
};

应用

由于js对象自带hash特性 而且hash应用其实非常多 这里就不特别举例了。

705. 设计哈希集合

参考 & 引用

https://blog.csdn.net/PingZhi_6766/article/details/78025313

基本数据结构

回顾一波基本数据结构,做个整理。

目录

[队列](# 队列(queue))
[栈](# 栈(Stack))
[链表](# 链表(List))
[堆](# 堆(Heap))

阅读全文 »