jquery validate,關于js的一切(updating...)

 2023-10-15 阅读 25 评论 0

摘要:1.js原型鏈 構造函數:function Person(),Person()即為構造函數 原型對象:每一個構造函數都會帶有一個Prototype屬性,該屬性為一個指針,指向了一個對象,即為原型對象。 實例對象:new Person(),new一個構造函數就會產生

1.js原型鏈

構造函數:function Person(),Person()即為構造函數
原型對象:每一個構造函數都會帶有一個Prototype屬性,該屬性為一個指針,指向了一個對象,即為原型對象。
實例對象:new Person(),new一個構造函數就會產生一個實例,實例對象有一個內部屬性_proto_,指向了原型對象。實例能夠訪問該原型對象的所有屬性和方法。
綜上:三者關系為,每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的指。即,實例通過內部指針可以訪問到原型對象,而原型對象通過constructor指針,又可以找到構造函數。(constructor實質上是實例對象的一個屬性)
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述實例對象person,繼承來自原型對象的屬性值age和name,內部屬性_proto_指向自己的原型對象(_proto_內部屬性不可訪問)。
原型對象上3個屬性(新增的action,constructor,proto),action為新增的方法(因此實例對象繼承action,能夠執行action函數),contructor即為構造函數,_proto_指向最終的原型對象即為object(在js中,任何對象的頂端都是object)。
構造函數Person實際就是個函數,而其內部屬性prototype指向自己的原型對象,而原型對象中的屬性constructor指向構造函數,并因此不斷的套圈循環 。

2.js事件循環機制

1.js是單線程的,且只有一個主線程和一個調用棧(先進后出)
在這里插入圖片描述
按照先進后出的原則,分別壓入調用棧的為,main.js(即為js代碼塊),b(),a()。所以輸出即為a,b,c。
在調用棧中,前一個函數在執行的時候,下面的函數全部需要等待前一個任務執行完畢,才能執行。當任務很多的時候,效率極其低下。因此js引入任務隊列的概念。
2.js將任務分為同步任務和異步任務
同步任務:在主線程上,前一個任務執行完后,才能執行接下里的任務。
異步任務:分為宏任務和微任務,不進入主線程,而進入任務隊列中。直到任務隊列通知主線程可以執行了,該任務才能執行。
常見宏任務有:script主代碼塊,(setTimeout,setInterval),setImmediate(NodeJs)
常見微任務有:promise,process.nextTick(NodeJs)
注:不同源的任務,會進入不同的任務隊列,上述只有setTimeout和setInterval是同源的。
在這里插入圖片描述
函數a為宏任務setTimeout,函數c為微任務Promise。
將整個script代碼塊看做是宏任務,宏任務內部執行同步任務,即b();進入b內部
遇到a宏任務push進宏任務隊列中,輸出‘b’,遇到c,Promise分為兩步,一是構造promise對象,此操作為同步,而其回調為異步,因此先輸出‘c’,再將其push進微任務隊列中,再輸出‘finish’。
執行完同步,優先執行微任務隊列,輸出’cc’。直到微任務隊列沒有任務后,
回頭看宏任務隊列只剩下一個setTimeout,執行setTimeout,輸出‘a’。再看微任務隊列中沒有任務,結束循環。
順序為 b,c,finish,cc,a。
上述即為js的事件循環機制,Event loop。
在這里插入圖片描述
在這里插入圖片描述

3.js詞法作用域

jquery validate。作用域:源程序代碼中定義變量的區域。分為靜態作用域和動態作用域
靜態作用域:也成詞法作用域,函數的作用域在函數定義的時候就決定了。
動態作用域:函數的作用域是在函數被調用的時候決定的。
在這里插入圖片描述
靜態作用域在定義函數的時候就決定了,因此即便foo()是在bar()中調用,且bar中有同名變量,foo()所輸出的value仍為1,而不是局部同名變量2。

4.js的執行上下文棧,變量對象和活動對象

執行上下文棧: js可執行代碼分為全局代碼,函數代碼,eval代碼。而當我們執行到一個函數時,所做的準備工作,即為“執行上下文”,用于管理n個執行上下文的棧即為“執行上下文棧”。

