自省系列JS-4

FormData

概念

FormData接口提供一种表示表单数据的键值对的构造方式.可以通过JavaScript模拟表单控件操作.可以通过XMLHttpRequestsend方法异步提交表单

使用

FormData

初始化表单对象,可以传入dom元素,可以为空

1
2
3
4
5
//创建一个空的FormData对象
let formData = new FormData();
//创建一个存在的form对象 这个对象包含这个表单的数据
const formOne = document.getElementById("myform");
let formData = new FormData(formOne);

append,set

append:添加一个新值对到FormData对象,键存在将新值添加到值的集合中,不存在则添加新的键值对

set: 通append,区别在于如果键存在情况下,新的值覆盖旧值

1
2
3
4
5
6
7
8
//formData.append(name,value)
//formData.append(name,value,[filename])--value为文件对象时,可以通过filename定义文件名字如果value是Blob对象,默认文件名是"blob"
formData.append("name","lily");
formData.appen("name","hello"); //此时name的值是 lily,hello的集合
formData.append("avatar",fileInput.files[0],'avatar1.jpg') //上传头像文件,指定文件名称

//formData.set(name,value);
//formData.set(name,value,filename) //同append

delete

删除键值对

formData.delete("name");

entrieskeys

entries:返回FormData的键值对数据集合,是一个iterator对象

keys: 返回FormData的键集合,是一个iterator对象

1
2
3
const formOne = new FormData();
formData.entries(formOne);
formData.keys(formOne);

getgetAll

get: 返回指定key的第一个值

getAll: 返回指定key的所有值

1
2
formData.get("keyName");
formData.getAll("keyName");

has

检测某个key是否存在

formData.has("keyName")

values

返回一个允许遍历该对象中所有值的 迭代器

1
2
3
4
5
6
7
8
9
10
11
//创建一个FormData测试对象
var formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');

//显示值
for (var value of formData.values()) {
console.log(value);
}
//value1
//value2

base64场景

  • 上传图片,可以转化为base64上传
  • 可以在页面显示base64图片,适应于不是很大的图
  • url加密

移动端点击事件延迟

移动端会延迟300ms,来判断是否还有下一次点击,以此来判定是点击还是双击

避免延迟

禁止缩放

<meta name="viewport" content="width=device-width user-scalable= 'no'">

fastclick.js

随机字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 随即字符串
* @param {Number} length
*/
function randomString(length) {
//如果转换的基数大于10,则会使用字母来表示大于9的数字,比如基数为16的情况,则使用a到f的字母来表示10到15
//如果radix是36,就会把数字表示为由0-9, a-z组成的的36进制字符串
let str = Math.random().toString(36).substr(2);
if(str.length >= length) {
return str.substr(0,length);
}
str += randomString((str.length) - length);
}

typeof null == "object"

不同的对象在底层都表示为二进制, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0, 自然前三位也是 0, 所以执行 typeof 时会返回“object”

在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息:

  • 000:对象
  • 1:整数
  • 010:浮点数
  • 100:字符串
  • 110:布尔

九九乘法表

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
/**
* 九九乘法表
*/
function nine() {
let result = "";
for (let index = 1; index <= 9; index++) {
for (let i = 1; i <= index; i++) {
result += `${i} x ${index} = ${index * i} `;
}
result += `\t\n`;
}
return result;
}

console.log(nine());
/*
1 x 1 = 1
1 x 2 = 2 2 x 2 = 4
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6 = 36
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42 7 x 7 = 49
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8 = 48 7 x 8 = 56 8 x 8 = 64
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9 = 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
*/

浏览器同源策略

  • 相同协议,host,端口才是同源
  • 防止了CSRF的安全问题
  • 防止DOM操作的安全问题

JS延迟加载

  • defer属性
  • async属性
  • body之后
  • setTimeOut放到异步队列中

写一个暂停函数

1
2
3
4
5
6
7
8
9
10
11
/**
*
* @param {Number} wait 微秒
*/
function sleep(wait) {
return new Promise((resolve) => setTimeout(resolve, wait));
}

sleep(2000).then(() => {
console.log(1);
});

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
function test(){ 
console.log(test.prototype);
console.log(Object.getPrototypeOf(test));
//如果函数返回的值是引用类型(对象)的值时,new运算符将返回这个值
return test;
}
new test() instanceof Object; //true
new test() instanceof test; //false
//等价于
test instanceof test; //false
//test是一个Function,原型链为 Function.prototype -> Object.prototype -> null
//原型链上没有 test.prototype 出现,所以 test 并不是 test 的一个实例

