Javascript 总结

2020-11-27

一. 闭包

就是一个函数,可以 访问并操作 其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

实例

1
2
3
4
5
6
7
8
9
10
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
//f2函数,就是闭包

参考链接


二. 对象

JavaScript 中的所有事物都是对象:字符串、数字、数组、日期,等等。
在 JavaScript 中,对象是拥有属性和方法的数据。

实例
当您像这样声明一个 JavaScript 变量时:var txt = "Hello";
您实际上已经创建了一个 JavaScript 字符串对象。字符串对象拥有内建的属性 length。对于上面的字符串来说,length 的值是 5。字符串对象同时拥有若干个内建的方法。

属性:
txt.length=5

方法:

1
2
3
txt.indexOf() //返回某个指定的字符串值在字符串中首次出现的位置,如果要检索的字符串值没有出现,则该方法返回 -1
txt.replace() //用于在字符串中用一些字符替换另一些字符
txt.search() //用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。如果没有找到任何匹配的子串,则返回 -1。

三. 原型 & 原型链

  1. 原型
    是一个对象,其他对象可以通过它实现属性继承。
    每一个构造函数都有一个原型,构造函数有一个prototype属性指向这个原型。

  2. 原型链
    由于proto是任何对象都有的属性。而 js 里面 万物皆对象,所以会形成一条 proto 连起来的链条。
    访问proto 必须到头,并且值为 Null。

    实例

    1
    2
    3
    4
    5
    6
    //构造函数
    var A = function(){
    key: "value"
    }
    //创建一个实例, 就是使用这个new来将构造函数实例化
    var a = new A();

    A.prototype == a.__proto__
    Image
    null

    在A函数的原型上定义属性和方法

    1
    2
    A.prototype.b = 3;
    A.prototype.bFun = function () {console.log(1)};

    继承

参考链接


四. BEM (一种 CSS 命名规则)

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由 Yandex 团队提出的一种前端命名方法论。
这种巧妙的命名方法让你的 CSS 类对其他开发者来说更加透明而且更有意义。

总结:BEM = block + element + modifier = 模块名 + 元素名 + 修改器

实例

1
2
3
4
5
6
<div class="tabs category-tabs">
<a href="#" class="tabs__item tabs__item--active">电影</a>
<a href="#" class="tabs__item">动画</a>
<a href="#" class="tabs__item">纪录片</a>
<a href="#" class="tabs__item">广告</a>
</div>
1
2
3
<div class="contact-page">
<div class="contact-page_header"></div>
</div>

五. 防抖节流 (属于性能优化的知识)

防抖
防抖的含义就是如果短时间内大量触发同一事件,只会执行一次函数。
比如当你连续点击btn的时候只执行最后一次的事件

应用场景:(最后一次)
1. 滚动条监听的例子,只有等用户停止滑动滚动条,才开始**监听浏览器滚动事件,返回当前滚条与顶部的距离**。
2. 页面resize事件,常见于需要做页面适配的时候。需要根据最终呈现的页面情况进行dom渲染(这种情形一般是使用防抖,因为只需要判断最后一次的变化情况)

节流
节流是:如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。
比如某个用户闲着无聊,按住滚动条不断的拖来拖去。

应用场景:(只执行第一次,然后一段时间内不会执行)
1. 滚动条监听的例子,按住滚动条不断的拖来拖去,事件只执行第一次,然后一段时间内不会执行,直至过了这段时间再重新执行。
2. 搜索框input事件,例如要支持输入实时搜索可以使用节流方案(间隔一段时间就必须查询相关内容),或者实现输入间隔大于某个值(如500ms),就当做用户输入完成,然后开始搜索,具体使用哪种方案要看业务需求。

参考链接

例子:
// 避免窗口在变动时出现昂贵的计算开销。
jQuery(window).on(‘resize’, _.debounce(calculateLayout, 150));

// 避免在滚动时过分的更新定位
jQuery(window).on(‘scroll’, _.throttle(updatePosition, 100));


五. 回流重绘

回流必定会触发重绘,重绘不一定会触发回流。重绘的开销较小,回流的代价较高。

