10.6
1.建構式中的方法應該寫在哪里?
- 屬性寫在建構式中,物件中的方法應該寫在prototype屬性上
- 原因:創建多個實體時不會每個實體都在記憶體中創建方法,節省記憶體空間
- 當實體想要呼叫建構式中的方法,會自動去原型鏈的prototype屬性找
2.原型鏈的終點?
- Object.prototype是原型鏈的終點
- Object.prototype屬性內置了.hasOwnProperty()和.toString()方法,所以我們創建的實體就能夠通過原型鏈呼叫到這兩個方法,
3.陣列的原型鏈?
- 陣列能夠呼叫.push()/.pop()/.slice()等方法就是因為這些方法定義在了Array建構式的prototype屬性上
- 而陣列的.isArray()方法則需要Array去呼叫,這是因為這個方法沒有定義到prototype屬性上,而是建構式里
- 而陣列能夠呼叫.toString()方法,就是因為array的原型Object.prototype
4.什么是繼承?
- 繼承描述了兩個類之間的“is a kind of”關系,比如學生“是一種人”,所以學生與人之間就構成了繼承關系
- People稱為父類(或者超類,基類),Student被稱為子類(派生類)
- 子類有父類的所有特性,并豐富了父類,讓類描述的更加具體,更加細化
5.javaScript中如何實作繼承?
- 實作繼承的關鍵在于:子類必須父類全部的屬性和方法并且子類擁有自己特有的屬性和方法
- 使用javaScript特有的原型鏈特性來實作繼承,是普遍的做法
- ES6中有新的實作繼承的方法
- 總結:子類的原型指向父類的實體
6.實作繼承的步驟?
- 首先創建父類,在prototype屬性中書寫方法,再創建一個子類,子類要擁有父類的全部屬性
- 讓子類的prototype屬性指向父類new出來的一個物件
- 子類的實體就可以呼叫父類的方法,實作類繼承
- 子類可以重寫父類的重名方法(override),主要應用到了建構式的遮蔽效應
7.面向物件的本質是什么?
- 定義不同的類,讓類的實體去作業,
- 面向物件最重要的作業就是去撰寫類
8.面向物件的優點是什么?
- 程式撰寫更加清晰,代碼結構更加嚴密,使代碼更健壯更利于維護,
9.面向物件經常用到的場合?
- 需要封裝和復用的場合(組件思維)
10.7
1.什么是包裝類?
- Number()、String()和Boolean()分別是數字、字串、布林值的包裝類
- 包裝類的目的就是讓基本型別變數,可以從他們的prototype屬性上獲得方法
- 用new包裝類得到的基本型別變數的型別是object
2.包裝類的作用?:包裝類的作用就是能夠使基本型別變數通過原型鏈來呼叫包裝類的prototype存在的方法,比如:
<script>
var a=123;
var b=new Number(123);//Number()包裝類的一個實體,是object型別
a.toString();//呼叫的是Number()包裝類中的prototype屬性中的方法
</script>
3.包裝類總結?
- Number()、String()和boolean()的new實體都是object型別,他們的PrimitiveValue屬性存盤他們本身值
- new出來的基本型別值可以正常參與運算
- 包裝類的目的就是為了讓基本型別值可以從他們的建構式的prototype上獲得方法
- 包裝類指的是對基本型別變數的封裝,參考型別的封裝不能稱為包裝類
- undefined和null沒有包裝類
4.Math物件常用方法?
- .pow(2,3):冪次方,求2的3次方
- .sqrt(5):開根號,求根號5
- .ceil(2.1):向上取整,結果為3
- .floor(2.9):向下取整,結果為2
- .round():四舍五入
- .round(2.5):3
- .round(-2.5):-2,注意,使用round方法,當判斷值為負數時,則以.5為臨界點,只要小于等于.5則舍,大于.5則入,
- .max():得到引數串列的最大值
- .min():得到引數串列的最小值
- .random():亂數生成0-1之間的隨機小數,不會生成1
- .abs():取絕對值
- .PI():取PI值
5.如何將一個小數四舍五入到指定位數?
- 以小數點后兩位為例,先將小數點向右移2位,就是乘以100
- 再進行四舍五入,得到后的結果,再除以100
- 得到最終的結果
6.如何求一個陣列的最大值?
<script>
var a=123;//實質上是Number()包裝類的一個實體
a.toString();//呼叫的是Number()包裝類中的prototype屬性中的方法
var arr=[12,14,15,17,18];
// 方式一:使用apply方法,apply會將陣列引數以零散值的形式傳入
console.log(Math.max.apply(null,arr));
//方式二:使用剩余運算子,剩余運算子可以將陣列引數拆分成散列引數
console.log(Math.max(...arr));
</script>
7.獲取Date日期物件的方法有哪些?
- 使用new Date()可以獲得當前時間的日期物件,它是object型別值
- 使用new Date(2020,11,1):獲取指定時間的日期物件,這種寫法不算時區
- 第二個引數表示月份,從0開始計算,11就表示12月
- 也可以使用new Date(“2020-12-01”)這樣的寫法,這種寫法算時區,中國屬于東八區
- 要注意月和日要是兩位數字,不足兩位的向前邊補0
- 這里的月寫幾就是幾,從1開始計算,12就表示12月
8.日期物件的常見幾個方法?
date日期物件:14個方法:
- 八個,獲取年月日時分秒毫秒星期等單個資料的方法:
- .getFullYear():得到年份
- .getMonth():得到月份0-11,獲取的月份,比真實月份少1
- .getDate():得到日期1-31
- .getHours():得到小時數0-23
- .getMinutes():得到分鐘數0-59
- .getSeconds():得到秒數0-59
- .getMilliSeconds():得到毫秒0-999
- .getDay():得到星期0-6,0代表星期日,1-6代表星期1-6
- 三個,獲取日期時間字串的方法:
- .toLocaleString():獲取本地的日期時間字串
- .toLocaleDateString():獲取本地的日期字串
- .toLocaleTimeString():獲取本地的時間字串
- 兩個,將日期物件轉為時間戳的方法:
- Date.prase():將日期物件轉為時間戳,精確到秒
- .getTime():轉為時間戳,精確到毫秒
- 一個:時間戳轉為時間物件的方法:
- new Date(時間戳):時間戳轉為時間物件
9.什么是時間戳?
- 時間戳表示1970年1月1日距離某時刻的毫秒數
- 通過.getTime()方法或者Date.parse()方法可以將日期物件變為時間戳
- 通過new Date(時間戳)的寫法,可以將時間戳轉為日期物件
<script>
var d=new Date();
// 有兩種方法能夠將日期物件轉為時間戳
console.log(d.getTime());//精確到毫秒
console.log(Date.parse(d));//精確到秒,但是也是以毫秒顯示,最后三位肯定是0
//將時間戳轉為時間物件
console.log(new Date(d.getTime()));
</script>
10.什么是正則運算式?
-
正則運算式描述了字串的構成模式,經常用于檢查字串是否符合預定的格式要求
-
**正則運算式是按位描述規則的:**它是一位一位的描述字串的構成形式的
11.正則運算式如何創建?
- 方式一:使用/內容/的形式創建一個正則運算式
- 方式二:使用new RegExp(‘內容’)的形式創建一個正則運算式,但是需要注意轉義字符\
- js內置了RegExp()建構式
- 使用typeof運算子檢測正則運算式的型別,結果是object
12.什么是元字符?使用元字符需要注意什么?
-
元字符是指一位指定型別的字符
- \d:匹配一位數字
- \D:匹配一位非數字
- \w:匹配一位單字字符(字母、數字、或下劃線)
- \W:匹配一位非單字字符
- \s:匹配一個空白字符(空格、制表符或換行符)
- .:任意字符
- ^:表示匹配開頭
- $:表示匹配結尾
- 【abc】:創建可以匹配的字符集
- 【0-9】:創建0到9范圍之間的字符集
- 【^0-9】:做非運算,除了0-9其他的字符都符合規則
- {5}:量詞,表示前面的字符*5個
-
當我們使用new RegExp()創建正則運算式時,需要注意的是在用到\的地方需要多加一個反斜杠來轉義
-
在特殊字符前加一個\則表示下一個字符不是特殊字符,應該按照字面意思理解
var regExp=/^.$/;//.表示任意字符
var regExp=/^\.$/;//.表示.而不是任意字符
- 不管一個符號是不是特殊字符,都可以在這個符號之前加一個\以確保它表達的是這個符號本身
13.方括號表示法的作用是什么?更高級的用法?
-
使用方括號表示法可以創建一個字符集合,表示匹配其中的任意一個字符比如:[abc],表示只要是a或者是b或者是c這一位都算通過
-
在方括號中可以使用-來表示一個范圍,在方括號中^表示否定,就是非的意思
- 方括號中的范圍做的是或運算
- \d等價于[0-9]
- \D等價于【^0-9]
- \w等價于[A-Za-z0-9_]
- \W等價于【^A-Za-z0-9_】
14.什么是量詞?
量詞:表示前面運算式出現次數的詞
- *:匹配前一個運算式0次或者多次,等價于{0,}
- +:匹配前一個運算式1次或者多次,等價于{1,}
- ?:匹配前面一個運算式0次或者1次,等價于{0,1}
- {n}:匹配前面一個運算式剛好出現n次
- {n,}:匹配前面一個運算式至少出現n次
- {n,m}:匹配前面一個運算式最少出現n次,最多出現m次
15.什么是正則運算式的修飾符?
-
修飾符也叫作標志(flags),用于使用正則運算式實作高級搜索
- i:不區分大小寫搜索
- g:全域搜索
-
修飾符的使用方法:
// 在正則運算式外面加修飾符 var regexp=/m/gi; // 用逗號隔開new運算式 var regexp1=new RegExp("m","gi");
10.8
1.正則運算式可以“打點”呼叫哪些方法?
var reg=/0-9a-z/;
-
reg.test(str):測驗某個字串是否匹配正則運算式,回傳布林值
-
reg.exec(str):根據正則運算式,在字串中進行查找,回傳結果類陣列物件或者null
-
直接檢索字串,匹配到第一個符合正則運算式規范的字符,就會回傳這個陣列
-
類陣列物件內容為回傳字符、字符所在下標、父串內容等
-
+表示貪婪查詢,會盡可能多的獲取更長的子串
-
g表示全域搜索,在運算式后面加上g使得每次檢索的結果可以逐條遍歷
-
var regexp=/\d/;//只檢索第一個符合條件的字符 var regexp1=/\d+/;//+貪婪檢索,盡可能多的檢索連續符合條件的字串 var regexp2=/\d+/g;//g全域檢索,開啟遍歷,每次檢索都會從上一個符合條件的字符后面開始
-
2.字串有哪些方法可以用正則運算式?
var str=“ascasd”;
var reg=/[a-z]/;
- str.search(reg):在字串中根據正則運算式進行查找匹配,回傳首次匹配到的位置索引,不存在則回傳-1
- str.match(reg):在字串中根據正則運算式進行查找,回傳一個所有符合條件的字串陣列,找不到回傳null
- str.replace(reg,“新內容”):使用替換字串替換掉匹配到的子字串,可以使用正則運算式
- str.split(reg):分割字串為陣列,可以使用正則運算式
3.正則運算式的實際應用?
用正則運算式進行表單驗證是正則運算式最重要的實際應用
- 中文漢字的范圍是:\u4E00-\u9FA5
4.onmouseover與onmouseenter的區別?
區別:
-
onmouseover、onmouseout:滑鼠移動到自身時候會觸發事件,同時移動到其子元素身上也會觸發事件
-
onmouseenter、onmouseleave:滑鼠移動到自身是會觸發事件,但是移動到其子元素身上不會觸發事件
10.9
1.let和var和const的區別?
- var的變數可以多次宣告,let如果宣告已經存在的變數,就會報錯
- var的變數會宣告提升,let的變數也會宣告提升,但是let的變數有一個它自己的暫時死亡區,在這個區域內不能呼叫它
- const是宣告一個常量,必須賦初始值,且這個常量之后不能改變
10.10
1.setTimeOut和setInterval?
- setTimeOut是延時器,到時間后只執行一次
- setInterval是定時器,每隔指定時間就會執行一次
- 第一個引數是要執行的函式體
- 第二個引數是間隔時間毫秒數
- 從第三個引數開始,后面的引數都是要傳到第一個函式里的實參
- 定時器和延時器都會有回傳值,回傳值是定時器和延時器在函式中是第幾個出現的
2.setTimeOut時間設為0毫秒時,與它下面普通的代碼執行順序是什么?
- setTimeOut和setInterval屬于異步代碼,普通代碼屬于同步代碼
- 編譯器會先執行所有的同步代碼,遇到異步代碼,會先將它放到異步佇列中
- 當所有的同步代碼執行完成后,再開始執行異步佇列中的異步代碼
- 所以即使setTimeOut的延時時間設為0,也會先執行它下面的普通代碼
- 用clear清定時器時,一般還會time=null;實作變數的垃圾回收
3.Date注意事項?
- 兩個時間物件做減法,得到的是兩個時間差距的時間戳
10.11
1.打開DOS命令視窗的幾種方法?
- win+r–>輸入cmd,
- 檔案資源管理器路徑上輸入cmd,直接進入當前檔案路徑的cmd
- 安裝git ->滑鼠右鍵點擊Bash Here
2.常用DOS命令?
DOS系統下使用,bash系統下有些不能用:
- 進入檔案夾:
- cd:修改路徑,進入
- cd …/:回退上一級
- cd /:快速回到根目錄
- tab:遍歷當前路徑下的檔案和檔案夾
- cd tab鍵:遍歷當前路徑下的檔案夾
- cd Desktop:跳轉到桌面
- 創建:
- mkdir 檔案夾名:創建檔案夾
- copy con +檔案名 ——>回車+輸入內容——>ctrl+z->回車:創建一個檔案夾
- 洗掉:
- 軟洗掉:檔案夾中有東西,洗掉不了
- rmdir 檔案夾名:洗掉檔案夾
- rd 檔案夾名:洗掉檔案夾
- 硬洗掉:檔案夾中有東西也能洗掉,會提示是否洗掉
- rd /s 檔案夾名:硬洗掉檔案夾
- 洗掉檔案:
- del 檔案夾名:洗掉檔案
- 軟洗掉:檔案夾中有東西,洗掉不了
- 重命名:
- rename b a:把檔案b重命名為a
3.git和svn?
- svn:集中式的版本控制系統
- 需要聯網,以檔案的形式上傳
- git:分布式的版本控制系統
- 每一個電腦都屬于一個完整的版本控制系統服務器
- 當多個電腦協同開發時,需要一個遠程倉庫(服務器)
- 每個電腦都可以將自己的版本代碼提交到遠程倉庫
- 每個電腦都可以從遠程倉庫download下所有版本的代碼
- 特點:
- 每個人的電腦就是一個服務器,有所有版本的資訊
- 如果不需要協同開發,不需要聯網也可以
- 傳輸是以檔案流的形式傳輸的,比檔案傳輸快
4.如何將a檔案夾變成git倉庫,將里面的檔案生成版本?
git倉庫分為三個區:作業區、暫存區、歷史區
將檔案生成git倉庫,并生成倉庫版本:
- 第一步:進入a檔案夾,打開Bash Here
- 第二步:git init:初始化當前檔案夾為git倉庫
- 第三步:git status:查看當前作業區中檔案的狀態
- 紅色:檔案在作業區還沒提交到暫存區
- 綠色:作業區的檔案已經提交到暫存區了,但是還沒有到歷史區
- 第四步:git add +檔案:將作業區的檔案提交到暫存區
- git add .:將作業區所有檔案全部提交到暫存區,不包含洗掉的
- git add A:將作業區所有檔案全部提交到暫存區
- 第五步:git commit -m “注釋”:提交a檔案夾的當前版本到歷史區
- -m:后面跟的是注釋
- 第六步:
- git log:查看歷史區的所有版本,不包含回滾資訊
- git reflog:查看所有歷史版本資訊,包括回滾資訊
- clear:清除視窗代碼
- git reset --hard 版本號:回退倉庫的版本號(用git log命令查看,至少前七位)
在gitee上面創建倉庫,并與git連接
-
配置上傳版本的用戶名和密碼
git config --global user.name "啊啊啊哈" git config --global user.email "8608378+aha-aha@user.noreply.gitee.com" -
創建git倉庫,并將本地的倉庫版本傳到gitee倉庫上:
mkdir zftest
cd zftest
git init
touch README.md
git add README.md
-------------上面的不重要-------------------
git commit -m "first commit";
git remote add origin https://gitee.com/aha-aha/zftest.git;//連接遠程倉庫
git remote -v://查看本地倉庫關聯的遠程倉庫
git remote remove origin;//洗掉遠程連接
git push -u origin master;//向遠程倉庫push檔案到主分支
- 如果已有倉庫直接用下面的
cd “已經存在的倉庫路徑”
連接遠程倉庫:git remote add origin https://gitee.com/aha-aha/zftest.git
向遠程倉庫push檔案到主分支:git push -u origin master
? -u origin master:表示推送到master分支
從gitee倉庫中down下最新倉庫到本地
-
克隆
-
git clone https://gitee.com/aha-aha/gitstuy.git:在目標檔案夾下打開本地bash視窗,輸入用git clone +想克隆的gitee倉庫地址
-
-
更新:
-
git pull ://將gitee上最新的版本拉下來
-
5.分支如何操作?
-
查看分支:git branch
-
新建分支:git branch 分支名
-
洗掉分支:git branch -d 分支名
-
切換分支:git checkout 分支名
-
創建并切換到新分支:git checkout -b 分支名
-
合并分支:
- 切換到主分支:git branch master
- 合并分支,當前分支與test分支合并:git merge test
6.什么是作用域,變數分幾種,什么是作用域鏈,上級作用域怎樣查找,閉包是什么?
https://www.jianshu.com/p/01804282372c
作用域: 表示一個變數的可用范圍,避免不同范圍的變數之間相互干擾,
作用域分為三種:
- 全域作用域:在瀏覽器端全域作用域就是window,他可以重復使用,隨處可用,但是全域作用的定義的變數容易被污染
- 函式私有作用域:函式宣告的時候會自動創建函式作用域物件scope,他指向函式宣告時的作用域,每個函式呼叫時,在創建AO物件之前會先創建當前函式的作用域,并創建parent物件,通過函式宣告時的作用域物件scope指向他函式的父級作用域,他不會污染全域,但是不會重復使用,函式執行完畢后會隨著函式執行背景關系出堆疊=>AO物件銷毀而銷毀
- es6新增的塊級作用域:除了物件的{},其他的{}都算塊級作用域,比如if(){};這個{}就是一個塊級作用域,只對es6新增的變數型別有效,對var和function無效,塊級作用域中的var和function還會宣告提升
變數:
- 變數分為全域變數,區域變數
- 定義在函式外的是全域變數
- 定義在函式內的區域變數
- 形式引數也是區域變數
作用域鏈的查找機制:變數到創建這個變數的函式的作用域中取值,但是如果在當前作用域中沒有查到值,就會向通過parent物件去父作用域去查,直到查到全域作用域,這么一個查找程序形成的鏈條就叫做作用域鏈,
- 如果全域作用域還沒有這個變數
- 如果是查詢:就報錯:Uncaught ReferenceError:a is not defind
- 如果是不加變數型別的賦值:如a=100;,則是添加一個全域變數
上級作用域:上級作用域是誰,跟在哪執行沒有任何關系,在哪定義的,它的上級作用域就是誰,
- 一定要與函式的背景關系(this)區別開,函式的背景關系是跟定義沒關系,只跟誰呼叫了它有關,
**閉包:**函式執行形成新的私有作用域,里面的私有變數只在里面有效,與外面的毫無關系
7.想讓js運行,需要提供環境?
- 瀏覽器(瀏覽器引擎)
- node(v8引擎)
- webview(v8引擎)
8.瀏覽器底層運行機制?
- 第一步:瀏覽器在運行js的時,會開辟兩個記憶體空間,堆(heap)和堆疊(ECStack)
- 第二步:在堆中開辟一個空間地址,用于存放瀏覽器的一些方法和屬性,這個物件稱為GO
- 第三步:為了區分代碼不同的作用域,在堆疊記憶體中會開辟兩種作用域空間:全域執行背景關系(EC(g))和私有執行背景關系(EC(fn))
- 全域執行背景關系**(EC(g))**:
- **功能:**存放全域變數區域VO、變數宣告提升、全域代碼自上而下的執行
- 私有執行背景關系(EC(fn)):
- 每次呼叫函式都會在堆疊中生成一個獨立的私有執行背景關系
- **功能:**存放私有變數區域AO、區域變數宣告提升、區域代碼自上而下的執行
- 全域執行背景關系**(EC(g))**:
- 第四步:在全域執行背景關系中創建存放全域變數的區域(VO),在私有執行背景關系中創建存放區域變數的區域(AO)
- 第五步:在VO中創建window物件,并指向堆中的GO

