javascript高階基礎的深入總結
基礎總結深入
1、資料型別
分類:
- 基本(值)型別
- String
- Number
- Boolean:true|false
- undefined:undefined
- null:null
- 物件(引用)型別
- Object:任意物件
- Function:一種特別的物件(可以執行)
- Array:一種特別的物件(數值下標,內部資料是有序的)
判斷:
- typeof
- instanceof
- ===(全等,不會做資料轉換) | ==(會做資料轉換)
1、undefined和null的區別?
undefined 代表定義未賦值
null 代表定義並賦值了,只是值為null
2、什麼時候給變數賦值為null?
起始的時候初始賦值為null,表明將要賦值為物件。
var b = null;
確定物件就賦值
b = [] || b = {}
最後,釋放資源,讓變數指向的物件成為垃圾物件(被回收)
b = null
3、嚴格區別變數型別與資料型別
變數型別
- 基本型別
- 物件型別
資料型別
- 基本型別:儲存的就是基本型別的資料
- 引用型別:儲存的是地址值
2、資料,變數與記憶體
1、什麼是資料?
儲存在記憶體中代表特定資訊的“東東”,本質上是010101…
資料的特點:可傳遞(基本型別傳遞的是指,引用型別傳遞的是地址值)、可運算
2、什麼是記憶體?
記憶體只是一種概念,現實形象的就是記憶體條了,記憶體條通電後產生的課儲存資料的空間(臨時的)
記憶體產生和死亡:記憶體條(電路板)–> 通電–> 產生記憶體空間–> 儲存資料–> 處理資料–> 斷電–> 記憶體空間和資料讀消失
一塊小記憶體的2個資料:地址值與儲存的資料。
記憶體分類:
- 棧:全域性變數、區域性變數
- 堆:物件(物件本身在堆空間中,但是表示物件的標識(變數名)在棧空間中)
3、什麼是變數?
可以變化的量,有變數名和變數值組成。常量是不嫩變化的量。
每個變數都對應一塊小記憶體,變數名可用來查詢對應的記憶體,變數值就是記憶體中儲存的資料。
4、前三者之間的關係
記憶體用來儲存資料的空間;
變數是記憶體的標識,
5、相關問題**
1、關於賦值與記憶體的問題?
問題:var a=xxx; a記憶體中到底儲存的是什麼?
- 如果xxx是基本資料,儲存的就是這個資料
- 如果xxx是物件,儲存的是物件的地址值
- 如果xxx是變數,儲存的是xxx的記憶體內容(可能是基本資料,也可能是地址值)
2、關於引用變數賦值問題?
小總結一下:關於變數賦值問題:
- 如果變數所指向的是基本型別,則賦值是直接將儲存的值複製過去。
- 如果變數所指向的是引用型別,則賦值是將儲存的地址值複製過去。
多個引用變數指向同一個物件,通過一個變數修改物件內部的資料,其他變數看到的是修改之後的資料。
var obj1 = {name:"wwj"} var obj2 = obj1; obj2.name = "Tom"; console.log(obj1.name + "---" + obj2.name); //Tom---Tom // ====== function fun(obj){ obj.name = "A"; } fun(obj2); // 把實參obj2的值賦值給形參,即把obj2變數儲存的物件的地址值賦值給形參。 console.log(obj1.name + "---" + obj2.name); //A---A
2個引用變數指向同一個物件,讓其中一個引用變數指向另一個物件,另一個引用變數依然指向前一個物件。
var a = {age:31} var b = a; a={name:"wwj", age:18}; console.log(b.age + "---" + a.name + "---" + a.age);//31---wwj---18 //============== function fun2(obj){ // 說明:當呼叫fun2方法是,把實參變數a的值(即使物件的地址值)賦值給形參obj,obj為區域性變數,這時,變數a和區域性變數obj都是指向同一個物件。 // 當區域性變數obj重新指向另一個物件時,區域性變數obj儲存的地址值改變,而變數a的值沒有改變,所以即使改變區域性變數obj所指向的物件的值,也改變不了不了a所指向的物件的值。而當函式執行完畢後,清除區域性變數obj obj = {age:88} } fun2(a); console.log(a.name + "---" + a.age); //wwj---18
3、在js呼叫函式時傳遞變數引數時,是值傳遞還是引用傳遞?
總結:
- 都是值傳遞(基本型別的值|引用型別的地址值)
- 如果變數所指向的是基本型別,則賦值是直接將儲存的值複製過去。
- 如果變數所指向的是引用型別,則賦值是將儲存的地址值複製過去。
var a = 3; function fun(a){ a = a + 1; } fun(a) console.log(a) // 3
4、js引擎任何管理記憶體?
- 記憶體生命週期
- 分配小記憶體空間,得到它的使用權
- 儲存資料,可以反覆進行操作
- 釋放小記憶體空間
- 釋放空間
- 區域性變數:函式執行完畢自動釋放
- 物件:成為垃圾物件==》垃圾回收期回收
3、物件
1、什麼是物件?
- 多個資料的封裝體
- 用來儲存多個資料的容器
- 一個物件代表現實中的一個事物
2、為什麼要用物件?
- 統一管理多個資料
3、物件的組成
屬性:
- 代表現實事物的狀態資料
- 由屬性名和屬性值組成
- 屬性名都是字串型別,屬性值是任意型別
方法:
- 代表現實事物的行為資料
- 是特別的屬性==》屬性值是函式
4、任何訪問物件內部資料?
屬性名:編碼簡單,但有時不能用
[“屬性名”]:編碼麻煩,但通用
4、函式
1、什麼是函式?
實現特定功能的n條語句的封裝體
只有函式是可以執行的,其他型別的資料不能執行
2、為什麼要用函式?
提高程式碼複用
便於閱讀交流
3、如何定義函式?
函式宣告
function fun(){}
函式表示式 - ```js var fun = function (){}
4、任何呼叫(執行)函式?
function fun(){ test:function(){} }
fun():直接呼叫
fun.test():通過物件呼叫
new fun():new呼叫
fun.call()|fun.apply():臨時讓某個物件呼叫
5、回撥函式
1、什麼函式才是回撥函式?
- 自己定義的
- 而且自己沒有呼叫
- 但是最終函式執行了
document.body.onclick = function(){ alert("這個函式回撥了") }
2、常見的回撥函式
- 定時器回撥函式
- 超時定時器
- 迴圈定時器
- Dom事件回撥函式
- ajax請求回撥函式
- 生命週期回撥函式
6、IIFE-立即執行函式
全稱:Immediately-invoked Function Expression(立刻執行函式表示式 或立刻呼叫函式表示式)
作用:
- 隱藏實現
- 不會汙染外部(全域性)名稱空間
- 用來編碼js模組
// 無慘
;(function(){
alert("立即執行了")
})()
// 有慘
;!function(obj){
alert("立即執行了---" + obj)
}("這是個引數...")
//===========
;-function(){
alert("立即執行了")
}()
//===========
;+function(){
alert("立即執行了")
}()
//===========
;~function(){
alert("立即執行了")
}()
// ......
;!function() {
var obj = {
name: "wwj"
}
function fun() {
console.log(obj);
}
window.$ = function() { // 向外暴露一個全域性變數
return {
obj: obj,
fun: fun
}
}
}()
// $ 是一個函式,函式返回一個物件。
$().fun();
7、函式中的this
檢視js基礎中的函式,有詳細說明;
8、語句加不加分號
沒有應該不應該,只有你自己喜歡不喜歡。
但是,有幾種不加分號,在壓縮程式碼的時候會有問題:
- 小括號開頭的前一條語句
- 中方括號開頭的前一條語句
- 定義變數的語句
函式高階
1、原型與原型鏈
1.1 原型-prototype
函式的prototype屬性
每個函式都有一個prototype屬性,它預設指向一個Object空物件(空物件:沒有我們的自定義的屬性。並且這個Object空物件是Object物件的例項,所以有一個隱式屬性
__proto__
)(即稱為:原型物件)var obj = function() { } console.log(obj.prototype); obj = new obj(); console.log(obj); console.log(Date.prototype);
- 當使用new 關鍵字建立一個例項是,都會有一個隱藏的屬性
__proto__
,下面有講解。。。原型物件中有一個屬性Constructor,它指向函式物件
var obj = function() { } console.log(obj.prototype.constructor === obj); console.log(Date.prototype.constructor === Date);
給原型物件新增屬性(一般都是方法)
- 作用:函式的所有例項物件自動擁有原型中的屬性(方法)
var Fun = function() { } Fun.prototype.test = function(){ alert("~~~"); } var fun= new Fun(); fun.test();
1.2 顯示原型月隱式原型
-
每個函式function都要一個prototype,即顯式原型(屬性)
var Fun = function() { } console.log(Fun.prototype) Fun.prototype.test = function(){ alert("~~~"); } console.log(Fun.prototype)
-
每個例項物件都要一個
__proto__
,可稱為隱式原型(屬性)var Fun = function() { } Fun.prototype.test = function(){ alert("~~~"); } var fun= new Fun(); console.log(Fun.__proto__)
-
物件的隱式原型的值為其對應建構函式的顯示原型的值。
var Fun = function() { } Fun.prototype.test = function(){ alert("~~~"); } var fun= new Fun(); fun.test(); // 證明~~~ console.log(fun.__proto__ === Fun.prototype)
-
內容結構(圖)
-
總結:
- 函式的prototype屬性:在定義函式時自動新增的,預設值是一個空的Object物件
- 物件的
__proto__
屬性:建立物件時自動新增的,預設值為建構函式的prototype屬性值 - 程式設計師能直接操作顯示原型,但不能直接操作隱式原型(ES6之前)
1.3 原型鏈
- 原型鏈(圖解):(空物件:沒有我們的自定義的屬性。並且這個Object空物件是Object物件的例項,所以有一個隱式屬性
__proto__
)
-
訪問一個物件的屬性時,先在自身屬性中查詢,找到返回;如果沒有,在沿著
__proto__
這條鏈向上查詢,找到返回,如果最終都沒找到,則返回undefined。 -
別名:隱式原型鏈
-
作用:查詢物件的屬性(方法)
-
建構函式 /原型/實體物件的關係(圖解)[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳
-
建構函式 /原型/實體物件的關係2(圖解2)
- 任何的函式都是通過new Function() 建立的,無論是內建函式,還是自定義函式。
- 例項物件的隱式原型等於建構函式的顯式原型。
補充:
-
函式的顯式原型指向的物件預設是空Object例項物件(但Object不滿足):
console.log(Fn.prototype instanceof Object) // true console.log(Object.prototype instanceof Object) // false console.log(Function.prototype instanceof Object) // true
-
實際上上圖中的 Function.prototype 還有一個
__proto__
屬性,並且指向Object.prototype。 -
所有函式都是Function的例項(包括Function)
console.log(Function.prototype === Function.__proto__) // true
-
Object的原型物件是原型鏈的盡頭。並且
__proto__
的返回值為nullconsole.log(Object.prototype.__proto__) // null
1.3.1 屬性問題
- 讀取物件的屬性值時:會自動到原型鏈中查詢(會先在物件本身上查詢,沒有則沿著原型鏈查詢)
- 設定物件的屬性值時,不糊查詢原型鏈,如果當前物件中沒有此屬性,直接新增此屬性並設定其值
- 方法一般定義在原型中,屬性一般通過建構函式定義在物件本身上。
1.4 探索instanceof
作用:判斷左邊的物件 是否是 右邊型別的例項
表示式:A instanceof B
結果:如果B函式的顯式原型物件在A物件的原型鏈上,返回true,否則返回false。
例子一:
例子二:
2、執行上下文與 執行上下為棧
1.變數提升與函式提升
-
變數宣告提升
-
通過var定義(宣告)的變數,在定義語句之前就可以訪問到
-
值:undefined
-
console.log(a); // undefined var a = "xx"; // 上面的程式碼相當於是: var a; console.log(a); // undefined a = "xx";
-
-
函式宣告提升
-
通過function宣告的函式,在定義語句之前就可以直接呼叫
-
值:函式定義(物件)
-
b(); function b(){ console.log("~") } // 上面的程式碼相當於是: function b(){ console.log("~") } b();
-
-
問題:變數提升和函式提升是如何產生的?
c(); var c = function(){ console.log("~") } // 上面的程式碼相當於是: var c; c(); var c = function(){ console.log("~") }
2.執行上下文
- 程式碼分類(位置)
- 全域性程式碼
- 函式(區域性)程式碼
- 全域性執行上下文:
- 在執行全域性程式碼前將window確定為全域性執行上下文
- 對全域性資料進行預處理
- var定義的全域性變數==》undefined,新增為window的屬性
- function宣告的全域性函式==》賦值(fun),新增為window的方法
- this==》賦值(window)
- 開始執行全域性程式碼
- 函式執行上下文
- 在呼叫函式,準備執行函式體之前,建立對應的函式執行上下文物件(是一個虛擬物件,執行完後就被刪除。換一個說法就是,在定義一個方法是,不會建立一個函式執行上下文物件,只有當呼叫函式時,才後建立一個函式執行上下文物件)
- 對區域性資料進行預處理
- 形參變數==》賦值(實參)==》新增文執行上下文的屬性
- arguments==》賦值(實參列表),新增為執行上下文的屬性
- var定義的區域性變數==》undefined,新增為執行上下文的屬性
- function宣告的函式==》賦值(fun),新增為執行上下文的方法
- this==》賦值(呼叫函式的物件)
- 開始執行函式體程式碼
3.執行上下文棧
- 在全域性程式碼執行前js引擎就會建立一個棧來儲存管理所有的執行上下文物件
- 在全域性執行上下文(window)確定)後,將window新增到棧中(壓棧)
- 當開始執行一個函式時,將該函式執行上下文物件新增到棧中(壓棧)
- 即使正在執行的函式裡又有多個該函式執行上下文物件,都要按照順序新增到棧中(壓棧)中並執行
- 在當前函式執行完畢後,將棧頂的物件移除(出棧)
- 如此迴圈後(第三步開始),當所有的函式執行上下文物件執行完後,棧中只有window
4.面試題
console.log("gb:", i);
var i = 1;
foo(i);
function foo(i){
if(i == 4) return;
console.log("fb:" + i);
foo(i + 1);
console.log("fe:" + i);
}
// 上面的程式碼中有幾個上下為物件? 5
// 上面的程式碼的結果是什麼?
// ----------------------------
function a(){}
var a;
console.log(a);
// 結果是什麼? 結果為:"function"
// 實際上問的是變數提升和函式提升的問題,這兩種提升到底是誰先提升。看結果得知,是先變數提升,後函式提升
// ----------------------------
if(!(b in window)){
var b = 1;
}
console.log(b);
// 結果為 undefined
// 為什麼? 還會變數提升問題
// ----------------------------
var c =1;
function c(c){
console.log(c)
}
c(2); // 報錯,提示c不是一個function
//為什麼會這樣呢?這還是變數提升和函式提升問題,程式碼的實際執行時這樣的:
var c;
function c(c){
console.log(c)
}
c =1;
c(2);
// 先變數提升,但是變數還沒賦值,接著函式提升,在變數賦值。所以最後c是變數
3、作用域域作用域鏈
-
理解
- 作用域就是一塊“地盤”,一個程式碼段所在的區域
- 它是靜態的(相對於上下文物件),在編寫程式碼是就確定了
-
分類
-
全域性作用域
-
函式作用域
-
沒有快作用域(ES6有了)
if(true){ var a = 3; } console.log(a); // 3
-
-
作用:
- 隔離變數,不同作用域下同名變數不會有衝突。
============
作用域與執行上下文:
區別1:
- 全域性作用域之外,每個函式都會建立自已的作用域,作用域在函式定義時就已經確定了。而不是在函式呼叫時
- 全域性執行上下文環境是在全域性作用域確定之後,j5程式碼馬上執行之前建立
- 函式執行上下文是在呼叫函式時,函式體程式碼執行之前建立
區別2:
- 作用域是靜態的只要函式定義好了就一直存在,且不會再變化
- 執行上下文是動態的,呼叫函式時建立,函式呼叫結束時上下文環境就會被釋放
聯絡:
- 執行上下文(物件)是從屬於所在的作用域
- 全域性上下文環境==>全域性作用域
- 函式上下文環境=>對應的函式使用域
============
作用域鏈:說白了,就是獲取物件的順序,從內到外。
4、閉包
最終理解:就是Java中類的get和set方法的應用
1.閉包的理解
1、任何產生閉包?
當一個巢狀的內部(子)函式引用了巢狀的外部(父)函式的變數(函式)時,就產生了閉包。
2、閉包到底是什麼?
- 使用瀏覽器除錯檢視
- 理解一:閉包是巢狀的內部函式(絕大部分人認為)
- 理解二:包含是被引用變數(函式)的物件(極少數人認為)
- 注意:閉包存在於巢狀的內部函式中
3、產生閉包的條件?
- 函式巢狀
- 內部函式引用了外部函式的資料(變數、函式)
function fun1(){
var a = 2;
var b = "abc";
function fun2(){ // 執行函式定義,就會產生閉包(不用非得呼叫內部函式)
console.log(a)
}
}
fun1();
2.常用閉包
將函式作為另一個函式的返回值:
function fun1(){
var a=2;
function f(){
a++;
console.log(a);
}
return f;
}
var f = fun1();
f(); // 3
f(); // 4
// 從上面的例子中可以看出,閉包中應用的變數(函式)時沒有關閉重新定義,而是保留著引用
將函式作為實參傳遞給另一個函式呼叫:
function showDelay(msg, time){
setTimeout(function(){
console.log(msg);
}, time)
}
showDelay(23, 500)
3.閉包的作用
1.使用函式內部的變數在函式執行完成後,仍然存活在記憶體中(延長了區域性變數的生命週期)
2.讓函式外部可以操作(讀寫)到函式內部的資料(變數、函式)
問題:
- 函式執行完後,函式內部宣告的區域性變數(函式)是否還存在? 一般是不存在,存在於閉包的變數才可能存在。
- 在函式外部能直接訪問函式內部的區域性變數嗎?不能,但是能通過閉包讓外部操作
function fun1() {
var a = 2;
var b = "abc";
function setA(x) {
a = x;
console.log(a);
}
function getA() {
console.log(a);
return a;
}
// test
function test() {
console.log(a);
return a;
}
return {
setA:setA,
getA:getA
};
}
var f = fun1(); // 在上面的函式中,有兩個閉包(setA,getA),在函式fun1執行完後,函式中的變數一般都都會回收,但是隻有且僅只有被閉包引用時才能存在。同時,函式fun1中的閉包也會被回收,只有當且僅當閉包被引用時,閉包才能存在而不被回收(未被引用的會被回收),而被閉包引用的變數延長生命週期。
f.getA()
f.setA(343)
f.getA()
// 死亡
f = null;
4.閉包的生命週期
產生:在巢狀內部函式定義執行完成時就產生了(不是在呼叫)
死亡:在巢狀的內部函式成為垃圾物件時
5.閉包的應用
定義js模組:
- 具有特定功能的js檔案
- 將所有的資料和功能封裝在衣蛾函式內部(私有的)
- 只向外暴露一個包含n個方法的物件或函式
- 模組的使用者,只需要通過模組暴露的物件呼叫方法來實現對應的功能
方式一(普通方式引入模組):
一個js檔案:test.js
function myModule() {
var msg = "hello";
function toUperCase() {
console.log(msg.toUpperCase());
// console.log(msg);
}
function toLowerCase() {
console.log(msg.toLowerCase());
// console.log(msg);
}
function setMsg(xxx) {
msg = xxx;
console.log(msg);
console.log(this);
}
// 方式一
return {
toUperCase: toUperCase,
toLowerCase: toLowerCase,
setMsg:setMsg
}
}
一個用於模組的html檔案:test.html
<!DOCTYPE html>
<html> <head> </head>
<body>
<script src="./test.js"></script>
<script>
// 方式一:
var module = myModule();
module.toUperCase();
module.toLowerCase();
module.setMsg("1345");
module.toUperCase();
module.toLowerCase();
</script>
</body>
</html>
方式二(立即執行函式式引入模組):
一個js檔案:test.js
(function myModule(window) {
var msg = "hello";
function toUperCase() {
console.log(msg.toUpperCase());
// console.log(msg);
}
function toLowerCase() {
console.log(msg.toLowerCase());
// console.log(msg);
}
function setMsg(xxx) {
msg = xxx;
console.log(msg);
console.log(this);
}
// 方式3二
window.myModule2 = {
toUperCase: toUperCase,
toLowerCase: toLowerCase,
setMsg: setMsg
}
})(window)
一個用於模組的html檔案:test.html
<script src="./閉包應用1.js"></script>
<script>
// 方式二
myModule2.toUperCase();
myModule2.toLowerCase();
myModule2.setMsg("1345");
myModule2.toUperCase();
myModule2.toLowerCase();
</script>
6.閉包的缺點
缺點:
- 函式執行完後,函式內的區域性變數沒有釋放,佔用記憶體時間會邊長
- 容易造成記憶體洩漏
解決:
- 能不用閉包就不用
- 及時釋放
7.閉包最終理解題
<script>
function fun(n, o){
console.log(o);
return {
fun: function(m){
return fun(m, n);
}
}
}
var a = fun(0);
a.fun(1);
a.fun(2);
a.fun(3);
// ------
var b = fun(0).fun(1).fun(2).fun(3);
// ------
var c = fun(0).fun(1);
c.fun(2);
c.fun(3);
</script>
物件高階
1、物件建立模式
1.Object建構函式模式
- 套路:先建立空Object物件,再動態新增屬性/方法
- 應用場景:起始時不確定物件內部資料
- 問題:語句太多
var p = new Object();
p.name = "text";
p.age = 12;
p.....
2.物件字面量模式
- 套路:使用{} 建立物件,同時指定屬性/方法
- 使用場景:起始時物件內部資料是確定的
- 問題:如果建立多個物件,有重複程式碼
var p = {
p.name = "text",
p.age = 12,
p.....
}
3.工廠模式
- 套路:通過工廠函式動態建立物件並返回
- 適用場景:需要建立多個物件
- 問題:物件沒有一個具體的型別,都是Object型別
<script>
// 人的型別
function createPerson(name, age) {
return {
name: name,
age: age,
setName: function(name) {
this.name = name;
}
}
}
var p1 = createPerson("tom", 23);// ... 建立更多
console.log(typeof p1) // object
// 學生的型別
function createStudent(name, age) {
return {
name: name,
age: age
}
}
var s1 = createStudent("Low", 11);// ... 建立更多
console.log(typeof s1) // object
</script>
// 通過上面可知,物件沒有一個具體的型別,都是Object型別
4.自定義建構函式模式
- 套路:自定義建構函式,通過new建立物件
- 適用場景:需要建立多個型別確定的物件
- 問題:每個物件都要相同的資料(每個物件的屬性可能不同,但是方法是相同的),浪費記憶體
// 人的型別
function Person(name, age) {
this.name = name;
this.age = age;
this.setName = function(name){this.name = name};
}
var p1 = new Person("tom", 23);// ... 建立更多
console.log(typeof p1) // Person
// 學生的型別
function Student(name, age) {
this.name = name;
this.age = age;
this.setName = function(name){this.name = name};
}
var s1 = new Student("Low", 11);// ... 建立更多
console.log(typeof s1) // Student
5.建構函式+原型的組合模式
- 套路:自定義建構函式,屬性在函式中初始化(在建構函式中只初始化一般屬性),方法新增到原型上
- 使用場景:需要建立多個型別確定的物件
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.setName = function(name) {
this.name = name
};
var p1 = new Person("tom", 23); // ... 建立更多
console.log(p1 instanceof Person) // true
console.log(p1) // true
// 學生的型別
function Student(name, age) {
this.name = name;
this.age = age
}
Student.prototype.setName = function(name) {
this.name = name
};
var s1 = new Student("Low", 11); // ... 建立更多
console.log(s1 instanceof Student) // true
console.log(s1) // true
2、繼承模式
1.原型鏈繼承
- 套路:
- 定義父型別建構函式
- 給父型別的原型新增方法
- 定義子型別的建構函式
- 建立父型別的物件賦值給子型別的原型
- 將子型別原型的構造屬性設定為子型別
- 給子型別原型新增方法
- 建立子型別的物件:可以呼叫父型別的方法
- 關鍵:子型別的原型為父型別的一個例項物件
// 父型別
function Supper(){
this.supProp = "supper prototype"
}
Supper.prototype.showSupperProp = function(){
console.log(this.supProp);
}
// 子型別
function Sub(){
this.subProp = "subProp prototype"
}
// 子型別的原型為父型別的一個例項物件
Sub.prototype = new Supper();
// 將子型別原型的構造屬性設定為子型別
Sub.prototype.constructor = Sub;
Sub.prototype.showSubProp =function (){
console.log(this.subProp);
}
var sub = new Sub();
sub.showSupperProp();
sub.showSubProp();
2.借用建構函式繼承
- 套路
- 定義父型別建構函式
- 定義子型別的建構函式
- 在子型別建構函式中呼叫父型別構造
- 關鍵:在子型別建構函式中通用call() 呼叫父型別建構函式。
function Person(name, age){
this.name = name;
this.age = age;
}
function Student(name, age, price){
Person.call(this, name, age);
this.price = price;
}
var s1=new Student('通', 23, 442);
console.log(s1)
3.組合繼承
原型鏈+借用建構函式的組合繼承
- 利用原型鏈實現對父型別物件的方法繼承
- 利用call() 基於父型別建構函式初始化相同的屬性
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.setName = function(name){
this.name = name;
}
function Student(name, age, price){
Person.call(this, name, age);
this.price = price;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.setPrice = function(price){
this.price = price;
}
var s1=new Student('通', 23, 442);
console.log(s1)
執行緒機制與事件機制
1、程式與執行緒
程式:程式的一次執行,它佔有一片獨有的記憶體空間;可以通過windows工作管理員檢視程式。
執行緒:執行緒是程式內的一個獨立執行單元,是程式執行的一個完整流程,是cpu的最小的排程單元
相關知識:
- 應用程式必須執行在某個程式的某個執行緒上
- 一個程式中至少有一個執行的執行緒:主執行緒,程式啟動後自動建立
- 一個程式中也可以同時執行多個執行緒,我們會說程式是多執行緒執行的
- 一個程式內的資料可以供其中的多個執行緒直接共享
- 多個程式之間的資料是不能直接共享的
- 執行緒池(thread pool):儲存多個執行緒物件的容器,實現執行緒物件的反覆利用
相關問題:
- 何為多程式和多執行緒?
- 多程式–一哥應用程式可以同時啟動多個例項執行
- 多執行緒—在一個程式內,同時又多個執行緒執行
- 比較單執行緒與多執行緒?
- 多執行緒
- 優點:能有效提升CPU的利用率
- 缺點:建立多執行緒開銷、執行緒間切換開銷、死鎖與狀態同步問題
- 單執行緒
- 優點(順序程式設計簡單易懂)、缺點(效率低)
- 多執行緒
- js是單執行緒
- 瀏覽器執行是多執行緒
2、瀏覽器核心
核心:支撐瀏覽器執行的最核心的程式
不同的瀏覽器可能核心不一樣:
- Chrome、Safari:webkit
- FireFox:Gecko
- IE:Trident
- 360、搜狗等國內瀏覽器:Trident+webkit
核心由很多模組組成:
3、定時器引發的思考
4、js是單執行緒執行的
5、瀏覽器的事件迴圈(輪詢)模型
模型原理圖:
相關重要概念:
6、H5 Web Workers(多執行緒)
注意:在分執行緒中的全域性物件不再是window,所有在分執行緒中不可能更新介面
使用多執行緒:
<!DOCTYPE html>
<html> <head> </head>
<body>
<input type="text" placeholder="數值" id="number"/>
<button id="bun">計算</button>
<script>
var input = document.getElementById("number");
document.getElementById("bun").onclick = function(){
var number = input.value;
// 建立一個Worker物件。其中引數是一個js檔名路徑名
var worker = new Worker("worker.js");
// 繫結接受訊息的監聽
worker.onmessage = function (event){
console.log("主執行緒接收分執行緒返回的資料:", event.data)
}
// 向分執行緒傳送資訊
worker.postMessage(number);
console.log("主執行緒向分執行緒傳送的資料:", number)
}
</script>
</body>
</html>
被引用多執行緒的js檔案
function fiboacci(n) {
return n <= 2 ? 1 : fiboacci(n - 1) + fiboacci(n - 2);
}
// 這個格式要固定,不能使用函式宣告
var onmessage = function (event){
console.log("分執行緒接收主執行緒傳送的資料:", event.data)
var number = event.data;
// 計算(自己定義的邏輯)
var result = fiboacci(number);
postMessage(result);
console.log("分執行緒向主執行緒返回資料:", result)
}
// 注意:在分執行緒中的全域性物件不再是window,所有在分執行緒中不可能更新介面
多執行緒的不知:
- 慢
- 不能跨域載入js
- worker內程式碼不能訪問DOM(更新UI)
- 不是沒個瀏覽器都支援這個新特性
補充
相關文章
- JavaScript基礎總結JavaScript
- 最全JavaScript基礎總結JavaScript
- JavaScript基礎總結(二)JavaScript
- JavaScript基礎總結(三)——陣列總結JavaScript陣列
- 【JavaScript高階進階】JavaScript變數/函式提升的細節總結JavaScript變數函式
- JS基礎知識深入總結JS
- 高階前端基礎-JavaScript抽象語法樹AST前端JavaScript抽象語法樹AST
- 深入解析 Spring 配置檔案:從基礎到高階Spring
- 前端知識點總結——JavaScript基礎前端JavaScript
- 深入理解javascript系列(十六):深入高階函式JavaScript函式
- React高階元件總結React元件
- 長篇總結之JavaScript,鞏固前端基礎JavaScript前端
- 物件導向(理解物件)——JavaScript基礎總結(一)物件JavaScript
- 深入理解javascript系列(十五):高階函式JavaScript函式
- JavaScript基礎——深入學習async/awaitJavaScriptAI
- PHP高階語法總結PHP
- 從基礎到高階,帶你深入瞭解和使用curl命令(二)
- jQuery基礎總結jQuery
- 【Python】基礎總結Python
- MongoDB基礎總結MongoDB
- 安全基礎總結
- VUE基礎總結Vue
- 深入JavaScript基礎之深淺拷貝JavaScript
- javascript 密碼花園 並不清晰的js基礎 總結(1)JavaScript密碼JS
- 338、分散式高階篇總結分散式
- 連結串列基礎總結
- js 閉包 基礎 示例 高階JS
- 深入理解 C++ 語法:從基礎知識到高階應用C++
- 我的html基礎總結—1HTML
- 學習canvas基礎的總結Canvas
- 4、JavaScript進階篇①——基礎語法JavaScript
- 常用JavaScript的高階技巧JavaScript
- C++基礎總結C++
- 最全Drawable基礎總結
- 深入探索LangChain的高階功能LangChain
- JavaScript 高階技巧JavaScript
- 2019 Android 高階面試題總結Android面試題
- 面試總結——Java高階工程師面試Java工程師