回流: 又叫重排(layout)。当元素的尺寸、结构或者触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。

  1. 页面初次渲染
  2. 浏览器窗口大小改变
  3. 元素尺寸/位置/内容发生改变
  4. 元素字体大小变化
  5. 添加或者删除可见的 DOM 元素
  6. 激活 CSS 伪类(:hover……)

重绘: 当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要 UI 层面的重新像素绘制,因此损耗较少。

  1. 改变元素颜色
  2. 改变元素背景色

参考链接


六. ajax请求的五个步骤

  1. 创建XMLHttpRequest异步对象
    var xhr = new XMLHttpRequest()

  2. 设置回调函数
    xhr.onreadystatechange = callback

  3. 使用open方法与服务器建立连接 / 配置请求信息,open()

    1
    2
    3
    4
    5
    6
    // get 方式
    xhr.open("get", "test.php", true)

    // post 方式发送数据 需要设置请求头
    xhr.open("post", "test.php", true)
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")

    例如:open(method,url,async)

    method url async
    GET 文件在服务器上的位置 true(异步) false(同步)
    POST 文件在服务器上的位置 true(异步) false(同步)
    注意: 按照HTTP规范,该参数要大写;否则,某些浏览器(如Firefox)可能无法处理请求。
  4. 向服务器发送数据 / 发送请求

    1
    2
    3
    4
    5
    // get 不需要传递参数
    xhr.send(null)

    // post 需要传递参数
    xhr.send("name=jay&age=18")
  5. 在回调函数中针对不同的响应状态进行处理 / 创建回调函数

    1
    2
    3
    4
    5
    6
    7
    8
    function callback() {
    if(xhr.readyState == 4) { // 判断异步对象的状态
    if(xhr.status == 200) { // 判断交互是否成功
    var res = xhr.responseText // 获取服务器响应的数据
    res = JSON.parse(res)// 解析数据
    }
    }
    }

    服务器响应

    readyState 表示Ajax请求的当前状态
    0 代表未初始化。 还没有调用 open 方法
    1 代表正在加载。 open 方法已被调用,但 send 方法还没有被调用
    2 代表已加载完毕。send 已被调用。请求已经开始
    3 代表交互中。服务器正在发送响应
    4 代表完成。响应发送完毕
    常用状态码 含义
    200 一切正常(ok)
    302 重定向 请求的资源临时分配了新url,本次请求暂且使用新url
    403 禁止访问(forbidden)
    404 没找到页面(not found)
    500 内部服务器出错(internal service error)

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//第一步,创建XMLHttpRequest对象
var xhr = new XMLHttpRequest();
function CommentAll() {
//第二步,设置回调函数
xhr.onreadystatechange =callback;
//第三步,配置请求信息,open()
xhr.open("post", "/ashx/test/Detail.ashx?methodName=GetAllComment", true);
//post请求下需要配置请求头信息
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//第四步,发送请求,post请求下,要传递的参数放这
xhr.send("methodName = GetAllComment&str1=str1&str2=str2");
}
//第五步,创建回调函数
function callback() {
if (xhr.readyState == 4){
if (xhr.status == 200) {
//取得返回的数据
var data = xhr.responseText;
//json字符串转为json格式
data = eval(data);
// data = JSON.parse(data)
}
}
}

参考链接 1
参考链接 2


七. http https 区别

  1. HTTP 明文传输,数据都是未加密的,安全性较差; HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
  2. 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。
  3. HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
  4. 连接的端口不一样,http是80,https是443。
  5. HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

补充:
HTTP是基于TCP/IP通信协议来传递数据的(HTML 文件, 图片文件, 查询结果等)。
注意:TCP/IP有个面向连接的特性!(意义:保证数据的完整性)
让咱们生动的了解一下TCP/IP通信协议中的三次握手四次挥手:

