js数组扁平化
// 数组扁平化
const arr = [1,[2,[3,[4,5]]],6];
//1:使用flat
const arrflat = arr.flat(Infinity);
console.log(arrflat);
//2:使用正则
const res2 = JSON.stringify(arr).replace(/\[|\]/g,'').split(',');
console.log(res2);//数据会变成字符串
//3:正则改良版本
const res3 = JSON.parse('['+ JSON.stringify(arr).replace(/\[|\]/g,'')+']');
console.log(res3);
//4:使用reduce
const flatten = arr => {
return arr.reduce((pre,cur) => {
console.log(pre);
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
},[])
}
const res4 = flatten(arr);
console.log(res4);
//函数递归
const res5 = [];
const fn = arr => {
for(let i = 0; i < arr.length; i++){
if(Array.isArray(arr[i])){
fn(arr[i]);
} else{
res5.push(arr[i]);
}
}
return res5;
}
console.log(fn(arr));
js数组去重
1:利用set
const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];
const res1 = Array.from(new Set(arr));
console.log(res1);
2:两层for循环加上splice
const res2 = arr => {
let len = arr.length;
for(let i =0;i < len;i++){
for(let j = i + 1;j < len;j++){
if(arr[i] === arr[j]){
arr.splice(j,1);
len--;
j--;
}
}
}
return arr;
}
console.log(res2(arr));
3:利用indexof
const res3 = arr => {
const res = [];
for(let i = 0;i < arr.length;i++){
if(res.indexOf(arr[i]) === -1)res.push(arr[i]);
}
return res;
}
console.log(res3(arr));
4:利用includes
const res4 = arr => {
const res = [];
for(let i =0;i < arr.length;i++){
if(!res.includes(arr[i]))res.push(arr[i])
}return res;
}
console.log(res4(arr));
5:利用filter
const res5 = arr => {
return arr.filter((item,index) => {
return arr.indexOf(item) === index;
})
}
console.log(res5(arr));
6:利用Map
const res6 = arr => {
const map = new Map();
const res = [];
for(let i = 0;i < arr.length;i++){
if(!map.has(arr[i])){
map.set(arr[i],true)
res.push(arr[i]);
}
}
return res;
}
console.log(res6(arr));
const DEFAULTS = {
logLevel: 0,
outputFormat: 'html'
};
function processContent(options) {
options = Object.assign({}, DEFAULTS, options);
console.log(options);
// ...
}
防抖节流
1、防抖
通过setTimeout的方式,在一定时间间隔内,将多次触发的事件一次触发。
btn.addEventListener('click',debounce(submit,2000),false);
function submit(e){
// console.log(this);
console.log(1);
}
function debounce(fn, timer){
var t = null;
return function(){
var firstClick = !t;
if(t){ clearTimeout(t); }
if(firstClick){
fn.apply(this,arguments);
}
console.log(t);
t = setTimeout(() => {
t = null;
}, timer)
}
}
在第一次点击的时候触发,调用submit函数,在设置的时间间隔内再次点击按钮时,var t = null 是不会执行的,执行的是返回的那个函数,此时的 t 不是null,所以定时器就会被清除掉了,也不会调用submit函数了。
当时间间隔过去之后,t 的值已经被设置为了null,所以在时间间隔后再次点击按钮的时候,就不会清除定时器,就会调用submit函数,从而就实现了在多次点击之后只会执行一次事件调用了。
2、节流
就是在一段时间内减少事件的触发频率。
源代码如下:
var btn = document.getElementById("input");
btn.addEventListener('click', throttle(submit, 2000), false);
function submit(e) {
console.log(e, this);
}
function throttle(fn,delay){
var begin = 0;
return function(){
var cur = new Date().getTime();
if(cur - begin > delay){
fn.apply(this,arguments);
begin = cur;
console.log(begin);
}
}
}
第一次点击按钮的时候,记录下当时的时间(为1970年来的毫秒数),然后设置一个开始的时间 begin = 0,用记录的时间减去设置的开始时间,如果得到的差大于我们设置的时间间隔的话,就会去调用submit函数,也就是说在时间间隔以内连续点击按钮的话,是不会执行submit函数的,也就是说相应的两个时间的间隔就是比设置的时间间隔长了一点点而已,从而达到了节流的效果.
http和https
http为什么不安全:因为http通信的时候是采用的明文,没有加密,内容可能被窃听。也无法验证接收报文的完整性,可能已经被篡改了。并且http也不验证通信方的身份,因此有可能被伪装。
https:简单来说,https就是http+加密+证书+完整性保护构成的。
在数据传输阶段,使用对称加密,就是再加密和解密的时候使用的是同一个密钥,只要攻击者拿到密钥,就一样可以进行攻击。证书交验阶段,采用非对称加密技术。
https采用的是混合加密。
tcp和udp
tcp提供了一种可靠的、面向连接的、字节流、传输层的服务,采用三次握手建立一个连接,四次挥手来关闭一个连接。
三次握手原理:
1、客户端发送syn(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认。
2、服务器接收到syn,必须确认客户端的SYN(ack = x + 1),同时自己也发送一个SYN(syn = y),即SYN+ACK包,此时服务器进入SYN_RECV状态。
3、客户端接收到服务器端的SYN+ACK包,向服务器发送确认包ACK(ack = y+1),发送完毕,客户端和服务器端进入ESTABLISHED状态,完成三次握手。
为什么要三次握手?
保证客户端和服务器端的接收能力和发送能力都是正常的。
js的this指向
默认指向
默认指向全局对象window
function a(){
console.log(this);
}
a();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
隐式绑定:
var girl = {
name: 'haha',
detail: function(){
console.log('姓名'+ this.name);
}
}
girl.detail();//姓名haha
硬绑定
var girl = {
name: 'haha',
detail: function(){
console.log('姓名'+ this.name);
}
}
var girl1 = {
name: '小白',
}
var girl2 = {
name: '小红',
}
girl.detail.call(girl1);//姓名小白
girl.detail.call(girl2);//姓名小红
girl.detail.apply(girl1);//姓名小白
girl.detail.apply(girl2);//姓名小红
构造函数绑定
function Lover(name){
this.name = name;
this.sayName = function(){
console.log("我的老婆是"+this.name);
}
}
var name = 'cabbage';
var dilireba = new Lover('迪丽热巴');
dilireba.sayName();//我的老婆是迪丽热巴
面试题目:
var name = '小白';
function special(){
console.log("name"+this.name);
}
var girl = {
name: '小红',
detail: function(){
console.log('name'+this.name);
},
woman:{
name: '小黄',
detail: function(){
console.log('name'+this.name);
}
},
special: special,
}
girl.detail();//里面的this指向当前调用这个方法的对象
girl.woman.detail();//里面的this指向当前调用这个方法的对象
girl.special();//里面的this指向当前调用这个方法的对象,如果没有 则会往上寻找。
var name = "小红";
function a(){
var name = "小白";
console.log(this.name);
}
function d(i){
return i();
}
var b = {
name: "小黄",
detail: function(){
console.log(this.name);
},
bibi: function(){
return function(){
console.log(this.name);
}
},
}
var c = b.detail;
b.a = a;
var e = b.bibi();
a();
c();
b.a();
d(b.detail);
e();
//输出:
//小红
//小红
//小黄
//小红
//小红
JS变量和函数使用
map和parseInt的用法:
var arr = ['1','5','6'];
var a = arr.map(function(item,index,array){
console.log(item,index,array);
});
console.log(a);
map后面接收一个函数,函数里面有三个参数,分别是数组的值,下标和数组本身。
map和parseInt结合在一起:
var arr = ['1','5','6'];
var a = arr.map(function(item,index,array){
return parseInt(item,index,array);
});
console.log(a);
//输出结果
/*(3) [1, NaN, NaN]
0: 1
1: NaN
2: NaN
length: 3*/
parseInt函数接收两个参数,第一个参数是数值型,第二个参数是要转换的进制类型,范围是在2-36之间。
否则就会返回NaN
var const let的区别
const let变量是不能被重复定义的。但是let是可以被重新赋值的,const变量是不可以被重新赋值的,但是const的数组是可以被改变内容的。
var关键字会有变量提升,但是赋值是不会被提升的。
let是没有变量提升的。const一旦声明就必须有定义。
let和const可以形成块级作用域:
{
let content = "haha";
console.log(content);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7JaWmxQm-1606267689078)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201008131159594.png)]
js数组的高级用法
//map的高级用法
// 参数:接收两个参数,一个是回调函数,另一个是回调函数的this值(可选)。回调函数接收三个参数,分别是当前值,当前索引和整个数组。
// 返回:函数返回一个新创建的数组,数组中的每个元素都经过了回调函数的处理,结果不改变原数组。
let nums = [1,2,3];
let obj = {val: 5};
let newNums = nums.map(function(item,index,array){
return item + index + array[index] + this.val;
// return item + index + array[index];
},obj);
console.log(newNums);
//reduce的高级用法
// 参数:接收两个参数,一个是回调函数,另一个是初始值(可选)。回调函数接收三个参数,分别是积累值、当前值和整个数组。
// 返回:函数返回一个值,该值由数组中的元素通过回调函数进行处理后积累得到的最终值。
// 注:若没传初始值,则会将数组中的第一个元素作为积累值,从数组的第二个元素开始进行函数调用
let nums1 = [1,2,3];
let newNums1 = nums1.reduce(function(preSum,curVal,array){
return preSum + curVal;
},2);
console.log(newNums1);
//filter的高级用法
// 参数:接收一个函数参数。函数接收一个默认参数,就是数组正在遍历的当前元素,函数参数的返回值是一个布尔值,若返回true,则数组元素得到保留。
// 返回:函数返回一个新创建的数组,数组元素为通过函数参数调用返回true的元素,此函数不会改变原数组。
let oldnums = [1,2,3,4,5,6,7,8,9];
let newnums = oldnums.filter(function(val){
// console.log(val%2)
return val % 2;
});
console.log(newnums);
//sort的高级用法
// 参数:接收一个用于比较的函数,比较函数默认接收两个参数,分别是代表比较的两个元素。
// 返回:返回一个经过比较函数调用的数组,此函数会改变原数组。
//注:若没有传入比较函数,则会将数字转换成字符串,然后根据字符的unicode值进行升序排序,也就是根据字符串的比较规则进行升序排序
let nums2 = [2,3,1,1,2,1,0];
//两个比较的元素分别为a, b
nums2.sort(function(a,b){
if(a > b) return 1;
else if(a < b) return -1;
else if(a == b) return 0;
});
console.log(nums2.reverse())