9.用不同關鍵字宣告的變數,他們在記憶體中都是如何創建的?
- ES5中宣告變數的關鍵字:var 、function
- 全域變數:會創建成一個window物件的屬性,屬性名是變數名,屬性值是變數值,因為window
- 區域變數:直接創建在私有函式背景關系(EC(fn))的AO中
- ES6中宣告變數的關鍵字:let 、const、class、import
- 全域變數:創建在VO中
- 區域變數:創建在EC(fn)的AO中
11.一段代碼執行的程序詳解?
- ECStack(Execution Context Stack):執行背景關系堆疊
- heap:堆記憶體
- EC(g):全域執行背景關系
- VO(Variable Object):變數物件(全域變數的存盤區域)
- EC(fn):函式私有執行背景關系
- AO(Activation Object ):活動物件 (函式的叫做AO,理解為VO的一個分支),私有變數的存盤區域
- Scope:作用域,創建的函式的時候就賦予的
- Scope Chain :作用域鏈
- global object:全域物件

10.12
1.全域執行背景關系和函式私有執行背景關系?
- 全域執行背景關系(EC(g)):js檔案執行時生成
- 私有執行背景關系(EC(fn)): 每次函式執行時都會生成獨立的
2.如何判斷某個物件是否擁有某個屬性?
- 使用in關鍵字
- 語法:屬性名 in 物件名
- 回傳布林值,如果有就回傳true,否則回傳false
3.在全域變數用var a=10;宣告一個變數和a=10;宣告一個變數的區別?
- 用var宣告的變數會進行宣告提升,直接a宣告的變數不會進行宣告提升
- var宣告的變數用delete window.a的形式不能洗掉變數(不可配置的),直接a宣告的變數用delete window.a的形式能夠洗掉(可配置的),
10.變數的宣告提升?
var宣告的變數,只提升宣告,賦值操作留在原地,- 函式宣告提升整個函式體,函式運算式的提升行為和變數一致,
- 同作用域中,如果函式宣告和
var宣告同名,只提升函式宣告,忽略var宣告,(var宣告不會覆寫函式宣告) let和const有暫時性死區,必須先宣告后使用,- 代碼自上而下執行時:
- 執行到var 陳述句時,給變數賦值
- 執行到function陳述句時,由于開始已經宣告提升了,所以function陳述句直接跳過,不再執行
4.變數提升需要注意的坑?
- 1、if陳述句:不管條件是否成立里面的變數都會宣告提升
- var:只宣告不定義
- 實名function:新版本:只宣告不定義,舊版本:宣告并且定義
- if條件成立后,首先將里面的實名函式進行定義的提升,再自上而下執行
- if里面的實名函式fn
- 無論條件是否成立,首先將fn作為變數名提升到if所在的作用域,這時全域fn=undefined
- 當條件成立進入if以后,首先再進行函式提升,提升if后面的代碼塊最頂部,形成區域函式fn=函式體,這時全域有一個fn,if代碼塊區域有一個fn
- 代碼自上而下執行,代碼塊中對fn的操作都是操作的區域fn變數,以fn定義代碼為分割線,當執行完fn定義代碼后,會將區域fn變數的值提升到全域fn變數,這時全域fn變數就會被修改一次,fn定義代碼后面對fn變數的操作,仍然是操作區域fn變數,全域fn不受影響,
- 2、函式運算式:提升var的變數,關鍵字不是var就不提升,函式運算式就是把等號后面的匿名函式看成變數的值
- 3、自執行函式:不宣告提升,但自身形成的私有執行背景關系里面的變數照常進行變數提升
- 4、return:return后面的代碼(回傳值代碼)不會提升,return陳述句下面的代碼如果有變數會宣告提升
- 5、變數提升階段:如果變數名重復,只宣告一次,但會多次賦值(var提升不會覆寫同名的函式提升)
5.私有函式執行背景關系里面都會有哪些操作?
- 第一步,生成AO私有變數存放區域
- 第二步:
- 初始化作用域鏈:scope->parent
- 初始化this指向:由函式的呼叫方式來確定
- 初始化arguments
- 給形參賦值
- 變數宣告提升
- 第三步:代碼自上而下執行