變量對象:每一個執行上下文都會分配一個變量對象,變零對象由變量和函數聲名構成。它保存了當前作用域的所有函數和變量。(只有函數聲名會被加入到變量對象中,而函數表達式并不會)
在這里插入圖片描述
在函數聲名的方式下,a會被加入到變量對象中,所以在當前作用域下能夠打印出a。
在函數表達式下,b作為變量加入到變量對象中,而_b作為函數表達式則不會加入,
因此能輸出b,而不能輸出_b。

jquery ready方法?關于全局變量的初始化: 當js編譯器開始執行的時候會初始化一個Global Object用于關聯全局的作用域。對于全局環境而言,global object就是變量對象(variable object)。變量對象對于程序而言是不可讀的,只有編譯器才有權訪問變量對象。在瀏覽器端,global object被具象成window對象,也就是說 global object === window === 全局環境的variable object。因此global object對于程序而言也是唯一可讀的variable object。

活動對象: 當函數被調用時,一個活動對象就會被創建并且分配給執行上下文
活動對象由特殊對象argument初始化而成,隨后,他被當做變量對象用于變量初始化。
在這里插入圖片描述
如上圖代碼,當a被調用時,在a的執行上下文會創建一個活動對象AO,并且被初始化為AO = [arguments],隨后AO又被當做變量對象VO進行變量初始化,此時VO = [arguments].concat([name,age,gender,b]);

執行過程
1.進入執行上下文
2.代碼執行。
在進入執行上下文前,正如之前所說的會創建一個活動對象AO,這個AO被初始化為
在這里插入圖片描述
如果有傳入實參,則有值,反之,則為undefined。
在進入上下文時,此時的AO(活動對象) === VO(變量對象 )。
變量對象會包括:
1.函數的所有形參 (如果是函數上下文):
由名稱和對應值組成的一個變量對象的屬性被創建
沒有實參,屬性值設為 undefined
2.函數聲明:
由名稱和對應值(函數對象(function-object))組成一個變量對象的屬性被創建
如果變量對象已經存在相同名稱的屬性,則完全替換這個屬性
3.變量聲明:
由名稱和對應值(undefined)組成一個變量對象的屬性被創建;
如果變量名稱跟已經聲明的形式參數或函數相同,則變量聲明不會干擾已經存在的這類屬性

js跳出foreach循環,舉個例子
在這里插入圖片描述

在執行時的AO = {									arguments:{0:1,length:1}a:1,b:undefined,c:reference to function c(){},		d:undefined
}
在執行后的AO = {arguments:{0:1,length:1}a:1,b:3,c:reference to function c(){},d:reference to FunctionExpression "d"
}

解釋:執行foo(1)時,在創建AO時,已經將形參a的值賦值,因此a的值初始化為1。
遇到變量聲明,添加變量名–undefined;
遇到函數聲明,添加函數名–function-object;
(由于d為函數表達式并非函數聲明,因此初始化時將被視為變量聲明,而非函數聲明)。

總結:
1.全局上下文的變量對象初始化是全局對象

2.函數上下文的變量對象初始化只包括 Arguments 對象

3.在進入執行上下文時會給變量對象添加形參、函數聲明、變量聲明等初始的屬性值

4.在代碼執行階段,會再次修改變量對象的屬性值

function foo() {console.log(a);a = 1;
}foo(); // a is not definedfunction bar() {a = 1;console.log(a);
}
bar(); // 1執行foo,輸出a時,a還未被聲明,因此AO中并沒有a這個屬性名,所以報錯 a is not defined。
執行bar,輸出a時,a已經被聲明,因此輸出為1。
將foo修改為
function foo() {console.log(a);var a = 1;
}
foo的輸出為undefined。這是由于var關鍵字具有變量提升,實際上foo為
function foo() {var a;console.log(a);a = 1;
}
因此,在初始化AO時,加入了a這個變量名,對應的值為undefined。而在執行時,按照從上而下的順序,輸出a時
a并沒有被賦值為1,因此輸出為undefined。
同理,將var改為letconst,仍為報錯,即AO中不存在a這個屬性,因為他們不具備變量提升,只有var有。
console.log(foo);function foo(){console.log("foo");
}var foo = 1;
//輸出為函數foo。
執行上下文時,優先處理函數聲明,再處理變量聲明,所以上述代碼為:
var foo;
foo = function(){console.log("foo")
}
foo = 1;
其實就是變量聲明要讓著函數聲明,即使名字一樣,也不能覆蓋。
但同名變量聲明會覆蓋之前的,同名函數聲明也會覆蓋之前的。

