存储

我们经常需要对业务中的一些数据进行存储,通常可以分为 短暂性存储 和 持久性储存。

短暂性的时候,我们只需要将数据存在内存中,只在运行时可用

持久性存储,可以分为 浏览器端 与 服务器端

浏览器:

  • cookie: 通常用于存储用户身份,登录状态等
  • http 中自动携带, 体积上限为 4K, 可自行设置过期时间
  • localStorage / sessionStorage: 长久储存/窗口关闭删除, 体积限制为 4~5M
  • indexDB

服务器:

  • 分布式缓存 redis
  • 数据库

从输入 url 到展示的过程

DNS 解析
TCP 三次握手
发送请求,分析 url,设置请求报文(头,主体)
服务器返回请求的文件 (html)
浏览器渲染
1.HTML parser –> DOM Tree
标记化算法,进行元素状态的标记
dom 树构建
2.CSS parser –> Style Tree
解析 css 代码,生成样式树
3.attachment –> Render Tree
结合 dom树 与 style树,生成渲染树
4.layout: 布局
GPU painting: 像素绘制页面

安全

SQL 注入

这是一种比较简单的攻击方式。

如果后台人员使用用户输入的数据来组装SQL查询语句的时候不做防范, 遇到一些恶意的输入, 最后生成的SQL就会有问题。
比如地址栏输入的是:

1
articlrs/index.php?id=1

发送一个get请求, 调用的查询语句是:

1
sql = "SELECT * FROM articles WHERE id =", $id

阅读全文

模块化

模块化开发在现代开发中已是必不可少的一部分,它大大提高了项目的可维护、可拓展和可协作性。通常,我们 在浏览器中使用 ES6 的模块化支持,在 Node 中使用 commonjs 的模块化支持。

在有 Babel 的情况下,我们可以直接使用 ES6 的模块化

1
2
3
4
5
6
7
8
// file a.js
export function a() {}
export function b() {}
// file b.js
export default function () {}

import { a, b } from "./a.js";
import XXX from "./b.js";

阅读全文

继承

今天我们来说一下继承,在ES5中,我们可以使用如下方式解决继承的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Super() {}
Super.prototype.getNumber = function() {
return 1
}

function Sub() {}
let s = new Sub()
Sub.prototype = Object.create(Super.prototype, {
constructor: {
value: Sub,
enumerable: false,
writable: true,
configurable: true
}
})

阅读全文

防抖节流

今天我们来说一下防抖和节流,防抖与节流函数是一种最常用的 高频触发优化方式,能对性能有较大的帮助。

防抖

防抖 (debounce): 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。使用场景:
1.给按钮加函数防抖防止表单多次提交。
2.对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数。

我们先来看一个袖珍版的防抖理解一下防抖的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// func是用户传入需要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
// 缓存一个定时器id
let timer = 0
// 这里返回的函数是每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个新的定时器,延迟执行用户传入的方法
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
// 不难看出如果用户调用该函数的间隔小于wait的情况下,上一次的时间还未到就被清除了,并不会执行函数

这是一个简单版的防抖,但是有缺陷,这个防抖只能在最后调用。一般的防抖会有immediate选项,表示是否立即调用。这两者的区别,举个栗子来说:

阅读全文

对象的拷贝

深浅拷贝

1
2
3
4
5
6
let a = {
age: 1,
};
let b = a;
a.age = 2;
console.log(b.age); // 2

从上述例子中我们可以发现,如果给一个变量赋值一个对象,那么两者的值会是同一个引用,其中一方改变,另一方也会相应改变。
通常在开发中我们不希望出现这样的问题,我们可以使用浅拷贝来解决这个问题。

浅拷贝
首先可以通过 Object.assign 来解决这个问题。

1
2
3
4
5
6
let a = {
age: 1,
};
let b = Object.assign({}, a);
a.age = 2;
console.log(b.age); // 1

阅读全文

== 和 === 有什么区别

== 和 === 运算符用于比较两个值是否相等,当然,它们对相等的定义不尽相同。两个运算符允许任意类型的操作数,如果操作数相等则返回true,否则返回false。那么关于== 和===有什么区别呢?让我们一起来探究。

‘===’恒等

===严格相等运算符,首先计算其操作数的值,然后比较这两个值,比较过程没有任何类型转换:
如果两个类型不相同,则它们不相等。例如:

1
1 === 'true'  // false

如果两个值都是null或者都是undefined,则它们相等。例如:

1
null === undefined  // false

如果两个值都是布尔值true或者都是false,则它们相等。例如:

1
true === true   // true

阅读全文

闭包

什么是闭包

闭包的定义其实很简单:函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。

1
2
3
4
5
6
7
function A() {
let a = 1;
function B() {
console.log(a);
}
return B;
}

变量的作用域

要理解闭包,首先必须理解 Javascript 特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
Javascript 语言的特殊之处,就在于函数内部可以直接读取全局变量。

阅读全文

原型

今天说一下JS中原型和原型链,我理解的也不是很透彻,这边结合网上的一些文章,记录一下。

1. 原型 / 构造函数 / 实例

每个函数都有 prototype 属性,除了 Function.prototype.bind(),该属性指向原型。
每个对象都有proto属性,指向了创建该对象的构造函数的原型。其实这个属性指向了 [[prototype]],但是 [[prototype]] 是内部属性,我们并不能访问到,所以使用proto来访问。
对象可以通过proto来寻找不属于该对象的属性,proto将对象连接起来组成了原型链。
如果你想更进一步的了解原型,可以仔细阅读深度解析原型中的各个难点

  • 原型(prototype): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都包含一个proto (非标准)的属性指向它爹(该对象的原型),可obj__proto__进行访问。
  • 构造函数: 可以通过new来 新建一个对象 的函数。
  • 实例: 通过构造函数和new创建出来的对象,便是实例。
  • 实例通过proto指向原型,通过constructor指向构造函数。

可能有点懵逼,这里来举个栗子,以Object为例,我们常用的Object便是一个构造函数,因此我们可以通过它构建实例。

1
2
// 实例
const instance = new Object()

阅读全文