6.es6中的變數的特點?
- 一、es6中的變數,有變數提升,但是由于es6暫時性死區的作用,使得在執行到定義變數代碼之前,不能呼叫該變數,
- 二、es6中的變數,阻斷了與window的關系
- 三、es6中的變數,在同一作用域,不允許重復宣告
- 五、es6中的變數,在不同的作用域,可以重復宣告
- 私有作用域中只要定義了變數,就不會去找全域中的這個變數
- 但是這個變數不會宣告提升,所以,不能在這個變數宣告定義之前呼叫這個變數,變數宣告定義之前的區域,成為它的暫時性死區,在暫時性死區訪問變數會報錯:Cannot access ‘a’ before initialization
- 四、es6中在代碼自上而下執行之前有一個階段:詞法檢測機制
7.什么是暫時性死區?
? 當程式的控制流程在新的作用域(module, function或block作用域)進行實體化時,在此作用域中的用let/const宣告的變數會先在作用域中被創建出來,但因此時還未進行詞法系結,也就是對宣告陳述句進行求值運算,所以是不能被訪問的,訪問就會拋出錯誤,所以在這運行流程一進入作用域創建變數,到變數開始可被訪問之間的一段時間,就稱之為TDZ(暫時死區),
? 結論:let/const宣告的變數,的確也是有提升(hoist)的作用,這個是很容易被誤解的地方,實際上以let/const宣告的變數也是會有提升(hoist)的作用,提升是JS語言中對于變數宣告的基本特性,只是因為TDZ的作用,并不會像使用var來宣告變數,只是會得到undefined而已,現在則是會直接拋出ReferenceError錯誤,而且很明顯的這是一個在運行期間才會出現的錯誤,
? ES6 規定暫時性死區和let、const陳述句不出現變數提升,主要是為了減少運行時錯誤,防止在變數宣告前就使用這個變數,從而導致意料之外的行為,這樣的錯誤在 ES5 是很常見的,現在有了這種規定,避免此類錯誤就很容易啦~
8.arguments.callee和arguments.callee.caller的區別?
- arguments.callee:獲取函式本身
- arguments.callee.caller:獲取執行該函式的宿主函式,如果函式在全域下執行,則這個屬性獲取的值是null
- 這兩個屬性常用于匿名函式中
- 當在嚴格編碼模式下(“use strict”),不能使用這兩個函式
- 立即執行函式里可以匿名函式具名化:具名化后的函式變成常量,不能再重新賦值,
10.13
1.堆記憶體的銷毀與堆疊記憶體的銷毀機制?
堆記憶體:主要存放參考資料型別的真實資料
- 每個廠商的對堆記憶體中資料的銷毀有不同的機制
- 谷歌:每過一段時間就會對沒有被指向的資料空間進行垃圾回收(銷毀)
- iE:對一個堆記憶體空間的指向個數計數,就是看有多少個參考這個資料的變數,當參考變數變為0時,就銷毀這個記憶體空間
堆疊記憶體:存放變數,執行代碼
- 堆疊記憶體的銷毀機制:全域作用域的銷毀、函式私有作用域的銷毀
- 全域作用域的銷毀:頁面關閉時被銷毀
- 函式私有作用域的銷毀:執行完立即銷毀、不銷毀、不立即銷毀,
2.堆疊記憶體中不銷毀的作用域?
不銷毀的作用域:函式里面有一個參考資料型別,被函式外界變數占用,導致這個函式不能被銷毀,也被稱為閉包
實質上:任何一個函式,只要它里面存在外界不能訪問的私有變數,那么這個函式就形成了閉包
市面上:函式只有形成不銷毀作用域,才稱得上是閉包
3.不立即銷毀的作用域(顆粒化函式)?
不立即銷毀:當一個fn1函式中return了另一個fn2函式,通過fn1(1)(2),的形式呼叫這個函式時,fn1(1)執行結束后,由于回傳的fn2函式還會被執行,所以fn1在堆疊記憶體中生成的私有執行背景關系不會被立即銷毀,而是等fn2()函式執行結束后fn1和fn2都被銷毀,
4.閉包的作用?
- 保護:里面的私有變數不受干擾
- 保存:形成不被銷毀的作用域,
5.當多人協同開發時,如何避免多個js檔案之間的變數不被污染?
將自己的js檔案所有的代碼都用自執行函式包起來,
原因:使自執行函式生成私有作用域,當里面的函式找不到變數時,先去自執行函式的私有作用域去尋找,而不是去全域作用域尋找
目的:保護單個js檔案里面的私有變數不受外界干擾,
6.如何實作js檔案方法的初始化和封裝?
- ES6新規則,如果物件里面的屬性名和屬性值內容相同,只需要寫屬性名即可
//utils最侄訓取的自執行函式回傳的物件結果
var utils=(function(){
var num=100;
function bannerFn(){
console.log("banner")
}
function getDate(){
console.log("date")
}
function fn(){
console.log("fn")
}
return {
initFn:function(){
bannerFn();
getDate();
},
fn,
num
}
//
})();
utils.initFn();//執行initFn,實作初始化
utlis.fn();//執行fn函式,是utils里面的方法
7.如果用自執行函式包裹了js檔案代碼,如何再實作讓外界能夠使用這個代碼里面的函式?
- 把想要讓外界訪問的函式賦給window物件的一個屬性,外界就能夠通過屬性名呼叫這個函式了
var num=3;
(function(){
var num=6;
function jquery(){
num++;
console.log(num);
}
window.jquery=window.$=jquery;
})();
$();
8.當用for回圈給多個li添加點擊事件時,如果用lis[i].onclick點擊就會報錯,為什么?怎么解決?
原因:for回圈的初始變數var i,宣告的是全域變數i,當觸發點擊事件時,無論是哪個lis[i],都會去全域作用域中尋找i,而這個全域變數i已經變成了3,沒有lis[3]這個li,所以就會報錯
如何解決:
- 方法一(推薦):可以給每個li元素設定一個自己的屬性,屬性值就是自己的下標,事件里的函式通過這個屬性去找到陣列指定下標的li
- 方法二:出現問題的根本原因是點擊事件找全域變數i了,所以可以讓每個點擊事件后面函式用自執行函式變成私有作用域,把i傳給自執行函式,變成每個li的私有變數,讓每個li都形成一個私有執行背景關系,再通過return要執行的函式,**實作閉包 **
<script>
var olis = document.querySelectorAll(".main li");
var odivs = document.querySelectorAll(".main>div");
for (var i = 0; i < olis.length; i++) {
olis[i].onclick = (function (i) {
// i 是私有變數
return function () {
for (var j = 0; j < olis.length; j++) {
olis[j].classList.remove("current");
odivs[j].classList.remove("current");
}
olis[i].classList.add("current");
odivs[i].classList.add("current");
}
})(i)
}
</script>
- 方法三:將for回圈里所有函式用自執行函式包裹,將i傳入自執行函式,由于olis[i].onclick事件占用著里面的函式,所以形成了閉包
<script>
var olis = document.querySelectorAll(".main li");
var odivs = document.querySelectorAll(".main>div");
for (var i = 0; i < olis.length; i++) {
(function (i) {
//i=0 i是私有變數
// i=1
// i=2
olis[i].onclick = function () {
for (var j = 0; j < olis.length; j++) {
olis[j].classList.remove("current");
odivs[j].classList.remove("current");
}
olis[i].classList.add("current");
odivs[i].classList.add("current");
}
})(i);//0 1 2
}
</script>
- 方法四:for回圈中的回圈變數用let宣告
- 原理:
- 在ES6中for(){}整體看做一個塊兒級作用域
- var和let的變數提升區別,var會提升到當前函式作用域的最上面,let會提升到當前塊兒作用域的最上面
- 如果回圈變數是let創建的,那么for回圈的每次執行都會形成一塊新的塊兒級作用域,每個作用域的i值不同
- 原理:
9.關于變數提升的小知識:
1.let 的「創建」程序被提升了,但是初始化沒有提升,(此時變數進入暫時死區)
2.var 的「創建」和「初始化」都被提升了,
3.function 的「創建」「初始化」和「賦值」都被提升了,
4.const 和 let 只有一個區別,那就是 const 只有「創建」和「初始化」,沒有「賦值」程序,(也會進入暫時死區),
10.宣告、定義、初始化和賦值的區別?
-
宣告:告訴編譯器或決議器該變數存在,這個行為并不分配記憶體空間,
-
定義:為變數分配記憶體空間,在C語言中,一般宣告就包含定義,比如:int a;,但在Javascript中,var a;這種形式只是宣告,
-
初始化:在定義變數以后,系統為變數分配的空間記憶體儲的值是不確定的,所以需要對這個空間進行初始化,以確保程式的安全性和確定性,給變數賦默認值,
-
賦值:變數在分配空間之后的某個時間里,對變數的值進行重繪操作,即修改存盤空間內的資料,
10.15
1.this的指向?
this只看呼叫方式,不看定義位置
塊級私有作用域中沒有this,只研究函式呼叫時產生的this
什么是回呼函式:a函式作為b函式的引數,a就叫回呼函式
- 1、全域、定時器、延時器里面的this:window(嚴格和非嚴格)
- 2、普通函式(前面沒有.呼叫)、自執行函式、回呼函式的this:
- 非嚴格模式下:this指向window
- 嚴格模式下:this指向undefined
- 3、系結事件函式中的this:指向系結當前事件的DOM元素
- 4、物件或者陣列呼叫里面的普通函式:函式里的this指向呼叫它的物件或陣列
- 如果用全域變數指向物件或者陣列里面的函式,再用這個變數執行函式,則視為普通函式的執行,this指向window(非嚴格模式)
- 物件或陣列里的自執行函式:函式里的this仍然是指向window(非嚴格模式)
- 5、箭頭函式:沒有自己的this,如果函式中呼叫了this,就沿著作用域鏈去找上級的this,
- **重點:**物件不會生成作用域,塊級作用域沒有this
- 6、new建構式的實體:this指向實體化物件
- 7、call、apply、bind:能夠指定this指向
2.私有函式生成背景關系后堆疊中會執行什么操作?
- 1、創建私有作用域AO
- 2、初始化作用域鏈
- 3、初始化this指向
- 4、初始化arguments
- 5、形參賦值
- 6、變數提升
- 7、代碼自上而下執行
3.堆中存放的函式,由幾部分構成?
- 作用域:[[scope]] ,存放函式定義所在的父級作用域
- **代碼字串:**函式體內的代碼字串
- **鍵值對:**name: 存放函式的名字 、length:存放形參的個數
4.js中的設計模式你知道的有哪幾種?
- 單例、工廠、建構式、發布與訂閱、觀察者模式,,,
5.單例設計模式?
- 單例設計模式:兩個個體獨立,相互不會影響
- 高級單例模式:在個體相互獨立的前提下,又想讓外面能獲取里面的變數,用自執行函式,形成私有作用域,return時回傳物件,物件里面輸入想回傳的私有變數
6.工廠設計模式?
- 工廠設計模式:將常用重復陳述句封裝到一個函式中,形成一個工廠,想使用這些陳述句就呼叫這個函式即可,
- 優點:代碼一次撰寫,能夠多次復用,實作了高內聚,低耦合
7.面向物件的三個重要概念?
- 面向物件是一種編程思想
- 面向物件的三個重要概念:物件、類、實體
- 類(建構式):按照特征進行分類,把事物進行歸納分類,而且類一定會賦予它的每個成員,一些屬性和方法
- 賦予給每個成員的屬性和方法稱為靜態屬性和方法,放在他堆中的鍵值對區域
- 建構式的定義名規范為首字母大寫
- 通過new呼叫的函式叫建構式
- 不通過new呼叫的函式叫普通函式
- 實體:類中的每一個成員,都是這個類的實體,每一個實體都具有私有屬性和方法,共有屬性和方法
- 私有屬性和方法:prototype屬性外的都是私有屬性和方法
- 共有屬性和方法:只要變數是Array資料型別,都能呼叫.push()方法,.push()就是公有方法,prototype屬性里的都是公有屬性和方法,
- 兩個實體中私有的方法做等等比較結果是false,公有的方法做等等比較結果是true
- 物件:在js中,萬事萬物皆物件,指代的是物件資料型別,new呼叫建構式,就必須回傳一個物件,所以實體的本質也是物件,
- 類(建構式):按照特征進行分類,把事物進行歸納分類,而且類一定會賦予它的每個成員,一些屬性和方法
8.建構式設計模式?
- 用new呼叫函式,就視為該函式是建構式(建構式設計模式)
- 不用new呼叫函式,就視為該函式是普通函式
9.建構式執行與普通函式執行的區別?
建構式在堆疊記憶體中執行的程序:
- 區別一:在執行六大步之前,先創建私有的實體物件
- 區別二:將建構式的this,指向創建的實體物件
- 區別三:有this.xxx=xxx;的代碼,就是給實體物件添加私有xxx屬性
- 區別四:
- return無回傳值或回傳的是原始型別值 ----->回傳實力物件
- return的是物件型別----->回傳自己寫的物件:所有參考型別都算是物件型別