随即打乱一个数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 洗牌算法-快速打乱数组顺序
* 倒序循环这个数组
* 取范围从1到n的随机数k
* k与n交换
* 直到循环至数组的首个元素
*/
function arrShuffle(arr) {
const length = arr.length - 1;
for (let n = length; n >= 0; n--) {
let randomIndex = Math.floor(Math.random() * (n + 1));
let randomArr = arr[randomIndex]; //随机数k
//k与n交换
arr[randomIndex] = arr[n];
arr[n] = randomArr;
}
return arr;
}`

为什么{}+[]===0

  • {} 被当成一个独立的空代码块
  • 所以上述表达式等价于+[] = 0
  • 0 === 0

({}+[])等于什么

  • 加上括号后会当做表达式计算
  • {}和[]都不是字符串
  • {}->valueOf->返回对象本身->非原始值->toString->[object Object]
  • []->valueIOf->返回对象本身->非原始值->toString->””
  • “[object Object]” + “ “ = “[object Object]”

数组的交集,差集,补集,并集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const arr1 = [1, 3, 4];
const arr2 = [1, 2, 4, 5];
const setArr1 = new Set(arr1);
const setArr2 = new Set(arr2);
//交集
let intersect = arr1.filter((item) => setArr2.has(item));
//差集
let minus = arr1.filter((item) => !setArr2.has(item));
//补集
let complement = [
...arr1.filter((item) => !setArr2.has(item)),
...arr2.filter((item) => !setArr1.has(item)),
];
//并集
let union = Array.from(new Set([...arr1, ...arr2]));
console.log(intersect, "交集");
console.log(minus, "差集");
console.log(complement, "补集");
console.log(union, "并集");

//[ 1, 4 ] 交集
//[ 3 ] 差集
//[ 3, 2, 5 ] 补集
//[ 1, 3, 4, 2, 5 ] 并集

如何给li绑定事件(ul下有1000+个li)

1
2
3
4
5
6
//通过事件冒泡,在父元素ul上绑定事件
document.getElementById("ul-id").addEventListener("click",(e) => {
if (e.target.tagName === "li") {
console.log(e);
}
})

"1,2,3,4"split()

split有两个参数,第一个参数是字符串或正则表达式,表明按照什么规则分隔字符串.如果为空,则将整个字符串返回.第二个参数规定分隔的数量

"1,2,3,4".split() -> ["1,2,3,4"]

"1234".split("",2) -> ["1,2"]

Ajax请求

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* ajax请求
* 不可跨域请求
*/
function ajax(params) {
params = params || {};
//要发送的数据
params.data = params.data || {};
//GET,POST
params.type = (params.type || "get").toUpperCase();
//格式化数据
params.data = formatParams(params.data);

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
//4已接收到全部响应数据
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
let response = "";
const responseType = xhr.getResponseHeader;
//获取响应数据格式
if (responseType === "application/json") {
response = JSON.parse(xhr.responseText);
} else if (responseType.indexOf("xml") !== -1 && xhr.responseXML) {
response = xhr.responseXML;
} else {
response = xhr.responseText;
}
//成功回调函数
params.success && params.success(response);
} else {
//失败回调函数
params.error && params.error(status);
}
}
};

//true异步 false同步
const asyncFlag = params.async || true;
if (params.type === "GET") {
xhr.open(params.type, params.url + "?" + params.data, true);
xhr.send();
} else {
xhr.open(params.type, params.url, asyncFlag);
xhr.setRequestHeader(
"Content-Type",
"application/x-www-form-urlencoded; charset=UTF-8"
);
xhr.send(params.data);
}
}

/**
* 数据格式化
*/
function formatParams(data) {
let params = [];
for (let name in data) {
params.push(
encodeURIComponent(name) + "=" + encodeURIComponent(data[name])
);
}
//时间戳 防止缓存
params.push("v=" + new Date().getTime());
//name=a&pwd=1&v=时间戳微秒
return params.join("&");
}

//示例
ajax({
url: "http://www.baidu.com", //请求地址
type: "GET", //请求类型 GET|POST
data: { wd: "时间戳" }, //请求数据
success: function (response) {
// 成功回调
console.log(JSON.parse(response));
},
error: function () {
//失败回调
console.log("失败");
},
});

红绿灯循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
async function trafficLight(color, wait) {
await new Promise((resolve) => {
console.log(color);
setTimeout(resolve, wait);
});
}

async function runLight() {
let i = 0;
while (i < 3) {
await trafficLight("红灯", 1000);
await trafficLight("绿灯", 2000);
await trafficLight("黄灯", 3000);
}
}

runLight();