算法
单向链表
interface Node {
element: any;
next: any;
}
class LinkedList {
private length: number = 0;
private list: any = null;
getNode(element: any): Node {
return {
element,
next: null
}
}
append(element: any) {
const node = this.getNode(element);
if (!this.list) {
this.list = node;
} else {
let current = this.list
while (current.next) {
current = current.next;
}
current.next = node;
}
++this.length;
}
insert(position: number, element: any) {
let current = this.list;
let node = this.getNode(element);
if (this.length > position && position >= 0) {
if (position === 0) {
node.next = current;
this.list = node;
} else {
for (let i = 1; i < position; i++) {
current = current.next
}
node.next = current.next;
current.next = node;
}
++this.length
} else {
this.append(element);
}
}
removeAt(position: number) {
if (this.length > position && position >= 0) {
if (position === 0) {
this.list = this.list.next;
} else {
let current = this.list;
for (let i = 1; i < position; i++) {
current = current.next;
}
current.next = current.next.next;
}
--this.length
}
}
remove(element: any) {
this.removeAt(this.indexOf(element))
}
indexOf(element: any): number {
let index = -1;
let current = this.list;
for (let i = 0; i < this.length; i++) {
if (current.element === element) {
return i
}
current = current.next;
}
return -1
}
isEmpty(): boolean {
return this.length === 0;
}
size(): number {
return this.length;
}
getHead() {
return this.list;
}
toString(): string {
var string: string = '',
current = this.list;
if(current){
string += current.element;
while(current.next){
current = current.next;
string += current.element;
}
}
return string;
}
print() {
console.log(this.toString())
}
}
var linkedList = new LinkedList();
linkedList.print();
linkedList.append(1);
linkedList.print();
linkedList.append(2);
linkedList.print();
linkedList.append(3);
linkedList.print();
linkedList.append(5);
linkedList.print();
linkedList.insert(3, 4);
linkedList.print();
console.log(linkedList.indexOf(4));
linkedList.remove(4);
linkedList.print();
linkedList.removeAt(3);
linkedList.print();
console.log(linkedList.size());
linkedList.getHead();
双向链表
interface Node {
element: any;
next: any;
prev: any;
}
class LinkedList {
private length: number = 0;
private list: any = null;
getNode(element: any): Node {
return {
element,
next: null,
prev: null
}
}
append(element: any) {
const node = this.getNode(element);
if (!this.list) {
this.list = node;
} else {
let current = this.list
while (current.next) {
current = current.next;
}
current.next = node;
node.prev = current;
}
++this.length;
}
insert(position: number, element: any) {
let current = this.list;
let node = this.getNode(element);
if (this.length > position && position >= 0) {
if (position === 0) {
node.next = current;
this.list = node;
} else {
for (let i = 1; i < position; i++) {
current = current.next;
}
current.next.prev = node;
node.next = current.next;
current.next = node;
node.prev = current;
}
++this.length
} else {
this.append(element);
}
}
removeAt(position: number) {
if (this.length > position && position >= 0) {
if (position === 0) {
this.list = this.list.next;
} else {
let current = this.list;
for (let i = 1; i < position; i++) {
current = current.next;
}
if(current.next && current.next.next){
current.next.next.prev = current;
current.next = current.next.next;
}else if(current.next && !current.next.next){
current.next = null;
}
}
--this.length
}
}
remove(element: any) {
this.removeAt(this.indexOf(element))
}
indexOf(element: any): number {
let index = -1;
let current = this.list;
for (let i = 0; i < this.length; i++) {
if (current.element === element) {
return i
}
current = current.next;
}
return -1
}
isEmpty(): boolean {
return this.length === 0;
}
size(): number {
return this.length;
}
getHead() {
return this.list;
}
toString(): string {
var string: string = '',
current = this.list;
if(current){
string += current.element;
while(current.next){
current = current.next;
string += current.element;
}
}
return string;
}
print() {
console.log(this.toString())
}
}
var linkedList = new LinkedList();
linkedList.print();
linkedList.append(1);
linkedList.print();
linkedList.append(2);
linkedList.print();
linkedList.append(3);
linkedList.print();
linkedList.append(5);
linkedList.print();
linkedList.insert(3, 4);
linkedList.print();
console.log(linkedList.indexOf(4));
linkedList.remove(4);
linkedList.print();
linkedList.removeAt(3);
linkedList.print();
console.log(linkedList.size());
linkedList.getHead();
BOM
不同的 frame window 对象不同。
窗口位置
X 坐标:screenLeft 和 screenX
Y 坐标:screenTop 和 screenY
moveTo(移动至某点) 和 moveBy(移动距离)
窗口大小
// 现代浏览器器
window.innerWidth 和 window.innerHeight
// IE 8 以前
document.documentElement.clientWidth
document.documentElement.clinetHeight
// IE 的混杂模式
document.body.clientWidth
document.body.clinetHeight
// 修改窗口大小
window.resizeTo()
window.resizeBy()
location
| 属性名 | 例子 | 属性说明 |
|---|---|---|
| href | – | 完整的 URL 链接 |
| protocol | https | 协议 |
| hostname | www.baidu.com | 不带端口的服务器名称 |
| port | 8080 | 返回端口号 |
| host | www.baidu.com:80 | 返回服务器名称和端口号 |
| pathname | /filename/xxx.html | 返回目录名和文件名 |
| search | ?q=aaa | 查询字符串,到 # 号为止 |
| hash | #page | 到结束 |
// 返回上一页,go(-1): 返回上一页,原页面表单中的内容会丢失;back(-1): 返回上一页,原页表表单中的内容会保留,一般还是back(-1)
history.go(-1)
history.back()
// 下一页
history.go(1)
history.forward()
URLSearchParams
用户将 URL 参数的结构解析成对象获取。a=111&b=222&c=333这种结构,实例会有以下方法用户获取 params 信息。
- has():返回一个布尔值,表示是否具有某个参数
- get():返回指定参数的第一个值
- getAll():返回一个数组,成员是指定参数的所有值
- set():设置指定参数
- delete():删除指定参数
- append():在查询字符串之中,追加一个键值对
-
toString():返回整个查询字符串
var paramsString = ‘a=111&b=222&c=333’; var searchParams = new URLSearchParams(paramsString);
searchParams.has(‘a’) // true searchParams.get(‘a’) // “111” searchParams.getAll(‘a’) // [“111”]
searchParams.get(‘d’) // null,注意Firefox返回空字符串 searchParams.set(‘d’, 444); searchParams.get(‘d’) // 444
searchParams.append(‘e’, ‘555’); searchParams.toString() // “a=111&b=222&c=333&d=444&e=555”
searchParams.append(‘a’, 666); searchParams.getAll(‘a’) // [111, 666]
searchParams.delete(‘e’); searchParams.toString() // “a=111&b=222&c=333&d=444&a=666”
hash
前端路由的实现一般有两种方式:
- location.hash + hashchange 事件
- history.pushState() + popState事件
hash 的改变并不会触发页面的跳转,所以现在的 SPA 基本上都是基于 hash 实现的,URL 中锚点的取值是从 #到结束,而参数是取自 ?到# 之间。所以 hash 后面带参数都会被认为是 hash,所以才能在现在前端路由中页面跳转带参数,将 hash 取出来再按照一定的规则进行处理得到路由的配置,执行不同的实例。
hashchange
hash 改变路由需要有监听,主要的监听方式由 hashchange 实现,当路由发生改变时会触发。
window.addEventListener('hashchange', function(){}, false);
state change
这种的实现主要是为了短暂的记录当前页面的状态。可能是 ajax 获取到了页面的数据,渲染页面,当页面返回时能从页面的状态中获取数据直接用于渲染
popstate
历史发生改变时都会触发,需要注意的是,仅仅调用pushState方法或replaceState方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用 JavaScript 调用 back、forward、go 方法时才会触发。
window.onpopstate = function (event) {
console.log('location: ' + document.location);
console.log('state: ' + JSON.stringify(event.state));
};
// 或者
window.addEventListener('popstate', function(event) {
console.log('location: ' + document.location);
console.log('state: ' + JSON.stringify(event.state));
});
history.pushState
history.pushState 会让 URL 立即发生改变,但是页面并不会发生任何改变,只是历史记录中多了条记录,如果设置的是锚点也不会触发 hashchange 事件。包含以下参数:
- state:一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。
- title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。
- url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。url必须同域,不能跨域
history.pushState({page: 2}, 'title 2', '?page=2');
history.replaceState
replaceState 和 pushState 相同,replace 是替换,push 是新增。
history.replaceState({page: 3}, 'title 3', '?page=3');