4.5 .對執行上下文的補充和總結

在4中,我主要是是對執行上下文的內部做的總結以及代碼測試,所以導致內容過長,理解不清晰,在4.5重新對執行上下文做一個更加明確的定義。

  1. 瀏覽器首次加載腳本,它將創建全局執行上下文,并壓入執行棧棧頂(不可被彈出)
  2. 然后每次進入其他作用域都將創建對應的執行上下文并把它壓入執行棧的頂部
  3. 一旦對應的上下文執行完畢,就從棧頂彈出,并將上下文控制權交給當前的棧
  4. 這樣依次執行,最后回到全局執行上下文

執行上下文包括

  1. 變量對象
  2. 作用域鏈
  3. this(this是執行上下文環境的屬性,不是變量對象的屬性)
    1. this沒有類似于變量一樣一個向上搜尋的過程
    2. 代碼中有this,這個this就直接從當前上下文直接拿,不會從作用域鏈中尋找
    3. this的值取決于進入上下文的情況
    4. 對于global context(全局上下文),this就是全局對象
    5. 對于function context,this的指向會根據每次函數的調用而變化。this由每次的caller提供,caller是通過表達式[call expression]產生,也就是這個函數如何被激活調用的。

5.js的閉包

js的閉包其實就是:閉包是指那些能夠訪問自由變量的函數
ECMAScript中,閉包指的是:
1.從理論角度:所有的函數。因為它們都在創建的時候就將上層上下文的數據保存起來了。哪怕是簡單的全局變量也是如此,因為函數中訪問全局變量就相當于是在訪問自由變量,這個時候使用最外層的作用域。
2.從實踐角度:以下函數才算是閉包:
I.即使創建它的上下文已經銷毀,它仍然存在(比如,內部函數從父函數中返回)
II.在代碼中引用了自由變量

var scope = "global scope";
function checkscope(){var scope = "local scope";function f(){return scope;}return f;
}var foo = checkscope();
foo();
執行過程:
1.進入全局代碼,創建全局上下文,壓入執行上下文棧
2.全局執行上下文初始化
3.執行checkScope函數,創建checkScope函數執行上下文,checkScope執行上下文被壓入執行上下文棧
4.checkScope上下文初始化,創建變量對象,作用域鏈,this5.checkScope函數執行完畢,checkScope執行上下文被執行上下文棧中彈出
6.執行f函數,創建f函數執行上下文,f執行上下文被壓入執行上下文棧
7.f執行上下文初始化,創建變量對象,作用域鏈,this8.f函數執行完畢,f函數執行上下文從上下文棧中彈出。當執行f函數時,checkScope函數上下文已經從執行上下文棧中彈出,
理論上f是讀不到checkScope作用域下的scope值。
而f上下文實際上維護著作用域鏈
fContext = {scope:[AO,checkScopeContext.AO,globalContext.VO]
}
這條作用域鏈,會讓f從自己的AO出發,直到globalContext.VO,直到找到scope這個值停止。
如果checkScope.AO中不存在scope,那它就會訪問到globalContext.VO中的scope(即global scope)
即便是checkScopeContext被銷毀,其AO仍將保存在f函數的作用域鏈中。
這實際上就是閉包。

舉個例子

var data = [];for (var i = 0; i < 3; i++) {data[i] = function () {console.log(i);};
}data[0]();
data[1]();
data[2]();
//
data[0]的上下文為:
data[0]Context = {Scope:[AO,globalContext.VO]
}
在這個function內,并沒有定義i,因此它會找到globalContext.VO中的i,
但我們知道只有當執行上下文的時候,function內i的值才會被賦值 ,而此時globalContext.VO.i = 3了,
所以data[0],data[1],data[2]所有的輸出均為3。此時你可認為全局變量i即為自由變量。
那么如何達到我們想要的效果呢?
很簡單,就是在其兩者中間創造一個自由變量
var data = [];for (var i = 0; i < 3; i++) {data[i] = (function (i) {return function(){console.log(i);}})(i);
}
其中后面加了(i)代表了我執行了這個匿名函數,并傳入了初始值i,
也就是匿名函數在for循環內已經在不斷創建上下文,并擁有 i:i鍵值對。
因此他兩者就形成了一個閉包。
data[0]Context = {Scope:[AO,匿名函數的上下文.AO,globalContext.VO]
}