1
2
3
4
5
6
7
8
9
10
11
12
三次握手建立连接:
🔑客户端说:嘿,服务端girl!我想和你建立连接。(打招呼)
🔒服务端说:好的呢,我听你的。
🔑客户端说:真好,那咱们开始数据交互吧(羞羞)。
.
.(进行数据交互)
.
四次挥手断开连接:
🔑客户端说:我已经和你交互完数据了,咱断开连接吧!(打招呼)
🔒服务端说:你确定断开连接嘛?(不舍)
🔒服务端又说:那你断开连接吧!
🔑客户端说:好的,那我断开连接了!

参考


八. call 和 apply 区别

  1. apply:调用一个对象的一个方法,用另一个对象替换当前对象。
    例如:B.apply(A, arr); 即A对象应用B对象的方法。

  2. call:调用一个对象的一个方法,用另一个对象替换当前对象。
    例如:B.call(A, args1,args2); 即A对象调用B对象的方法。

    实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function add(a,b){
    return a+b;
    }
    function sub(a,b){
    return a-b;
    }
    var a1 = add.apply(sub,[4,2]);  //sub调用add的方法
    var a2 = sub.apply(add,[4,2]);
    alert(a1); //6
    alert(a2); //2

    /*call的用法*/
    var a1 = add.call(sub,4,2);

九. 类的继承

  1. apply, call 继承
    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 Parent(add,net,no,teacher) {
    this.add = add;
    this.net = net;
    this.no = no;
    this.teacher = teacher
    }
    /*子类*/
    function Child(name,age,sex,id) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.id = id;
    Parent.call(this,"山东","www.baidu.com","1608","ccy"); //这个时候的Parent中的this已经被Child所代替
    // Parent.apply(this,["山东","www.baidu.com","1608","ccy"]);
    }
    var child = new Child("fangMing","18","男","10086");
    console.log(child)
    //add: "山东"
    // age: "18"
    // id: "10086"
    // name: "fangMing"
    // net: "www.baidu.com"
    // no: "1608"
    // sex: "男"
    // teacher: "ccy"
  2. 利用prototype关键字
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function Person(){ } 
    Person.prototype.hello = "hello";
    Person.prototype.sayHello = function(){
    alert(this.hello);
    }
    function Child(){ }
    Child.prototype = new Person();//这行的作用是:将Person中所有通过prototype追加的属性和方法都追加到Child,从而实现了继承
    Child.prototype.world = "world";
    Child.prototype.sayWorld = function(){
    alert(this.world);
    }
    var c = new Child();
    c.sayHello();
    c.sayWorld();

十. 数组去重

  1. ES6 Set
    1
    2
    3
    let arr = [12,43,23,43,68,12];
    let item = [...new Set(arr)];
    console.log(item);//[12, 43, 23, 68]
1
2
3
let arr1 = [1,2,3,4,5];
let arr2 = [4,5,6,7,8];
new Set([...arr1,...arr2]) //{1,2,3,4,5,6,7,8}
  1. indexOf
    1
    2
    3
    4
    5
    6
    7
    8
    var arr = [1,2,2,2,2,3,4,4,45,5,3];
    var newArr = [];
    arr.forEach(function(item,index){
    if (newArr.indexOf(item) <= 0){
    newArr.push(item)
    }
    })
    console.log(newArr) //[1, 2, 3, 4, 45, 5]
  2. hasOwnProperty,是javascript中用于检测对象是否包含某个属性的方法,返回一个布尔值。
  3. Map
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    let arr=[1,2,3,1,2,3,"a","a","b"];
    function arrayNoRepeat(arr) {
    let map = new Map();
    let result = new Array(); // 数组用于返回结果
    for (let i = 0; i < arr.length; i++) {
    if(map.has(arr[i])) { // 判断 map 中是否已有该 key 值
    map.set(arr[i], true); // 后面的true 代表该 key 值在原始数组中重复了,false反之
    } else { // 如果 map 中没有该 key 值,添加
    map.set(arr[i], false);
    result.push(arr[i]);
    }
    }
    return result;
    }
    console.log(arrayNoRepeat(arr));//[1, 2, 3, "a", "b"]

十一. forEach 和 map 区别

forEach是es3中推出的方法,
map是es5中推出的方法,目前在ie的低版本中都还有一些兼容性问题。

