前端小知识总结

一、HTML

二、CSS

三、JS

1、加法运算符的特殊用法

console.log("==============================")
    let str1 = "abccc";
    let numStr = "4";
    let num = 10;
    console.log(numStr + num); //410
    console.log(numStr - num); //-6
    console.log(numStr * num); //40
    console.log(numStr / num); //0.4

    console.log(str1 + num); //abccc10
    console.log(str1 - num); //NAN
    console.log(str1 * num); //NAN
    console.log(str1 / num); //NAN

    let foo = '20' - 10 + "10" + 10;
    console.log(foo); //101010

2、JS的执行机制

原文:https://www.jianshu.com/p/fb1c07b4d90d

四、VUE

1、VUE的生命周期

- 什么是生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
- 生命周期钩子:就是生命周期事件的别名而已;
- 生命周期钩子 = 生命周期函数 = 生命周期事件
- 主要的生命周期函数分类: - 创建期间的生命周期函数: - beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性 - created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板 - beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中 - mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示 - 运行期间的生命周期函数: - beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点 - updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了! - 销毁期间的生命周期函数: - beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。 - destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

2、v-for中key的作用:

VueReact,在执行列表渲染时也会要求给每个组件添加上key属性。这是由于虚拟DOMDiff算法,一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面,而隐藏在背后的原理便是其高效的Diff算法。

虚拟DOMDiff算法,其核心是基于两个简单的假设:

  1. 两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。

  2. 同一层级的一组节点,他们可以通过唯一的id进行区分。

基于以上这两点假设,使得虚拟DOMDiff算法的复杂度从O(n^3)降到了O(n)

当页面的数据发生变化时,Diff算法只会比较同一层级的节点:

如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。

当某一层有很多相同的节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则。

 

BC之间加一个FDiff算法默认把C更新成FD更新成CE更新成D,最后再插入E,所以需要使用key来给每个节点做一个唯一标识Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。

 

所以,key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。

五、服务端与网络

1、http状态码

  https://www.cnblogs.com/gitnull/p/9532129.html

2、http请求中请求头和响应头包含哪些内容