9.js內置類?
所有原型鏈的終點都指向Object類
- 各種資料型別內置類:
- null和undefined沒有內置類
- 基本資料型別:Number、String、Boolean、Symbol、Bigint
- 參考資料型別:Object(最大的內置類)、Array、Function、Regexp、Error、Date…
- 每一個DOM元素標簽都有自己所屬的類:p標簽有自己的內置類、a標簽有自己的內置類…
10.let f1 =new Fn與let f2=new Fn(10,20)的區別?
相同點:
- 無論有沒有(),建構式都執行了,f1和f2都實體化物件,
不同點:
-
區別一:new fn沒有傳參,new fn(10,20)傳參了
-
區別二:優先級不同:new fn()的優先級是20,new fn的優先級是19
10.16
1.instanceof關鍵字的使用?
instanceof關鍵字:用來判斷一個實體物件,是否屬于后面這個類
function Fn(){}
var fnn=new Fn();
console.log(fnn instanceof Fn);//true,判斷fnn屬于Fn類嗎
console.log(fnn instanceof Array);//false,判斷fnn屬于Array類嗎
console.log(fnn instanceof Object);//false,萬物皆物件,所有的實體原型鏈都是Object基類
2.原型和原型鏈?
- 幾乎所有的函式都有prototype(原型)屬性,
- 有prototype屬性的函式型別:普通函式(實名匿名)、建構式、生成器函式
- 沒有prototype屬性的函式型別:箭頭函式、物件{}中用函式ES6簡潔表示法撰寫的函式
- 每個prototype屬性,都自帶一個constructor屬性:指向本建構式
- 所有的物件都有
__proto__(原型鏈)屬性,它指向創建這個實體的類的prototype屬性 - 每個prototype屬性也是一個物件,所以也存在
__proto__屬性:它指向更高一層的類的prototype屬性 - Object是一切物件型別的基類
- Object的prototype屬性中的
__proto__屬性指向null,就是到頭了 - prototype屬性為實體提供公有方法
- 建構式的靜態方法或屬性,通過函式名.方法或屬性來定義,比如:Array.job=“array”;
3.原型鏈查找機制?
- 首先查找實體本身私有的屬性和方法,如果有就用私有的
- 如果私有里面沒有,就沿著
__proto__屬性,去第一層原型鏈中的prototype屬性中去找,如果第一層prototype上有就用第一層prototype上的公有方法 - 如果第一層prototype屬性中還沒有,就沿著第一層prototype屬性的
__proto__原型鏈繼續向上找 - 直到找到Object的prototype屬性,如果它也沒有就報錯沒有這個屬性或方法,
4.如何給js內置類擴展方法?
- 以陣列為例,Array內置類
- 擴展方法在建構式的原型(prototype)上
- Array.prototype.mypush=function(){}//給Array添加方法
- 注意:函式中的this不看在哪定義,誰呼叫函式this就是誰,
5.建構式的靜態方法、實體的私有方法、實體的公有方法都如何呼叫?
- 建構式的靜態方法呼叫:建構式名.靜態方法
- 實體的私有方法:實體名.私有方法
- 實體的公有方法:實體名.公有方法
- 實體不能使用建構式的靜態方法,
6.鏈式呼叫?
-
鏈式操作就是一直用.呼叫方法:arr.sort().reverse().push(2),
-
鏈式操作必要條件:需要注意每個點方法的回傳結果的資料型別是否能呼叫后面的方法,
- 陣列的鏈式操作:它的回傳值必須是陣列,才能繼續鏈下去,
7.in關鍵字和hasOwnProperty關鍵字?
-
in檢測私有和作用域鏈范圍,hasOwnProperty檢測私有范圍
-
“name” in “arr”:檢測某個物件是否有某個屬性或方法(不管公有私有)
-
arr.hasOwnProperty(“name”):檢測某個物件是否存在某個私有屬性或方法
-
公有還是私有,是相對來說的,主要看針對的物件是誰
8.基本資料型別是如何呼叫到方法屬性的?
-
基本資料型別也叫原始資料型別
-
參考資料型別也叫物件資料型別
-
基本資料型別的變數不存在堆中,它不是物件,所以沒有原型鏈的概念,不能呼叫屬性和方法,那為什么基本型別變數還能一些呼叫方法呢?
-
裝箱:當我們用基本資料型別呼叫方法時,系統會隱式將基本型別變數用new包裝為一個同型別物件,然后再呼叫,這就是裝箱
-
拆箱:涉及底層,先留著
9.getPropertypeOf()方法,手寫判斷是否有公有屬性的方法?
-
Object.getPrototypeOf(arr):獲取arr的原型
-
手寫判斷公有屬性或方法:
-
function Fn(name, age) { this.name = name; this.age = age; } var f1 = new Fn("lili", 18); Fn.prototype.name="haha"; // 方法一:自己的方法 Object.prototype.hasPubProperty = function (attr) { if(attr in Object.getPrototypeOf(this)){ return true; } return false; } // 方法二:老師的方法 Object.prototype.hasPubProperty2 = function (attr) { // 獲取當前物件的原型 var pro=Object.getPrototypeOf(this); var res=false; // 如果原型不是null,就回圈 while(pro){ // 如果按原型鏈找到某一層有這個屬性,就將res改為true,并回傳 if(pro.hasOwnProperty(attr)){ res=true; break; } // 如果這一層還沒有,繼續找上一層鏈 pro=Object.getPrototypeOf(pro); } return res; } console.log(f1.hasPubProperty("toString"))//true console.log(f1.hasPubProperty("age"))//false
-
10.18
1.原型重定向?
- 方式一:給建構式的prototype屬性重新指向一個新的物件,新物件中如果沒有constructor,所以會沿原型鏈去找,如果有就用自己添加的constructor
- 方式二:給建構式的prototype屬性重新指向一個new 建構式自己,
- 兩個方式的區別:方式一的constructor,指向了Object,方式二的constructor:又指向了自己,
- 內置類的prototype屬性不能被重定向,但是可以往里面增加新的方法,并且可以重寫原有的方法,
2.什么情況下獲取的值會是undefined?
(1)變數被宣告了,但沒有賦值時,就等于undefined,
(2) 呼叫函式時,應該提供的引數沒有提供,該引數等于undefined,
(3)物件沒有賦值的屬性,該屬性的值為undefined,
(4)函式沒有回傳值時,默認回傳undefined,
- this.x是到物件中找屬性,x是到作用域中找變數
- 變數沒有被宣告就會報錯,被宣告沒定義報undefined,物件中沒有的屬性會回傳undefined
3.undefined和null的區別?
- null表示沒有值,就是這個地方不應該存在值
- undefined表示**”缺少值“**,表示這里應該有值,只是還沒給值
4.函式的三種角色?
- 函式的三種角色:普通函式、建構式、普通物件
5.建構式的__proto__指向哪里?
- 所有物件都是Object類的實體,Object類是所有物件的基類
- 只要是物件就默認有
__proto__屬性
- 只要是物件就默認有
- 所有函式、類,都是Function類的實體
- 幾乎所有函式默認有
prototype屬性
- 幾乎所有函式默認有
- 建構式即是函式,又是物件,所以建構式中都有
__proto__和prototype屬性,而且__proto__指向的是Function.prototype類
6.Function與Object的關系?
-
Object.__proto__===Function.prototype:證明Object是Function的實體 -
Function.__proto__===Functon.prototype:為了讓所有的函式都能用函式類原型上的方法 -
Function.__proto__.__proto__===Object.prototype:證明Function也是物件的實體 -
Object.__proto__.__proto__===Object.prototype:為了讓所有物件能夠用物件類原型上的方法 -
Function.prototype:本質上是一個匿名空函式,所有的操作都跟物件一樣
-
總結:
- Object與Function互相為對方的實體
- 因為Object和Function即是物件,也是建構式
- 當他們作為物件角色時,他們都是Object建構式的實體,他們應該能夠呼叫Object的方法,所以他們沿著prototype的
__proto__(原型鏈)屬性都會找到Object.prototype - 當他們作為函式角色時,他們都是Function建構式的實體,他們就應該能呼叫Function的方法,所以他們的
__proto__(原型鏈)都指向了Function.prototype
- 當他們作為物件角色時,他們都是Object建構式的實體,他們應該能夠呼叫Object的方法,所以他們沿著prototype的
- 所有的建構式會沿著
__proto__屬性找到Function.prototype,沿著prototype的原型鏈找到Object.prototype
7.new和.運算子的優先級?
-
成員訪問: (xxx.xxx) 優先級20
-
new Foo(): 有引數串列new 優先級20
-
new Foo :無引數串列new 優先級19
-
優先級相同時,由左到右,由內到外運算
-
new Foo.getName():拆分為new Foo和Foo.getName(),把Foo.getName()看成整體,找到了一個函式,再執行new +函式 -
new Foo().getName():拆分為new Foo()和Foo().getName(),先執行new Foo(),再執行 前面的結果.getName() -
new new Foo().getName():由于由內到外執行,先執行第二個new以及后面的代碼,分為new Foo(),Foo().getName(),優先級相同,由左到右執行,執行完new Foo(),形成了new 上一步回傳值.getName(),再進行優先級判斷,分為了new 上一步回傳值和上一步回傳值.getName(),后者優先級高,先執行后者,獲取了實體.getName()函式,再執行new 實體.getName()函式, -
總結,重點是根據優先級得到將哪一部分看成一個整體,
10.19
1.js在客戶端運行與作為nodejs在服務器端運行的區別是什么?
- 客戶端(瀏覽器、手機瀏覽器端)有window物件.
- 服務器端(nodejs/webpack)沒有window物件.
2.瀏覽器環境下和服務器環境的js分別如何匯出?
-
瀏覽器js匯出:
-
if(window!=undefined){ window.obj=obj; }
-
-
服務器js匯出:
-
if(typeof module==="object"&&typeof module.exports=="object"){ module.exports=obj; }
-
3.call/apply/bind?
-
call和apply、bind:都是改變函式的this指向方法,他們是在function的原型上宣告的,只有函式才能呼叫call、apply、bind
-
call和apply:
-
相同點:
- 第一個引數:要指向的物件、可以是任何型別
- 第二個引數及后面的引數:傳給fn的引數
-
不同點:
- call():傳給fn的實參以散列形式傳輸
- apply():傳給fn的實參以陣列形式傳輸
-
當沒有傳入第一個引數是,默認將this指向window
-
當第一個引數是null、undefined時,this在非嚴格模式下指向window,在嚴格模式下指向undefined
-
使用apply可以用Math.min方法:Math.min.apply(arr),實作檢測陣列中的最小值
-
-
bind:
- call和apply是直接執行函式,bind是將新的更改指向this的函式回傳,不執行
- bind給函式傳參和call一樣,以散列的形式給函式傳參
4.將基本資料型別轉為物件,用new 和Object的區別?
- new Number():這種方式是呼叫建構式,Symbol()、bigint、undefined、null沒有建構式,所以不能使用該方法
- Object(Symbol("")):這種方式是轉物件型別,所有的基本資料型別都可以轉為物件型別
5.手寫call方法?
// 自己寫call
// call的作用:修改this的指向,給前面的函式傳引數
Function.prototype.call = function (point, ...args) {
// 判斷第一個引數是不是undefined或null,如果是就讓this指向window
if (point == undefined) {
point = window;
}
// 如果重新指向的目標是基本資料型別,就先把基本資料型別轉為物件,不能使用new,得用Object
if (!(typeof point == "object" || typeof point == "function")) {
point = Object(point);
}
// 如果重新指向的目標是物件型別
let result;//result用來接收obj.fn()運行的結果
point["key"] = this;//把原this變成物件的一個屬性,再用物件的方式呼叫它,它的this指向就變成了物件
result = point.key(...args);//將函式執行的結果,先放入result,后面洗掉這個屬性,這才是真正的執行fn()函式的地方,
delete point.key;//洗掉屬性
return result;//得到新的執行物件后,fn的執行結果,這也是我們想要的東西
}
var obj = {
name: "aaa"
}
function fn() {
console.log(this);
}
fn.call("aaa");
6.call方法使用的注意事項?
- 兩個及兩個的call,就可以直接視為呼叫CALL方法:fn.call.call.call.call()=>CALL方法.call()
- CALL方法.call(fn2):這樣的代碼執行,call里面的實參是什么,什么就執行,所以,這樣的寫法,call里面只能是函式,因為其他資料型別不能執行
7.類陣列轉為陣列的方法有哪些,類陣列如何使用forEach?
- 類陣列有哪些:arguments、NodeList
- 類陣列不能使用陣列中的方法,所以如果想用,就要將類陣列轉為陣列
- 方法一:let newArr=Array.from(類陣列)
- 方法二:let newArr=[…args]
- 方法三:[].slice.call(args)/Array.prototype.slice.call(args):改變slice中的this指向args,得到一個完整的陣列
- slice的底層:this指向的是要遍歷的陣列,將類陣列或者陣列的內容轉入一個新陣列,獲取的是陣列型別
- 方法四:[].concat.apply([],arguments)/[].concat.call([],…arguments):借用concat的底層原始碼機制,
- 方法五:for回圈
- 類陣列使用forEach:
- [].forEach.call(arguments,(item,index)=>{}):將陣列forEach底層方法中的this指向arguments
- 先轉為陣列,再用forEach
// 類陣列轉陣列
var ps=document.getElementsByTagName("p");
// 方式一
console.log(Array.from(ps));
// 方式二
console.log([...ps]);
//方式三
console.log([].slice.call(ps));
//方式四
console.log([].concat.apply([],ps));
console.log([].concat.call([],...ps));
//方式五
var arr=[];
for(let i=0;i<ps.length;i++){
arr.push(ps[i]);
}
console.log(arr);
// 類陣列forEach方法
[].forEach.call(ps,(item)=>{console.log(item)});
8.使用Set進行陣列去重?
arra=[1,43,4,3,2,32,32,1,321,2,1];
let newSet=new Set(arra);
console.log(Array.from(newSet));
9.ES6的基礎語法之箭頭函式?
- 簡化:
- function換成=>
- 只傳遞一個引數時:可以省略小括號
- 函式執行體只有一句時:省略{}和return
- 函式回傳的是物件時,如果省略{}和return:物件被小括號包起來:({obj})
- 區別:
- 1、寫法省略
- 2、箭頭函式沒有arguments-》使用剩余運算子接收形參
- 3、箭頭函式沒有this-》如果函式體使用了this,就沿著作用域鏈去父級背景關系找
- 4、箭頭函式沒有prototype屬性-》不能作為建構式,箭頭函式不能被new
10.ES6的基本語法之解構賦值?
- 解構賦值等號兩邊資料型別要相同:陣列、物件
- 物件解構賦值的引數能被:=號賦默認值、:起別名
- 陣列結構賦值按索引取值:左邊索引上寫變數名,=號賦默認值
11.不需要第三個值,交換兩個數的資料?
- 用解構賦值
12.模板字串?
- 用反引號包裹字串,用${}獲取外面的變數名,會保留回車和空格,就是你拼接的是啥,輸出就是啥,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/325608.html
標籤:其他
上一篇:JQuery發送Ajax請求的5種簡單使用方式,一看就會~
下一篇:你會用ES6,那倒是用啊!