6.js的this

簡單來說,this永遠指向一個對象,且永遠指向其直接調用者。
1.在非嚴格模式下,this默認指向window,而嚴格模式下,this為undefined。
2.作為對象調用,指向直接調用的對象
3.作為函數調用,在非嚴格模式下指向window
4.在new操作符下,指向創造的實例對象
5.可被apply,bind,call改變指向obj。

7.js的函數柯里化,偏函數,惰性函數

函數柯里化:柯里化是將一個多參數函數轉換成多個單參數函數,也就是將一個 n 元函數轉換成 n 個一元函數。
偏函數:局部應用則是固定一個函數的一個或者多個參數,也就是將一個 n 元函數轉換成一個 n - x 元函數。
惰性函數:用于優化被多次調用的函數

var t;
function foo() {if (t) return t;t = new Date()return t;
}
上述代碼缺陷:污染全局變量,且每次調用都要進入if語句判斷
1.使用閉包
var foo = (funciton({var t;return fuction(){if (t) return t;t = new Date()return t;}
})()
缺陷:每次仍然需要調用if語句判斷
2.使用惰性函數
var foo = function() {var t = new Date();foo = function() {return t;};return foo();
};
在函數內部重寫函數,即形成了閉包,避免污染了全局,
同時也保證了每次調用不用進行if判斷,因為返回的是foo函數,而非 t。

8.js的callee和caller到底是個啥

callee是arguments的屬性,他是正在執行的函數的引用。
caller是調用該函數的函數的引用,也就是this的指向。

9.js的defineProperty和proxy

Object.defineProperty(obj, prop, descriptor)(ES5):

  • 該方法可在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,并返回這個對象。
  • 對于每一個屬性,都有數據描述符和存取描述符兩種方式,且只能是其中一種。
  • 對于所添加的每一個屬性,其都可為該屬性添加getter,setter方法。例如:`
  var obj = {};var value  = null;Object.defineProperty(obj,"count",{configurable:true,      //描述符可修改?enumerable:true,        //對象可枚舉?//數據描述符value:1,                //初始值writable:false,         //該屬性可被賦值運算符修改?//存取描述符get:function(){console.log('get 了');return value;},set:function(val){console.log('set 了');value = val;}})obj.count = 5;console.log(obj.count);這里以存取描述符為例(因為我們要對其進行監聽)可以看到當我們給count賦值,調用了set方法;輸出count,調用了get方法。由此可見,當我們使用或者修改count屬性的時候,則都可以執行一些自定義操作,這就是監聽。當然,監聽屬性的變化有啥用呢?現假設有一個需求,當我們點擊一次button,lablel的數值就+1
 <div id = "demo">1</div><button id = 'button'>+</button><script>document.getElementById('button').addEventListener('click',function(){var num = + document.getElementById('demo').innerHTMLdocument.getElementById('demo').innerHTML = num + 1;});</script>我們可能很容易想到這樣去做,但是如果改成defineProperty呢<div id = "demo">1</div><button id = 'button'>+</button><script>var obj = {};var value  = null;Object.defineProperty(obj,"count",{ get:function(){return value;},set:function(val){value = val;document.getElementById('demo').innerHTML = value;}})document.getElementById('button').addEventListener('click',function(){obj.count +=1;});</script>這就是vue2.0的響應式的原理。

proxy(es6):

  • 和defineProperty不同,proxy可以定義多種攔截行為,且代理的是整個對象,而不是屬性
  var obj = {}var proxy = new Proxy({},{get: function(obj, prop){console.log('get 了')return obj[prop];},set: function(obj, prop, value){console.log('set 了');obj[prop] = value;}});proxy.name = 10;console.log(proxy.name);這里很容易看出區別,proxy實際上是創建了一個實例。而且我監聽不再是一個單一的屬性,而是整個對象,對象內的任意一個屬性發生改變,都可以執行回調。

10.箭頭函數和普通函數的區別

箭頭函數,其實就是普通函數的簡化版,其實也是匿名函數

  1. 不能作為構造函數,不能被new
  2. 不綁定arguments,用rest參數代替
  3. 不綁定this,以其上層上下文的this代替。指向箭頭函數定義時所處的對象,而不是箭頭函數使用時所在的對象,默認使用父級的this

11.前端構建工具Webpack

Webpack是一種前端資源構建工具。它主要功能就是分析模塊依賴,并將項目文件打包成靜態資源。

  • 編譯開發環境的代碼,生成兼容性代碼。(例如babel編譯es6的語法)
  • 分析模塊依賴,將零散的模塊文件打包合并。

基本工作流程:

  1. 初始化參數。根據配置文件初始化配置
  2. 初始化編譯。加載配置的插件,初始化編譯器。
  3. 確定入口。將配置文件中標記的每一個入口起點作為構建一個依賴圖的起點。
  4. 模塊編譯與依賴分析。從每一個入口起點出發,根據引用關系(import,require等)遞歸構建依賴圖。
  5. 打包分塊。將每一個依賴圖合并為一個或多個分塊(chunk),分塊中包含對應的資源。
  6. 輸出。將打包的chunk組創建為對應的bundle,生成到目標位置。
基本配置
module.export = {mode: 'production',   // 設置模式為生產環境entry: './index.ts',  // 單個入口resolve: {// 設置支持的擴展名extensions: ['.js', '.ts', '.tsx', '.json']},module: {rules: [// 配置 ts 和 tsx 的加載器{test: /\.(ts|tsx)?$/,     // 匹配 .ts 和 .tsx 文件loader: 'ts-loader',      // 使用 ts-loader 加載器exclude: /node_modules/   // 排除 node_modules 目錄},// 配置 CSS 樣式文件的加載器{test: /\.css$/,           // 匹配 .css 文件loader: 'css-loader',     // 使用 css-loader 加載器exclude: /node_modules/   // 排除 node_modules 目錄}],},externals: {"react": "React",             // 將 react 標記為擴展依賴"react-dom": "react-dom"      // 將 react-dom 標記為擴展依賴},output: {filename: 'index.js',         // 定義輸出文件名path: path.resolve(__dirname, "dist")  // 定義輸出目錄},// 添加插件plugins: [new CleanWebpackPlugin()    // 在編譯前清空輸出目錄]
};

上述代碼為單頁面打包(webpack默認模式),頁面數量和入口文件的數量相同;若要實現多頁面打包,將entry設置為數組即可。

Loader(加載器)
Loader用于轉換模塊的源代碼,通常使用npm管理,需要安裝。由于webpack本身并不具備解析所有資源類型的能力,因此需要各種loader完成這一任務 。
常用的loaders:

  • js兼容性處理。babel-loader(將es6轉換為es5)
  • css樣式文件。css-loader(加載解析CSS),style-loader(將css注入js)
  • js語法檢查。eslint-loader
  • 資源文件。file-loader和url-loader

Plugin(插件)
plugin是一個擴展器,它豐富了webpack本身,針對是loader結束后,webpack打包的整個過程,它并不直接操作文件,而是基于事件機制工作,會監聽webpack打包過程中的某些節點,執行廣泛的任務

Webpack 與 gulp 的區別

  • glup是一種基于流(stream)的自動化構建工具,通過配置task生成項目的構建流水線
  • 從打包過程來看,Webpack是基于實際的依賴關系,而gulp是基于項目的物理結構。
  • 從目標導向上看,Webpack是偏向于模塊化部署,而glup偏向于產品管理。
  • 從配置角度看,Webpack是基于入口起點,而glup是基于流的。

12.js垃圾回收機制

什么是內存泄漏: 不再用到的內存,如果沒有及時釋放,就叫內存泄漏
什么是垃圾: 一般來說沒有被引用的對象就是垃圾。
js常用兩種垃圾回收規則是:

  • 標記清除
    垃圾回收期在運行的時候會給存儲在內存中所有變量都加上標記,
    然后,它會去掉環境中的變量以及被環境中的變量引用的變量的標記
    之后被加上標記的變量都將被視為準備刪除的變量,原因是環境中的變量已經無法訪問到這些變量
  • 引用計數
    跟蹤記錄每個值被引用的次數,當一個值被引用,次數+1,減持時-1,下次垃圾會回收期會回收次數為0的值的內存。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/140060.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息