forEach: 不会返回执行结果,是 undefined,会改变原来数组。
Map: 会返回一个新的数组。

1
2
3
4
5
6
7
8
9
var arr = ['a','b','c','d'];
var a = arr.forEach(function(item,index,arr){ 
return 123
});
var b = arr.map(function(item,index,arr){
return 123
}); 
console.log(a); //undefined
console.log(b); //[123,123,123,123]

————————————————- 20200529 更新 ————————————————-

十二. 判断对象是否为空

1
2
3
var a = {a: 1};
JSON.stringify(a) == "{}" //false:不为空 true:为空
Object.keys(a).length //!=0:不为空 ==0:为空

十三. 浏览器内核

主流浏览器有五大款,分别是IE、Firefox、Google Chrome、 Safari 、Opera。

序号 浏览器 内核
1 IE Trident内核,也是俗称的IE内核;
2 Firefox Gecko内核,俗称Firefox内核;
3 Chrome 统称为Chromium内核或Chrome内核,以前是Webkit内核,现在是Blink内核;
4 Safari Webkit内核。
5 Opera 最初是自己的Presto内核,后来是Webkit,现在是Blink内核。

20230511 更新

1. Event Loop

众所周知,在使用javascript时,经常需要考虑程序中存在异步的情况,如果对异步考虑不周,很容易在开发中出现技术错误和业务错误。
作为一名合格的javascript使用者,了解异步的存在和运行机制十分重要且有必要;
那么,异步究竟是何方神圣呢?我们不得不提Event Loop.

Event Loop: 也叫做事件循环,是指浏览器或Node环境的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是实现异步的原理。作为一种单线程语言,javascript本身是没有异步这一说法的,是由其宿主环境提供的.

2. JS 宏任务和微任务

js 是一种单线程语言,简单的说就是:只有一条通道,那么在任务多的情况下,就会出现拥挤的情况,这种情况下就产生了 ‘多线程’
但是这种“多线程”是通过单线程模仿的,也就是假的。那么就产生了同步任务和异步任务。

微任务:Promise.then、Object.observe、MutationObserver、process.nextTick(Node.js 环境)
宏任务:script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate(Node.js 环境)

执行顺序:
(1) 先执行同步代码
(2) 遇到异步微任务则将异步微任务放入微任务队列中, 遇到异步宏任务则将异步宏任务放入宏任务队列中
(3) 当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

这里容易产生一个错误的认识:就是微任务先于宏任务执行。实际上是先执行同步任务然后在执行异步任务,异步任务是分微任务宏任务两种的。

1
2
3
4
5
6
7
8
9
10
11
12
13
setTimeout(function(){
console.log(1);
});
new Promise(function(resolve){
console.log(2);
resolve();
}).then(function(){
console.log(3);
}).then(function(){
console.log(4)
});
console.log(5);
// 2 5 3 4 1
1
2
3
4
5
6
7
8
9
10
11
12
console.log(1)
setTimeout(function() {
console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
resolve(4)
})
p.then(data => {
console.log(data)
})
console.log(3)
//1,3,4,2

3. 预请求

TODO

4. 面向对象

(Object Oriented简称OO :如C++,JAVA等语言):看名字它是注重对象的。

当解决一个问题的时候,面向对象会把事物抽象成对象的概念,就是说这个问题里面有哪些对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决。

5. 新特性

h5 新特性

1
2
3
4
<input type="date">
<input type="week">
<input type="month">
<canvas id="canvas" width="200" height="200" style="border: 1px solid #000000"></canvas>

css3新特性

1
2
3
4
flex
text-shadow
@media
border-image: url(border.png) 30 round;

6. Nodejs 和 Javascript 区别

第一,JavaScript是一门编程语言(脚本语言),而Node.js是一个平台,可以简单理解为它是JavaScript的一种执行环境。
第二,JavaScript以前是在浏览器里执行的,需要浏览器里的JavaScript引擎,Firefox有叫做Spidermonkey的引擎,Safari有JavaScriptCore的引擎,Chrome有V8的引擎,
现在有人把Chrome有V8的引擎的引擎拿出来做了包装,加入了 内置基本模块(大多用JavaScript编写),就构成了Node.js。
第三,Node.js可以说是JavaScrip的一种独立于浏览器的运行环境。

