文章目录
有关DNS
A. DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。
BC.DNS协议运行在UDP协议之上,使用端口号53。
D. 浏览器:chrome对每个域名会默认缓存60s,IE将DNS缓存30min,Firefox对DNS缓存功能,但是默认缓存时间只有1分钟,safari约为10s。
windows DNS缓存的默认值是MaxCacheTTL,它的默认值是86400s,也就是一天。
浏览器DNS缓存的时间跟ttl值无关,每种浏览器都使用一个固定值。
TCP
数组元素移动
function replaceElements( arr ) {
let newArr = [];
while(arr.length) {
//得到该元素的右边元素
arr.shift();
if(!arr.length) {
newArr.push(-1)
} else {
//得到右边元素
newArr.push(Math.max(...arr))
}
}
return newArr
}
两个数组的交集
const set_intersection = (set1, set2) => {
if (set1.size > set2.size) {
return set_intersection(set2, set1);
}
const intersection = new Set();
for (const num of set1) {
if (set2.has(num)) {
intersection.add(num);
}
}
return [...intersection];
}
var intersection = function(nums1, nums2) {
const set1 = new Set(nums1);
const set2 = new Set(nums2);
return set_intersection(set1, set2);
};
webpack缓存:
- babel缓存
cacheDirectory: true
–> 让第二次打包构建速度更快- 文件资源缓存
hash: 每次wepack构建时会生成一个唯一的hash值。
问题: 因为js和css同时使用一个hash值。
如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)
chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
问题: js和css的hash值还是一样的
因为css是在js中被引入的,所以同属于一个chunk
contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样
–> 让代码上线运行缓存更好使用(上线代码的性能优化的)
综上所述:开启缓存需要经历两个步骤:
1. 设置cacheDirectory: true
2. 在输出的数组中加上contenthash
toString与valueOf 巧妙使用
如何进入if语句中
let a = {
_default: 0,
valueOf: function() {
return ++this._default;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("you are win !!")
}
let b = {
_default: 0,
valueOf: function() {
return ++this._default;
}
}
if (b == 1 && b == 2 && b == 3) {
console.log("you are win !!")
}
var _default = 0;
Object.defineProperty(window, 'c', {
get() {
return ++_default;
}
})
if (c === 1 && c === 2 && c === 3) {
console.log("you are win !!")
}
Function
Function.length
length 是函数对象的一个属性值
,指该函数有多少个必须要传入的参数,即形参的个数。形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。
与之对比的是,arguments.length
是函数被调用时实际传参的个数
。
Function 构造器的属性
Function 构造器本身也是个Function。他的 length 属性值为 1 。该属性 Writable: false, Enumerable: false, Configurable: true.
console.log(Function.length); /* 1 */
console.log((function() {}).length); /* 0 */
console.log((function(a) {}).length); /* 1 */
console.log((function(a, b) {}).length); /* 2 etc. */
console.log((function(...args) {}).length);
// 0, rest parameter is not counted
console.log((function(a, b = 1, c) {}).length);
// 1, only parameters before the first one with
// a default value is counted
Function 构造器
由
Function 构造器创建的函数不会创建当前环境的闭包
,它们总是被创建于全局环境
,
因此在运行时它们只能访问全局变量和自己的局部变量
,
不能访问它们被 Function 构造器创建时所在的作用域的变量。这一点与使用eval 执行创建函数
的代码不同。
const test = new Function("a", 'b', 'c', "console.log(a+b+c)")
// const test = new Function('a,b,c', "console.log(a+b+c)")
test(1, 3, 4) // 8
var x = 10;
function createFunction1() {
var x = 20;
return new Function('return x;'); // 这里的 x 指向最上面全局作用域内的 x
}
function createFunction2() {
var x = 20;
function f() {
return x; // 这里的 x 指向上方本地作用域内的 x
}
return f;
}
var f1 = createFunction1();
console.log(f1()); // 10
var f2 = createFunction2();
console.log(f2()); // 20
扁平数据树形结构化
测试data
const data = [{
id: '1',
menu_name: '设置',
menu_url: 'setting',
parent_id: 0
}, {
id: '1-1',
menu_name: '权限设置',
menu_url: 'setting.permission',
parent_id: '1'
}, {
id: '1-1-1',
menu_name: '用户管理列表',
menu_url: 'setting.permission.user_list',
parent_id: '1-1'
}, {
id: '1-1-2',
menu_name: '用户管理新增',
menu_url: 'setting.permission.user_add',
parent_id: '1-1'
}, {
id: '1-1-3',
menu_name: '角色管理列表',
menu_url: 'setting.permission.role_list',
parent_id: '1-1'
}, {
id: '1-1-4',
menu_name: '角色管理新增',
menu_url: 'setting.permission.role_add',
parent_id: '1-1'
}, {
id: '1-2',
menu_name: '菜单设置',
menu_url: 'setting.menu',
parent_id: '1'
}, {
id: '1-2-1',
menu_name: '菜单列表',
menu_url: 'setting.menu.menu_list',
parent_id: '1-2'
}, {
id: '1-2-2',
menu_name: '菜单添加',
menu_url: 'setting.menu.menu_add',
parent_id: '1-2'
}, {
id: '2',
menu_name: '订单',
menu_url: 'order',
parent_id: 0
}, {
id: '2-1',
menu_name: '报单审核',
menu_url: 'order.orderreview',
parent_id: '2'
}, {
id: '2-2',
menu_name: '退款管理',
menu_url: 'order.refundmanagement',
parent_id: '2'
}, {
id: '2-3',
menu_name: '实物订单',
menu_url: 'order.realorder',
parent_id: '2'
}, {
id: '2-1-1',
menu_name: '全部报单',
menu_url: 'order.orderreview.all',
parent_id: '2-1'
}, {
id: '2-2-1',
menu_name: '所有记录',
menu_url: 'order.refundmanagement.all',
parent_id: '2-2'
}, {
id: '2-2-2',
menu_name: '待处理',
menu_url: 'order.refundmanagement.wait',
parent_id: '2-2'
}, {
id: '2-2-3',
menu_name: '退款原因',
menu_url: 'order.refundmanagement.result',
parent_id: '2-2'
}, {
id: '2-3-1',
menu_name: '实物订单管理',
menu_url: 'order.realorder.list',
parent_id: '2-3'
}, {
id: '3',
menu_name: '商品',
menu_url: 'commodity',
parent_id: 0
}, {
id: '3-1',
menu_name: '分类管理',
menu_url: 'commodity.classifieldmanagement',
parent_id: '3'
}, {
id: '3-1-1',
menu_name: '管理',
menu_url: 'commodity.classifieldmanagement.management',
parent_id: '3-1'
}, {
id: '3-1-2',
menu_name: '编辑或新增',
menu_url: 'commodity.classifieldmanagement.edit',
parent_id: '3-1'
}, {
id: '3-2',
menu_name: '品牌管理',
menu_url: 'commodity.brandmanagement',
parent_id: '3'
}, {
id: '3-2-1',
menu_name: '管理',
menu_url: 'commodity.brandmanagement.management',
parent_id: '3-2'
}, {
id: '3-2-2',
menu_name: '编辑或新增',
menu_url: 'commodity.brandmanagement.edit',
parent_id: '3-2'
}, {
id: '3-3',
menu_name: '商品管理',
menu_url: 'commodity.commoditymanagement',
parent_id: '3'
}, {
id: '3-3-1',
menu_name: '管理',
menu_url: 'commodity.commoditymanagement.management',
parent_id: '3-3'
}, {
id: '3-3-2',
menu_name: '编辑或新增',
menu_url: 'commodity.commoditymanagement.edit',
parent_id: '3-3'
}, {
id: '3-4',
menu_name: '类型管理',
menu_url: 'commodity.typeManagement',
parent_id: '3'
}, {
id: '3-4-1',
menu_name: '管理',
menu_url: 'commodity.typeManagement.management',
parent_id: '3-4'
}, {
id: '3-4-2',
menu_name: '编辑或新增',
menu_url: 'commodity.typeManagement.edit',
parent_id: '3-4'
},
{
id: "1-1-2-1",
menu_name: "我是第四级",
menu_url: "four",
parent_id: "1-1-2"
}
];
递归实现
function formatDataTree(data) {
// 说明是根数据
let parents = data.filter(p => p.parent_id === 0),
//子元素
children = data.filter(p => p.parent_id != 0);
dataTree(parents, children)
// parents children array[]
function dataTree(parents, children) {
parents.map(p => {
children.map((c, i) => {
if (c.parent_id === p.id) {
// 深拷贝一份,防止直接修改原先引用
let _children = JSON.parse(JSON.stringify(children))
_children.splice(i, 1)
// 再次递归寻找子节点
dataTree([c], _children)
if (p.children) {
p.children.push(c)
} else {
p.children = [c]
}
}
})
})
}
return parents
}
const treeData = formatDataTree(data)
console.log(treeData)
循环实现
时间复杂度O(n^2)
function formatDataTree(data) {
let _data = JSON.parse(JSON.stringify(data));
return _data.filter(p => {
const childrenArr = _data.filter(c => c.parent_id === p.id);
childrenArr.length && (p.children = childrenArr);
return p.parent_id == 0;
})
}
const dataTree = formatDataTree(data);
console.log(dataTree)
转对象实现
时间复杂度 O(n)
function buildTree(list) {
let temp = {};
let tree = {};
for (let i in list) {
temp[list[i].id] = list[i];
}
for (let i in temp) {
debugger
if (temp[i].parent_id) {
if (!temp[temp[i].parent_id].children) {
temp[temp[i].parent_id].children = new Object();
}
temp[temp[i].parent_id].children[temp[i].id] = temp[i];
} else {
tree[temp[i].id] = temp[i];
}
}
return tree;
}
let arr = [];
for (let index in data) {
arr.push(JSON.parse(JSON.stringify(data[index])))
}
const dataTree = buildTree(arr);
实现MVVM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="name" placeholder="姓名" />
<input type="text" v-model="age" placeholder="年龄" />
<input type="text" v-model="email" placeholder="邮箱" />
<input type="text" v-model="tel" placeholder="号码" />
<div>
<p>姓名:<span>{{name}}</span></p>
<p>年龄:<span>{{age}}</span></p>
<p>邮箱:<span>{{email}}</span></p>
<p>
<p>
号码:<span>{{tel}}</span>
</p>
</p>
</div>
<button id="btn">改变名字</button>
</div>
<script src="./mvvmProxy.js"></script>
<script>
const app = new MVVM('#app', {
name: 'xxx',
age: '',
email: '',
tel: '',
})
document.querySelector('#btn').addEventListener('click', function() {
app.setData('name', "哈哈哈")
})
</script>
</body>
</html>
使用Object.defineProperty
步骤
- 数据 --> 响应式数据
Object.defineProperty Proxy
input
-->input/keyup
–> 事件处理函数的绑定 --> 改变数值- 相关的
DOM
--> 数据绑定 ==> 绑定在一起
操作数据的某个属性 --> 对应的DOM 就改变
class MVVM {
constructor(el, data) {
this.el = document.querySelector(el);
this._data = data;
this.domPool = {}
this.init()
}
init() {
this.initData()
this.initDom()
}
initDom() {
this.bindDom(this.el);
this.bindInput(this.el);
console.log(this.domPool)
}
initData() {
const _this = this;
this.data = {};
for (let key in this._data) {
Object.defineProperty(this.data, key, {
get() {
console.log("获取数据:", key, _this._data[key])
return _this._data[key];
},
set(newValue) {
console.log("设置数据:", key, newValue)
_this.domPool[key].innerHTML = newValue;
_this._data[key] = newValue
}
})
}
}
bindDom(el) {
// 取出子节点
const childNodes = el.childNodes;
// 寻找文本节点
childNodes.forEach(item => {
// item.nodeType === 3 寻找文本类型节点
if (item.nodeType === 3) {
const _value = item.nodeValue;
if (_value.trim().length) {
// 匹配 {{nameString}}
let _isValid = /\{\{(.+?)\}\}/.test(_value);
if (_isValid) {
// 将{{nameString}} 中的 nameString 取出
const _key = _value.match(/\{\{(.+?)\}\}/)[1].trim();
// 存储文本节点的父节点
this.domPool[_key] = item.parentNode;
// 初始化数据
item.parentNode.innerText = this.data[_key] || undefined;
}
}
}
// 递归寻找子节点
item.childNodes && this.bindDom(item);
});
}
// 给所有的输入框绑定事件
bindInput(el) {
// 获取输入框的值
const _allInput = el.querySelectorAll('input');
_allInput.forEach(input => {
// 获取v-model 的值
const _vModel = input.getAttribute('v-model');
if (_vModel) {
// 监听输出框数据改变
input.addEventListener('keyup', this.handleInput.bind(this, _vModel, input));
}
});
}
// 输入框数据改变回调函数
handleInput(key, input) {
// 当输入框数据改变时,将数据保存在data中
const _value = input.value;
this.data[key] = _value;
}
// 设置数据
setData(key, value) {
this.data[key] = value
}
}
/*
1. 数据 --> 响应式数据 Object.defineProperty Proxy
2. input --> input/keyup --> 事件处理函数的绑定 --> 改变数值
3. 相关的DOM --> 数据绑定 ==> 绑定在一起
操作数据的某个属性 --> 对应的DOM 就改变
*/
使用Proxy代理捕获
const reg_var = /\{\{(.+?)\}\}/;
class MVVM {
constructor(el, data) {
this.el = document.querySelector(el);
this.data = data;
this.domPool = {}
this.init()
}
init() {
this.initData()
this.initDom()
}
initDom() {
this.bindDom(this.el);
this.bindInput(this.el);
console.log(this.domPool)
}
initData() {
const _this = this;
// Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
// 使用Proxy代理拦截捕获值的变化
this.data = new Proxy(this.data, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, value) {
_this.domPool[key].innerHTML = value;
return Reflect.set(target, key, value)
}
})
}
bindDom(el) {
// 取出子节点
const childNodes = el.childNodes;
// 寻找文本节点
childNodes.forEach(item => {
// item.nodeType === 3 寻找文本类型节点
if (item.nodeType === 3) {
const _value = item.nodeValue;
if (_value.trim().length) {
// 匹配 {{nameString}}
let _isValid = reg_var.test(_value);
if (_isValid) {
// 将{{nameString}} 中的 nameString 取出
const _key = _value.match(reg_var)[1].trim();
// 存储文本节点的父节点
this.domPool[_key] = item.parentNode;
// 初始化数据
item.parentNode.innerText = this.data[_key] || undefined;
}
}
}
// 递归寻找子节点
item.childNodes && this.bindDom(item);
});
}
// 给所有的输入框绑定事件
bindInput(el) {
// 获取输入框的值
const _allInput = el.querySelectorAll('input');
_allInput.forEach(input => {
// 获取v-model 的值
const _vModel = input.getAttribute('v-model');
if (_vModel) {
// 监听输出框数据改变
input.addEventListener('keyup', this.handleInput.bind(this, _vModel, input));
}
});
}
// 输入框数据改变回调函数
handleInput(key, input) {
// 当输入框数据改变时,将数据保存在data中
const _value = input.value;
this.data[key] = _value;
}
// 设置数据
setData(key, value) {
this.data[key] = value
}
}
/*
1. 数据 --> 响应式数据 Object.defineProperty Proxy
2. input --> input/keyup --> 事件处理函数的绑定 --> 改变数值
3. 相关的DOM --> 数据绑定 ==> 绑定在一起
操作数据的某个属性 --> 对应的DOM 就改变
*/
mustache
git地址:Mustache源码
diff算法
函数、对象、数组的length 相关
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 字符串的 toString
let len1 = ({} + {}).length;
console.log(len1); // 30 ==> "[object Object][object Object]".length
let arrNullAdd = [] + []; // ==> 相当于 "" + ""
console.log(typeof arrNullAdd) //string
console.log(arrNullAdd) //"": string
console.log(arrNullAdd.length) // 0 ==> "".length = 0;
// 数组相加
let arr = [12];
let arrAdd = 4 + arr; // "412" string ==> 4+"12"
let arr2 = 4 * arr; // 48 number ==> 4*"12"
console.log(arrAdd) // "412" string
console.log(4 + "12")
console.log(arr2) // 48 number
console.log(4 * "12") // 48 number
let arr3 = [1, 3];
let arr4 = [2, 2];
let arrHaveAdd = arr3 + arr4; // "1,32,2" ==> "1,3" +"2,2"
console.log(arrHaveAdd) // "1,32,2"
console.log("1,3" + "2,2") // "1,32,2"
let len2 = arrHaveAdd.length; // 6
console.log(len2) // 6
let arr5 = [1];
let arr6 = [2];
let arrOneAdd = arr5 + arr6; // "12" string ==> "1"+"2"
console.log(arrOneAdd)
// 函数的length
console.log("--------------函数----------")
/*
- 函數的length 属性
length 属性指明函数的形参个数。
length 是函数对象的一个属性值,指该函数有多少个必须要传入的参数,即形参的个数。
形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。
与之对比的是, arguments.length 是函数被调用时实际传参的个数。
Function 构造器本身也是个Function。他的 length 属性值为 1 。该属性 Writable: false, Enumerable: false, Configurable: true.
*/
let funLen = (function() {}).length
console.log(funLen)
console.log(Function.length); /* 1 */
console.log((function() {}).length); /* 0 */
console.log((function(a) {}).length); /* 1 */
console.log((function(a, b) {}).length); /* 2 etc. */
console.log((function(...args) {}).length); //形参的数量不包括剩余参数个数,
// 0, rest parameter is not counted
console.log((function(a, b = 1, c) {}).length); //形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。
// 1, only parameters before the first one with
// a default value is counted
</script>
</body>
</html>
toString、valueOf和Object.defineProperty
如何使以下条件成立
if (a == 1 && a == 2 && a == 3) {
console.log("you are win !!")
}
if (c === 1 && c === 2 && c === 3) {
console.log("you are win !!")
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// tostring 与 valueOf 使用
/*
tostring 与 valueOf 隐式调用
https://blog.csdn.net/qq_45768871/article/details/110365885
*/
// 使用valueOf 隐式调用
let a = {
_default: 0,
valueOf: function() {
return ++this._default;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("you are win !!")
}
// 使用toString 隐式调用
let b = {
_default: 0,
toString: function() {
return ++this._default;
}
}
if (b == 1 && b == 2 && b == 3) {
console.log("you are win !!")
}
// 使用 Object.defineProperty 绑定对象属性 + get 获取
var _default = 0;
Object.defineProperty(window, 'c', {
get() {
return ++_default;
}
})
if (c === 1 && c === 2 && c === 3) {
console.log("you are win !!")
}
</script>
</body>
</html>
Function
const test = new Function("a", 'b', 'c', "console.log(a+b+c)")
// const test = new Function('a,b,c', "console.log(a+b+c)")
test(1, 3, 4) // 8
var a = 1,
b = 2;
function fun() {
var b = 3;
return function(c) {
console.log(a + b + c);
}
}
var funTest = fun();
funTest(4); // 8
/*
由 `Function 构造器创建的函数不会创建当前环境的闭包`,它们总是`被创建于全局环境`,
因此在运行时它们`只能访问全局变量和自己的局部变量`,
不能访问它们被 Function 构造器创建时所在的作用域的变量。这一点与使用` eval 执行创建函数`的代码不同。
*/
function fun2() {
var b = 3;
return new Function('c', "console.log(a+b+c)")
}
var funTest2 = fun2();
funTest2(4); // 7