1)请求(客户端->服务端[request]) 
    GET(请求的方式) /newcoder/hello.html(请求的目标资源) HTTP/1.1(请求采用的协议和版本号) 
    Accept: */*(客户端能接收的资源类型) 
    Accept-Language: en-us(客户端接收的语言类型) 
    Connection: Keep-Alive(维护客户端和服务端的连接关系) 
    Host: localhost:8080(连接的目标主机和端口号) 
    Referer: http://localhost/links.asp(告诉服务器我来自于哪里) 
    User-Agent: Mozilla/4.0(客户端版本号的名字) 
    Accept-Encoding: gzip, deflate(客户端能接收的压缩数据的类型) 
    If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(缓存时间)  
    Cookie(客户端暂存服务端的信息) 
    Date: Tue, 11 Jul 2000 18:23:51 GMT(客户端请求服务端的时间)
2)响应(服务端->客户端[response])     HTTP/1.1(响应采用的协议和版本号) 200(状态码) OK(描述信息)     Location:
http://www.baidu.com(服务端需要客户端访问的页面路径)      Server:apache tomcat(服务端的Web服务端名)     Content-Encoding: gzip(服务端能够发送压缩编码类型)      Content-Length: 80(服务端发送的压缩数据的长度)      Content-Language: zh-cn(服务端发送的语言类型)      Content-Type: text/html; charset=GB2312(服务端发送的类型及采用的编码方式)     Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务端对该资源最后修改的时间)     Refresh: 1;url=http://www.it315.org(服务端要求客户端1秒钟后,刷新,然后访问指定的页面路径)     Content-Disposition: attachment; filename=aaa.zip(服务端要求客户端以下载文件的方式打开该文件)     Transfer-Encoding: chunked(分块传递数据到客户端)       Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务端发送到客户端的暂存数据)     Expires: -1//3种(服务端禁止客户端缓存页面数据)     Cache-Control: no-cache(服务端禁止客户端缓存页面数据)       Pragma: no-cache(服务端禁止客户端缓存页面数据)        Connection: close(1.0)/(1.1)Keep-Alive(维护客户端和服务端的连接关系)       Date: Tue, 11 Jul 2000 18:23:51 GMT(服务端响应客户端的时间) 在服务器响应客户端的时候,带上Access-Control-Allow-Origin头信息,解决跨域的一种方法。 原文链接:https://blog.csdn.net/weixin_37861326/article/details/82216068

 

六、数据结构与算法

七、ES6

1、let与const

  特点:(1)块级作用域(2)不存在变量声明提升(3)存在暂时性死区(4)不能够重复声明

var bar = 1;
function foo(){
    alert(bar);
    var bar = 2;
}
foo();//undefined,因为。。。。

let bar = 1;
function foo(){
    alert(bar);
    let bar = 2;//在块级作用域中,变量唯一存在;如果在块级作用域中用let声明了一个变量,那么该变量就唯一属于这个块级作用域,不受外部变量的影响;
}
foo();// Cannot access 'bar' before initialization
console.log(b);//Cannot access 'b' before initialization==b is not defined;
let b=1;

console.log(b);//undefined;变量声明提前,但是变量的赋值并没有提前
var b=1;

let a = 1;
console.log(window.a); //undefined 在全局作用域下,不同于var声明的变量,使用let来定义变量,该变量不会成为全局变量的一个属性。

var a = 1;
console.log(window.a); //1

const定义的对象,当对象改变了之后,const定义的值也会跟着改变。

cosnt定义的变量是一个对象的一个属性值,但是当对象属性值改变了以后,const定义的这个值并不会改变。

2、变量的解构赋值(字符串、数值、布尔、数组、对象、函数参数)

  ES6新特性,按照一定模式,从数组或者对象中提取值,然后对变量进行赋值,称为解构。(模式匹配)

(1)字符串的解构赋值

const [a,b,c,d,e] = 'hello';
console.log([a,b,c,d,e]);  //array ["h","e","l","l","o"]

let {length : len} = "hello";   //字符串是类似数组的对象,有length属性
console.log(len); //5

(2)数值和布尔值的解构赋值

  解构赋值的时候,如果等号右边是数值或者布尔值,会先将数值或布尔值转为对象;

let {toString: s1} = 123;
console.log(s1) // toString()
console.log(s1 === Number.prototype.toString) //true

let {toString: s2} = true;
console.log(s2) //toString()
console.log(s2 === Boolean.prototype.toString) //true

(3)数组的解构赋值

let [a,b,c] = [1,2,3];
console.log([a,b,c])  //[1,2,3] ;a=1,b=2,c=3

//完全解构
let [head, ...tail] = [1,2,3,4,5,6];
console.log(head); //1
console.log(tail); //[2,3,4,5,6]

//不完全解构(右边数组解构一部分) 左<右
let [x,y] = [1,2,3,4,5];
console.log(x)  //1
console.log(y)  //2

//解构失败  左>右
let [u, v, ...w] = ["a"];
console.log(u);  //a
console.log(v);  //undefined
console.log(w);  //[]

(4)对象的解构

let {name,age} = {name:"miny",age:18};
console.log(name)  //"miny"
console.log(age)  //18

let {sex:gender} = {sex:"girl"}  
console.log(gender); //"girl"
对象解构赋值的内部机制是先找到同名属性,然后再赋值给对应的变量,真正被赋值的是后者;例如,sex是匹配的模式,gender是变量,真正被赋值的是变量。
var node = {
loc:{
start:{
line:1,
column:5,
}
}
};
var {loc, loc:{start}, loc:{start:{line}}} = node;
console.log(line) //1
console.log(loc) //object start:{line:1, column:5}
console.log(start) //object {line:1, column:5}

(5)函数参数(对象解构的默认赋值)

  默认值生效的条件:对象的属性值严格等于undefined。

var {x=3} = {x:undefined};
console.log(x)  //3

var {y=3} = {y:null};
console.log(y)  //null
//以前
function
f(){ var a = a || 5; } //现在 function f(a = 5){}

3、字符串

3.1模板字符串

  模板字符串是增强版的字符串,用反引号(`)标识。可以在其中嵌入JavaScript变量或JS代码。

//所有模板字符串中的空格和换行都会被保留,若想删除字符串的首位空格,可使用trim()方法
//arguments是所有非箭头函数都可用的局部变量,可以使用arguments对象在函数中引用函数的参数;arguments[0]:函数的第一个参数。
// replace():该方法用于在字符串中用一些字符替换另一些字符,或者替换一个与正则表达式匹配的子串。
//     replace(regExp,替换文本或者替换文本的函数);若regExp中有全局标志g,则替换所有匹配的子串,否则,只替换第一个匹配子串;
//     第二个参数中:$2表示与regexp中的第二个子表达式相匹配的文本
let name = "Doe, John";
let name2 = name.replace(/(\w+)\s*, \s*(\w+)/, "$2 $1");
console.log(name2) // John Doe
// eval():可以计算某个字符串,或者执行其中的JavaScript代码。
const name = "小强";
const age = 100;
const str = '${name},突然变成${age}了!';
const replacer = function(){
console.log('match', arguments[0]); //匹配模式的字符串
console.log('$1', arguments[1]); //与模式中的子表达式(分组)匹配的字符串,可以有 0 个或多个这样的参数;/(正则)(.+?)(式)/,"《$1》$2<$3>"
console.log('offset', arguments[2]); //接下来的参数是一个整数,声明了匹配在字符串对象中出现的位置==索引;
console.log('string', arguments[3],'\n'); //最后一个参数是字符串本身。
return eval(arguments[1]); //函数返回字符串,并计算字符串的值;
};

const _str1 = str.replace(/\$\{([^}]+)\}/g, replacer);
console.log(_str1); //小强,突然变成100了!

 

 

3.1.0带标签的模板字符串

 

3.2  includes()方法:判断某个字符串中是否包含某个字符串

  startsWith()、endsWith()方法:判断某个字符串是否以某个子串开始、结束。

const str = 'abcdminyxyz';
console.log(str.includes('miny'))  //true
console.log(str.endsWith('a')); //false
console.log(str.startsWith('ab')); //true

4、函数

4.1函数的参数:可赋值(设置默认值)、可解构

function fun({x=2, y='默认值', z='默认值'} = {x:100,y:undefined,z:null}){
        console.log(x,y,z)
}
fun(); //100 "默认值" null

4.2箭头函数

(1)如果参数只有一个,可省略小括号;(2)如果不写return,可以不写花括号{ };(3)没有arguments变量;(4)不改变this指向

let sum = (a,b) => a+b;
console.log(sum(1,2))  //3

5、数组:数组新方法

    // Array.from():将类数组转化为数组
    var obj = {"0":'a',"1":'b',"2":'c',length:3};
    let arr = Array.from(obj);
    console.log(arr); //["a", "b", "c"]

    // Array.of():创建数组
    let arr1 = Array.of(1,2,3);
    console.log(arr1) //[1, 2, 3]

    // Array.fill(value,start,end):填充数组
    let arr2 = [1,2,3,4,5,6]
    arr2.fill(7,3,5)
    console.log(arr2); //[1, 2, 3, 7, 7, 6]

    // Array.includes():判断数组是否有某值
    let arr3 = [1,2,3,4,5]
    console.log(arr3.includes(100)); //false
    console.log(arr3.includes(1));  //true

    // Array.find():查找符合条件的第一个返回值
    let arr4 = [1,2,3,4,5,6,7,8,9]
    let res = arr4.find(function (item) {
        return item > 4;
    })
    console.log(res); // 5

    // Array.filter():数组过滤,筛选出符合条件的元素
    let arr5 = [1,2,3,4,5,6,7,8,9];
    let arr5Res = arr5.filter(function (ele,index) {
        return index > 5;
    })
    console.log(arr5Res); //[7, 8, 9]
    let arr5Res2 = arr5.filter(function (ele,index) {
        return ele > 4;
    })
    console.log(arr5Res2); //[5, 6, 7, 8, 9]

    // 累加器 Array.reduce(function(total, currentValue, currentIndex, arr){}, initialValue)
    let arr6 = [1,2,3,4];
    let arr6Res = arr6.reduce(function(total, currentValue, currentIndex, arr){
        return total + currentValue;
    }, 100);
    console.log(arr6Res); //110

6、对象

 

7、class类

8、Generator

 (1)迭代器函数:在普通函数名前加星号*

function *fun() {}

(2)yield 退让

generator函数并不会自动执行,调用generator函数,会返回一个遍历器对象,代表generator内部的指针;以后每次调用遍历器对象的next()方法,都会返回一个包含value和done属性的对象;value值代表当前状态内部状态值,done值为布尔值,代表当前遍历是否结束。

迭代器函数中,遇到yield 暂停中止执行,遇到迭代器的next()方法继续执行;

    function *fun() {
        let [a,b,c] = [1,2,3]
        yield a;
        yield b;
        return c;
    }

    let res = fun(); //res是一个迭代器对象Iterator
    console.log(res.next())    //{value: 1, done: false}
    console.log(res.next())    //{value: 2, done: false}
    console.log(res.next())    //{value: 3, done: true}
   console.log(res.next())    //{value: undefined, done: true}
  或者:

  let res = fun();
  function next() {
      let {value,done} = res.next();
      console.log(value);
      if(!done){
          next();
      }
  }
  next(); //1   2   3

如何往迭代器里面传值?

    function *fun() {
        let a = yield '第一个yield表达式';
        console.log(a);
        let b = yield '第二个yield表达式';
        console.log(b);
    }
    let res = fun(); //返回迭代器对象
    console.log(res.next());          //{value: "第一个yield表达式", done: false}
    console.log("========================================")
    console.log(res.next('参数1'));   //参数1  //{value: "第二个yield表达式", done: false}
    console.log("========================================")
    console.log(res.next('参数2'));   //参数2  //{value: undefined, done: true}
    console.log("========================================")
    console.log(res.next());         //{value: undefined, done: true}

 

 

 

9、async  await

   async 用来修饰函数,需要配合await使用;await后只能跟promise使用。

    async function initPerson(){
        let params = {
            name:'miny'
        };
        let res = await initPersonInterface(params);
        console.log(res);
    }

 在JavaScript的世界中,所有的代码都是单线程执行的。由于这个“缺陷”,导致JavaScript所有的网络操作、浏览器事件,都必须是异步执行的。promise是异步编程的一种方式,比传统的解决方案(回调函数与事件)更合理、更强大。

回调:是指一个函数作为参数传递到另一个函数中,并在另一个函数执行结束后执行。

异步回调:是由于JS的单线程,在很多情况下(ajax请求远程数据,IO等),非常耗时。如果一直单线程的堵塞下去,会导致程序等待时间过长页面失去响应,影响用户体验。为解决这个问题,我们将耗时间的都扔给异步去做,做好了再通知我们,再拿着数据往下走。

传统的异步编程(回调函数与事件)缺点:“回调地狱”,有太多的异步步骤需要一步一步执行,或者一个函数里面有太多异步操作,这就产生大量的嵌套的回调,使代码嵌套太深而难以阅读与维护。promise解决了这一问题。

promise原理

(1)对象的状态不受外界影响。promise对象代表一个异步操作,有3种状态:pending(进行中)、fulfilled(已完成)、rejected(以失败)。只有异步操作的结果可以决定当前处于哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变就不会再改变了,任何时候都可以得到这个结果。promise的状态改变只有两种可能:从pending到fulfilled;从pending到rejected。具体流程如下:

 

Promise的使用:

    function loadImg(src) {
        //1、new Promise一个实例对象,并且将该实例return,作为then方法回调函数的参数,本例中是img
        //2、该实例对象接受一个函数作为参数,该函数的有两个参数,resolve和reject,它们也是两个函数,由JS引擎提供,不需要自己部署
        //3、成功时执行resolve函数,失败时执行reject函数
        const promise = new Promise(function (resolve,reject) {
            var img = document.createElement('img');
            img.onload = function () {
                resolve(img)  //成功时执行resolve函数
            }
            img.onerror = function () {
                reject()    //失败时执行reject函数
            }
            img.src = src;
        })
        return promise;
    }
    var src = "http://www.imooc.com/static/img/index/logo_new.png";
    var result = loadImg(src);
    //4、then()监听结果;第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数
    result.then(function (img) {
        console.log(img.width);//resolve(成功)时候的回调函数
    },function () {
        console.log("failed");//rejected(失败)时候的回调函数
    })

async函数

(1)async函数返回一个promise对象,可以用then(callback)添加回调函数。当函数执行的时候,遇到await会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

(2)async关键字,表明该函数内部有异步操作,调用该函数会立即返回一个promise对象。

promise题目:关于JavaScript执行机制的

promise构造函数是立即执行的
const first = () => (new Promise((resolve,reject)=>{ console.log(3); let p = new Promise((resolve, reject)=>{ console.log(7); setTimeout(()=>{ console.log(5); resolve(6); },0) resolve(1); }); resolve(2); p.then((arg)=>{ console.log(arg); }); })); first().then((arg)=>{ console.log(arg); }); console.log(4); 链接:https://juejin.im/post/5af800fe518825429c594f92

 

八、浏览器

1、从URL输入到显示页面,发生了什么?

第一步:客户机提出域名解析请求,并将该请求发送给本地的域名服务器。
第二步:当本地的域名服务器收到请求后,就先查询本地的缓存,如果有该纪录项,则本地的域名服务器就直接把查询的结果返回。
第三步:如果本地的缓存中没有该纪录,则本地域名服务器就直接把请求发给根域名服务器,然后根域名服务器再返回给本地域名服务器一个所查询域(根的子域)的主域名服务器的地址。
第四步:本地服务器再向上一步返回的域名服务器发送请求,然后接受请求的服务器查询自己的缓存,如果没有该纪录,则返回相关的下级的域名服务器的地址。
第五步:重复第四步,直到找到正确的纪录。

第2种解释:

一般会经历以下几个过程:

1、首先,在浏览器地址栏中输入url

2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。

3、在发送http请求前,需要域名解析(DNS解析)(DNS(域名系统,Domain Name System)是互联网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住IP地址。),解析获取相应的IP地址。

4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。(TCP即传输控制协议。TCP连接是互联网连接协议集的一种。)

5、握手成功后,浏览器向服务器发送http请求,请求数据包。

6、服务器处理收到的请求,将数据返回至浏览器

7、浏览器收到HTTP响应

8、读取页面内容,浏览器渲染,解析html源码

9、生成Dom树、解析css样式、js交互

10、客户端和服务器交互

11、ajax查询
 
原文链接:https://blog.csdn.net/xm1037782843/article/details/80708533

 九、问题

1、let arr = JSON.parse(JSON.stringify(this.sealTableData[index])); //对JSON对象实现深拷贝,开辟一个新的存储地址,两个对象彼此新增、删除元素,互不影响;

2、申请发起失败,input表单输入无限制,后台数据库存不进数据,报错;对表单进行限制。

3、文件上传过程,点击复制或者新增一行,表格错位;原因:数据未请求过来网页没有刷新,文件上传前beforeUpload,设置页面加载this.loading=true;文件上传成功或者失败的回调函数中,设置this.loading=false,页面加载关闭,进行下面操作。

4、

 十、git

 

十一、webpack

 项目创建、文件打包

零、其他

 

原文:

https://juejin.im/post/5b037b536fb9a07aa9260b39#heading-32

https://juejin.im/post/5abf531d6fb9a028dc412419#heading-28

posted @ 2020-06-07 21:21  红桃七716  阅读(248)  评论(0)    收藏  举报