V8 是 Chrome 浏览器中的 JavaScript 引擎,经过多年的发展和优化,性能和安全性都已经达到了相当的高度。
而 Node.js 则进一步将 V8 引擎加工成可以在任何操作系统中运行 JavaScript 的平台。

7. 函数式编程

函数式编程的影子:ES6 中加入了箭头函数,Redux 引入 Elm 思路降低 Flux 的复杂性,
React16.6 开始推出 React.memo(),使得 pure functional components 成为可能,16.8 开始主推 Hook,建议使用 pure function 进行组件编写……

函数式编程有两个核心概念:
数据不可变(无副作用): 它要求你所有的数据都是不可变的,这意味着如果你想修改一个对象,那你应该创建一个新的对象用来修改,而不是修改已有的对象。
无状态: 主要是强调对于一个函数,不管你何时运行,它都应该像第一次运行一样,给定相同的输入,给出相同的输出,完全不依赖外部状态的变化。

8. HTTP状态码

1xx - 服务器收到请求。
2xx - 请求成功,如 200。
3xx - 重定向,如 302。
4xx - 客户端错误,如 404。
5xx - 服务端错误,如 500。

常见状态码:
200 - 成功。
301 - 永久重定向(配合 location,浏览器自动处理)。
302 - 临时重定向(配合 location,浏览器自动处理)。
304 - 资源未被修改。
400 -(错误请求) 服务器不理解请求的语法。
401 -(未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 -(禁止) 服务器拒绝请求。
404 - 资源未找到。
500 - 服务器错误。
502 -(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
504 - 网关超时。

ref: https://www.cnblogs.com/kumufengchun/p/14917660.html

9. BFC

块格式化上下文(Block Formatting Context,BFC)
BFC是Web页面中可视CSS渲染的一部分,是块盒子布局过程中发生区域,也是浮动元素与其他元素的交互区域。

触发BFC的条件是什么?
(1) 属于同一个BFC的两个相邻的容器上下的margin会重叠。且会取间距最大的值。
原因:两个元素都属于HTML根元素,BFC的特性1规定 “属于同一个BFC的两个相邻容器的上下margin会重叠”。

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<style>
.box{
width: 100px;
height: 100px;
background: red;
margin-bottom: 10px;
}
.box1{
width: 100px;
height: 100px;
background: blue;
margin-top: 60px;
}
</style>
<body>
<div class="box"></div>
<div class="box1">
<div class="box1-1"></div>
</div>
<script>
</script>
</body>
</html>

(2) 计算BFC高度时浮动元素也参于计算
原因:当父元素没有设置高度的时候,子元素设置的float不等于none,就会引发BFC的特性。
触发条件: 浮动元素(元素的 float 不是 none),父元素的高度塌陷。

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<style>
.box {
height: 200px;
width: 200px;
background: #ccc;
float: left;
margin: 10px

}
.container {
background-color: red;
/* 清除浮动 */
/* overflow: hidden; */
}
</style>
<body>
<div class="container">
<div class="box"></div>
<div class="box"></div>
</div>
<script>
</script>
</body>
</html>

(3) BFC的区域不会与浮动容器发生重叠
原因:左侧元素浮动,脱离了文档流。

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<style>
.box {
height: 200px;
width: 200px;
background: #ccc;
float: left;

}
.box1 {
height: 200px;
background: #f7aeae;
/* 清除浮动 */
/* overflow: hidden; */
}

.container {
}
</style>
<body>
<div class="container">
<div class="box"></div>
<div class="box1"></div>
</div>
<script>
</script>
</body>
</html>

总结
BFC是格式化上下文的一个黑盒子是CSS布局中的一个概念方法,触发BFC有很多的方式 它可以解决:margin相互重叠、浮动高度塌陷、浮动元素重叠等问题,在日常的开发中可谓必不可少。

参考: https://segmentfault.com/a/1190000039836437
官方: https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context