# js高級(jí)知識(shí)點(diǎn)
##? 線程
- 一個(gè)線程一次只能處理一件事情,多個(gè)線程可以多個(gè)事情同是進(jìn)行惕橙。
**js中瞧甩,分三個(gè)任務(wù)**
- 渲染任務(wù)
- js代碼執(zhí)行任務(wù)
- 事情處理任務(wù)
**js代碼執(zhí)行順序**
- 先把主任務(wù)(代碼任務(wù))執(zhí)行完畢
- 再去執(zhí)行次要任務(wù)(包括setTimeOut 和 setInterval中的回調(diào)函數(shù)中的代碼,這兩個(gè)都屬于宏任務(wù)弥鹦,promise中的then屬于微任務(wù))
**setTimeOut**
- 至少在指定的時(shí)間后執(zhí)行回調(diào)函數(shù)
- 因?yàn)橐戎魅蝿?wù)中的代碼執(zhí)行完畢之后才回去檢查肚逸,setTimeOut的回調(diào)函數(shù),有沒(méi)有到執(zhí)行時(shí)間
## 閉包
閉:閉合彬坏,關(guān)閉朦促,封閉
包:包裹,包起來(lái)栓始。
一個(gè)具有封閉的對(duì)外不公開(kāi)的务冕,包裹結(jié)構(gòu),或空間
- js中的閉包就是函數(shù)
- 閉包的原理就是作用域訪問(wèn)原則:上級(jí)作用域無(wú)法訪問(wèn)下級(jí)作用域幻赚。
- 閉包要解決的問(wèn)題:1禀忆、閉包內(nèi)的數(shù)據(jù)不允許外界訪問(wèn),2落恼、要解決的問(wèn)題就是間接訪問(wèn)數(shù)據(jù)箩退。
```javascript
? ? // 例1
? ? function foo(){
? ? ? ? var num = 123;
? ? ? ? return num;
? ? }
? ? var x = foo();
? ? console.log(x)
? ? var y = foo();
? ? console.log(x===y) //這里因?yàn)槭菙?shù)值所以相等
? ? // 例2(用來(lái)說(shuō)明函數(shù)的每次調(diào)用,返回的對(duì)象都是新的佳谦,每次都不一樣)
? ? function foo(){
? ? ? ? var obj = {
? ? ? ? ? ? name: 'hyl',
? ? ? ? ? ? age:15
? ? ? ? }
? ? ? ? return obj;
? ? }
? ? var obj1 = foo();
? ? var obj2 = foo();
? ? console.log(obj1 === obj2);
```
- 常見(jiàn)的問(wèn)題
```javascript
? ? for(var i=0;i<5;i++){
? ? ? ? setTimeout(()=>{
? ? ? ? ? ? console.log(i)
? ? ? ? },0) // 5,5,5,5,5
? ? }
? ? div[i].onclick = function(){
? ? ? ? console.log(i)
? ? }
```
----
- 解決方式
```javascript
? ? for(let i=0;i<5;i++){
? ? ? ? setTimeout(()=>{
? ? ? ? ? ? console.log(i) // 0戴涝,1,2,3喊括,4,用es6的塊級(jí)作用域解決
? ? ? ? },0)
? ? }
? ? for(var i=0; i<5; i++){
? ? ? ? setTimeout((function(j){
? ? ? ? ? ? return function(){
? ? ? ? ? ? ? ? console.log(i)
? ? ? ? ? ? }
? ? ? ? })(i),0) // 0,1矢棚,2郑什,3,4,用閉包的方式解決
? ? }
? ? div[i].onclick = function(j){
? ? ? ? return function(){
? ? ? ? ? ? console.log(j)
? ? ? ? }
? ? }(i)
```
**沙箱模式**
----
? ? 原理:函數(shù)可以構(gòu)建作用域蒲肋,上級(jí)作用域不能直接訪問(wèn)下級(jí)作用域蘑拯。
-? 與外界隔絕的一個(gè)環(huán)境,外界無(wú)法修改環(huán)境內(nèi)的任何信息兜粘,沙箱內(nèi)的東西單獨(dú)屬于一個(gè)世界
-? 360 沙箱模式申窘,將軟件和操作系統(tǒng)進(jìn)行隔離,以達(dá)到安全的目的
-? 蘋(píng)果手機(jī)也是一個(gè)沙箱模式孔轴,隔離app的空間剃法,每個(gè)app都是獨(dú)立運(yùn)行的。
-? js的沙箱模式就是立即執(zhí)行函數(shù)
```javascript
? ? // 基本模式
? ? (function(){
? ? ? ? var a = 123;
? ? })()
? ? // jquery中的沙箱模式
? ? (function(win){ // window對(duì)象最好不要全局引用路鹰,因?yàn)橹苯右脮?huì)破壞沙箱原則贷洲,所以我們選擇新參的形式傳入,此時(shí)沙箱使用window對(duì)象的時(shí)候晋柱,不會(huì)進(jìn)行全局搜索window對(duì)象优构。
? ? ? ? var itcast = {
? ? ? ? ? ? getEle:function(){
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? win.itcast = itcast;
? ? }
? ? )(window)
```
- 沙箱模式一般應(yīng)用于第三方框架或者插件或者書(shū)寫(xiě)一些獨(dú)立的組件
**沙箱模式的**
- 沙箱模式使用的是IIFE(立即執(zhí)行函數(shù)),不會(huì)再外界暴露任何全局變量,也就不會(huì)造成全局對(duì)象污染雁竞。
- 沙箱模式中的所有數(shù)據(jù)钦椭,都是和外界相隔離的购对,外界無(wú)法進(jìn)行修改谍婉,也保證了代碼的安全性。
## 緩存
**緩存的作用(cache) 就是將一些常用的數(shù)據(jù)挽荠,儲(chǔ)存起來(lái)联贩,提供使用漫仆,提升性能**
- CDN(Content Delivery Network 內(nèi)容分發(fā)網(wǎng)絡(luò))
- Redis做緩存
- 網(wǎng)站靜態(tài)頁(yè)面緩存機(jī)制(將網(wǎng)頁(yè)靜態(tài)化)
**斐波那契的性能問(wèn)題**
- fib(3) = fib(1)+fib(2) fib(4) = fib(2)+ fib(3) fib(3)就重復(fù)計(jì)算了
```javascript
? ? // 優(yōu)化前
? ? let number = 1;
? ? function fib(n) {
? ? ? ? number++;
? ? ? ? if (n == 1 || n == 0) {
? ? ? ? ? ? return 1;
? ? ? ? }
? ? ? ? return fib(n - 2) + fib(n - 1)
? ? }
? ? let result = fib(30);
? ? console.log(number) //2692538 次 需要調(diào)函數(shù)的次數(shù)
? ? console.log(result) // 1346269
? ? // 優(yōu)化后
? ? let number = 1;
? ? function createCache() {
? ? ? ? let cache = [];
? ? ? ? function fib(n) {
? ? ? ? ? ? number++;
? ? ? ? ? ? if (cache[n]) {
? ? ? ? ? ? ? ? return cache[n]
? ? ? ? ? ? }
? ? ? ? ? ? if (n == 1 || n == 0) {
? ? ? ? ? ? ? ? cache[n] = 1;
? ? ? ? ? ? ? ? return 1;
? ? ? ? ? ? }
? ? ? ? ? ? let temp = fib(n - 2) + fib(n - 1);
? ? ? ? ? ? cache[n] = temp
? ? ? ? ? ? return temp;
? ? ? ? }
? ? ? ? return fib;
? ? }
? ? let fib = createCache();
? ? let result = fib(30);
? ? console.log(number) //60 需要調(diào)函數(shù)的次數(shù)
? ? console.log(result) // 1346269
```
**jquery 緩存分析**
- $('#test'),如果緩存中有這個(gè)值的話,就不會(huì)重新去document.getElementById,
```javascript
? ? function createCache(){ // 自己的版本
? ? ? ? var cache = {}; // cache對(duì)象中以鍵值對(duì)形式進(jìn)行存儲(chǔ)數(shù)據(jù)
? ? ? ? var index = []; // inde數(shù)組中該存儲(chǔ)健泪幌,這個(gè)健是有順序盲厌,可以方便我們做超出容量的處理
? ? ? ? return function(key,value){
? ? ? ? ? ? if(value){
? ? ? ? ? ? ? ? cache[key] = value;
? ? ? ? ? ? ? ? index.push(key);
? ? ? ? ? ? ? ? if(index>10){
? ? ? ? ? ? ? ? ? ? delete cache[index.shift()]
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return cache[key]
? ? ? ? }
? ? }
? ? // 調(diào)用
? ? let cache = createCache();
? ? cache('name','hyl');
? ? console.log(cache('name'))
```
- jquery自身的版本
```javascript
? ? function createCache(){
? ? ? ? var keys = [];
? ? ? ? function cache(key,value){
? ? ? ? ? ? if(keys.push(key+' ')>50){
? ? ? ? ? ? ? ? delete cache[key+' ']
? ? ? ? ? ? }
? ? ? ? ? ? return (cache[key+' '] = value)
? ? ? ? }
? ? ? ? return cache;
? ? }
? ? let cache = createCache();
? ? cache('name','hyl');
? ? cache['name'+ ' ']
```
## 函數(shù)的調(diào)用方式
- 函數(shù)調(diào)用模式
- 方法調(diào)用模式
- 構(gòu)造函數(shù)模式
- 上下文調(diào)用模式
```javascript
? ? function test(){
? ? ? ? console.log(this) // this指向window;
? ? }
? ? test();
? ? var obj = {
? ? ? ? test:function(){
? ? ? ? ? ? console.log(this)
? ? ? ? }
? ? }
? ? obj.test(); // this指向 obj
? ? function Person(){
? ? ? ? console.log(this)
? ? }
? ? new Person(); // this指向 Person對(duì)象
? ? test.call(obj,argument1,argument2);
? ? test.apply(obj,[argument1,argument2]);
? ? test.bind(obj,argument1,argument2)();
```
**構(gòu)造函數(shù)調(diào)用模式特征**
- 構(gòu)造函數(shù)的首字母需要大寫(xiě)
- 一般情況下和new關(guān)鍵字一起使用
- 構(gòu)造函數(shù)中的this指定是new關(guān)鍵字創(chuàng)建出來(lái)的對(duì)象
- 默認(rèn)的返回new創(chuàng)建出來(lái)的對(duì)象
- 構(gòu)造函數(shù)的返回值:默認(rèn)返回new創(chuàng)建出來(lái)的,如有返回祸泪,如返回值類型的數(shù)據(jù)(包括null)沒(méi)有影響吗浩,若是對(duì)象模型,則返回這個(gè)對(duì)象没隘,不會(huì)返回原來(lái)創(chuàng)建出來(lái)的對(duì)象懂扼。
```javascript
? ? // 構(gòu)造函數(shù)
? ? function Person(){
? ? ? ? this.name = 'hyl'
? ? }
? ? var p = new Person();
? ? // 工廠模式的構(gòu)造函數(shù)
? ? function Person(name,age){
? ? ? ? var o = {
? ? ? ? ? ? name:name,
? ? ? ? ? ? age:age,
? ? ? ? ? ? sayHello:function(){
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? var p = Person('張三',18);
? ? // 寄生式構(gòu)造函數(shù)
? ? function Person(){
? ? ? ? var o = {
? ? ? ? ? ? name:name,
? ? ? ? ? ? age:age,
? ? ? ? ? ? sayHello:function(){
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return o;
? ? }
? ? var p = new Person('張三',16);
```
## js上下文
**js中的上下文(執(zhí)行環(huán)境)**
- 字面意思:上面的文字,下面的文字阀湿。
- call,apply,bind可以改變this的值赶熟,
- 函數(shù).apply(對(duì)象,[argument1,argument2])
- 函數(shù).call(對(duì)象,argument1,argument2);
- 函數(shù).bind(對(duì)象,argument1,argument2).()
---
**call和 apply的區(qū)別**
1. 第一個(gè)參數(shù)都是把this修改為對(duì)象
2. 當(dāng)函數(shù)需要參數(shù)的時(shí)候,那么apply是用數(shù)組的形式進(jìn)行傳遞或者類數(shù)組陷嘴,call是是用單個(gè)參數(shù)進(jìn)行傳遞
3. 而call是使用單個(gè)參數(shù)進(jìn)行傳遞
call用于參數(shù)確定個(gè)數(shù)的時(shí)候使用
apply是用于新參不確定的時(shí)候使用
```javascript
? ? // 用apply求數(shù)組的最大值
? ? let array = [1,23,2];
? ? let result = Math.max.apply(null,array)
? ? console.log(result) //23
? ? //
? ? function foo(){
? ? ? ? [].join.apply(argument,['-'])
? ? }
? ? foo(2,1,3) // 2-1-3
```
知識(shí)點(diǎn)總結(jié)
## 閉包練習(xí)
? ? setTimeout的執(zhí)行時(shí)機(jī)
? ? ? ? 所有的主任務(wù)的代碼執(zhí)行完畢之后映砖,去檢查所有的setTimeout回調(diào)函數(shù),如果到時(shí)間了就執(zhí)行
? ? 用閉包來(lái)解決回調(diào)函數(shù)在調(diào)用的時(shí)候訪問(wèn)的是全局的變量
? ? 在閉包中創(chuàng)建一個(gè)變量灾挨,來(lái)單獨(dú)存儲(chǔ)當(dāng)前的回調(diào)函數(shù)需要的數(shù)據(jù)邑退,
? ? 在調(diào)用的時(shí)候就會(huì)去使用這個(gè)單獨(dú)的數(shù)據(jù),而不是去訪問(wèn)全局變量
? ? 注冊(cè)點(diǎn)擊事件的時(shí)候
? ? 點(diǎn)擊事件在觸發(fā)的時(shí)候訪問(wèn)的是全局的變量
? ? 在閉包中創(chuàng)建一個(gè)變量劳澄,來(lái)單獨(dú)存儲(chǔ)當(dāng)前的事件處理函數(shù)需要的數(shù)據(jù)地技,
? ? 在調(diào)用的時(shí)候就會(huì)去使用這個(gè)單獨(dú)的數(shù)據(jù),而不是去訪問(wèn)全局變量
## 閉包緩存
? ? 緩存:將常用的數(shù)據(jù)進(jìn)行存儲(chǔ)秒拔,以提升性能
? ? 硬件緩存
? ? 瀏覽器緩存
? ? CDN
? ? 內(nèi)存型數(shù)據(jù)庫(kù)
? ? 如何用閉包實(shí)現(xiàn)緩存
? ? 1莫矗、寫(xiě)一個(gè)閉包在閉包中創(chuàng)建一個(gè)對(duì)象,用來(lái)做緩存的存儲(chǔ)對(duì)象
? ? 2砂缩、在閉包中創(chuàng)建一個(gè)對(duì)象趣苏,用來(lái)做緩存的存儲(chǔ)對(duì)象
? ? 3、在閉包中創(chuàng)建一個(gè)數(shù)組梯轻,用來(lái)存儲(chǔ)換中的鍵
? ? 4食磕、返回一個(gè)函數(shù),這個(gè)函數(shù)需要兩個(gè)參數(shù)喳挑,一個(gè)是key 一個(gè)是value
? ? 5彬伦、在返回的函數(shù)中,判斷傳入的value是否為undefined
? ? 6、如果為Undefined 則表示是獲取值伊诵,就直接返回在第一步創(chuàng)建的緩存對(duì)象中指定的鍵對(duì)應(yīng)的值
? ? 7单绑、如果不為Undefined 則表示是設(shè)置值
? ? 8、在緩存對(duì)象中設(shè)置指定的key的值為value
? ? 9曹宴、把key加入存儲(chǔ)key的數(shù)組
? ? 10搂橙、判斷key數(shù)組是不是超出了緩存大小限制
? ? 11、如果超出限制笛坦,刪除數(shù)組第一個(gè)元素(使用shift)区转,獲取到刪除的key
? ? 12、使用刪除的key刪除緩存對(duì)象中存儲(chǔ)的值(delete)
## 使用緩存解決斐波那契數(shù)列的性能問(wèn)題
? ? 就是將已經(jīng)計(jì)算過(guò)的數(shù)字緩存進(jìn)一個(gè)數(shù)組中版扩,下次再來(lái)訪問(wèn)的時(shí)候废离,直接在數(shù)組中進(jìn)行查找,如果找到直接使用礁芦,如果沒(méi)有找到蜻韭,計(jì)算后將數(shù)字存入數(shù)組悼尾,然后返回該數(shù)字
## 沙箱模式
? ? 沙箱模式就是一個(gè)封閉的獨(dú)立的環(huán)境
? ? 沙箱模式的基本模型
? ? (function(){
? ? ? ? //變量定義
? ? ? ? //邏輯代碼
? ? ? ? //如果需要,向window對(duì)象添加成員肖方,以暴露接口
? ? })()
? ? 第三方框架
? ? 插件
? ? 獨(dú)立的組件
## 函數(shù)的四種調(diào)用模式
函數(shù)模式
? ? this--->window
方法模式
? ? this---->調(diào)用方法的對(duì)象
構(gòu)造函數(shù)模式
? ? this----->new出來(lái)的對(duì)象
? ? 工廠模式
? ? 寄生模式
上下文模式
? ? this----->指定的是誰(shuí)就是誰(shuí)
? ? call? 函數(shù).call(對(duì)象,arg1,arg2,arg3,...argn)
? ? apply? 函數(shù).apply(對(duì)象,數(shù)組)
? ? ? ? 都可以用來(lái)改變this的指向?yàn)閰?shù)的第一個(gè)值
? ? ? ? call是使用單獨(dú)的每一個(gè)參數(shù)來(lái)傳參
? ? ? ? apply是使用數(shù)組進(jìn)行傳參的闺魏,這個(gè)數(shù)組在調(diào)用的時(shí)候,會(huì)被意義拆解俯画,當(dāng)做函數(shù)的每一個(gè)采參數(shù)
? ? call在函數(shù)的形參個(gè)數(shù)確定的情況下使用
? ? apply在函數(shù)的形參個(gè)數(shù)不確定的情況下使用