1,
reflow和repaint:回流和重繪。
回流:renderTree 重建。
重繪:外觀樣式風格進行更新。(color更改)
頁面在第一次加載時候必須進行了回流操作,有回流一定伴随重繪,但是重繪不一定回流。
減少回流和重繪,也就是減少對renderTree的操作:
合并多次多DOM的修改
2,
浏覽器對頁面的呈現流程基本如下:
1)浏覽器把擷取到的html代碼解析成一個DOM樹,每個tag都是樹上的一個節點,根節點就是document對象,包括(display:none,和js動态建立的節點)
2)浏覽器把所有樣式解析成樣式結構體(定義的和代理的所有樣式),不同浏覽器會自動去掉不能識别的樣式。
3)DOM Tree 和樣式結構體合并生成 RenderTree,每個節點都有style,不包含隐藏的節點(display:none),但是包含不可見的節點(visibility:hidden)。
4)浏覽器根據RenderTree 繪制頁面
3,
記憶體洩漏
對于持續運作的服務程序,必須及時釋放不再用到的記憶體,不然記憶體會越來越多,導緻程序越來越慢,甚至系統崩潰。
不用到的記憶體沒有及時釋放,就叫記憶體洩漏。
垃圾回收機制:引用計數法。如果一個值的引用次數為0,則證明不再使用,可以釋放。如果引用次數不為0,卻不再使用,無法釋放,導緻了記憶體洩漏。
如何檢測是否存在:谷歌控制台---memory--timeline
原因:
1)全局變量(可以在js檔案開頭‘use strict’,嚴格解析,阻止意外的全局變量産生)
2)沒有及時清理定時器
3)閉包
4)超出DOM的引用
4,
const--let.png
const 隻聲明,不指派會報錯;一旦指派,就不能修改,否則也報錯,不存在變量提升,常量
let 塊級作用域,不能重複聲明,不存在變量提升
var 函數作用域,可以重複聲明
5,
三列布局,兩邊定寬,中間自适應
1)
wrap包裹.png
position-margin.png
2)
布局.png
float-margin.png
3)
布局.png
flex.png
6,
兩列布局,左邊定寬,右邊自适應
1)
float--BFC.png
2)
position--margin.png
7,
flex
傳統布局:display+position+float解決方案。
flex布局的元素稱為容器,元素内的子元素稱為容器的項目。項目預設沿着主軸排序。
image.png
設定為flex布局後,子元素的float,vertical-align,clear屬性失效。
容器屬性:
flex-direction:
row(預設)
row-reverse(主軸為水準方向,起點在右端)
column(主軸為垂直方向,起點在上沿)
column-reverse(主軸為垂直方向,起點在下沿)
flex-wrap:
nowrap(預設)/
wrap(主軸方向換行)/
wrap-reverse(換行第一行在最下邊)
flex-flow: flex-direction | flex-wrap(以上兩種簡寫)
在主軸方向:
justify-content:
flex-start(左對齊)/
flex-end(右對齊)/
center(居中)/
space-between(間隔相等,最左最右對齊)/
space-around(每個項目左右相等)
在交叉軸上:
align-items:
flex-start(上對齊)/
flex-end(下對齊)/
center(居中)/
baseline(基線對齊)/
stretch(若項目沒設定高度,則占滿整個容器高度)
align-content: 多條主軸時候起作用
flex-start(上對齊)/
flex-end(下對齊)/
center(居中)/
space-between(間隔相等,上下對齊)/
space-around(每個主軸上下相等)
stretch(軸線占滿整個交叉軸)
項目屬性:
order:數值(越小越靠前;預設是0)
flex-grow:放大倍數(預設是0)容器存在剩餘空間時候才會生效。有放大屬性的項目會根據比例平分剩餘空間。
12 123 1234 12345 123456
image.png
flex-shrink: (預設是1)縮小倍數 。容器空間不足才會生效。有放大屬性的項目會根據比例縮小不夠的空間。屬性為0,其他項目都為1,則空間不足時,前者不縮小。
12 123 1234 12345 123456
image.png
flex:0/1/auto(簡寫)
align-self: 可覆寫父元素的align-items。
auto(繼承父元素的align-items)/
flex-start
flex-end
baseline
stretch
8,
垂直水準居中
margin.png
transform.png
margin2.png
9,
position
absolute:最近的positioned的祖先元素,如果祖先都沒有positioned,相對于body
relative:偏移正常位置,其他元素不受影響
fixed:固定定位,即使滾動頁面,也不會改變相對浏覽器視窗的位置
static:預設值,沒有positioned
10,
分析輸入URL到頁面被傳回的過程:
1)輸入位址
2)浏覽器查詢IP位址(DNS查找:浏覽器緩存--系統緩存--路由緩存--遞歸搜尋)
3)浏覽器給web伺服器發送一個http請求
4)伺服器給浏覽器傳回一個永久重定向301(有利于搜素引擎SEO,兩個位址都看作同一個位址,增加了通路量;增強緩存友好性)
5)浏覽器跟蹤從定向的位址,繼續發送另一個請求
6)伺服器處理請求
7)伺服器傳回200的反應
8)浏覽器顯示HTML
9)浏覽器發送擷取嵌入在HTML中的對象的請求(靜态檔案資源)
10)浏覽器發送異步ajax請求(頁面顯示完成後,浏覽器仍與伺服器連接配接)
11,
變量提升:隻提升聲明,不提升指派
var a = 2;
function A() {
var a = 1;
console.log(a);//1
console.log(this.a)//2
}
function B() {
var a = 4;
return A;
}
B()();
12,
DNS又稱域名系統,用來解析可讀主機名(www.baidu.com)為機器可讀的IP位址(204.13.248.115)
DNS是如何工作的:
1)本地DNS緩存查詢,如果未查到結果,則進行第二步驟;
2)計算機聯系ISP(網絡服務提供商)的遞歸DNS伺服器,執行DNS查詢;如果未查詢到,進行第三步驟;
3)詢問根域名伺服器,(從右向左),将請求指向(.com)對應的頂級域伺服器(TLD.com),繼續檢查下一個資訊(baidu),并将查詢指向負責此域名的伺服器。這些權威的伺服器将資訊存儲在DNS中。
4)遞歸伺服器從權威伺服器擷取到記錄,并存在本地緩存中。(記錄都是有有效期的)
5)傳回計算機
13,
webStorage和cookie
cookie:存儲量4KB左右,比webStorage存儲小,且方式不直覺
webStorage:
localStorage:本地永久存儲,除非主動删除,不然不會消除;
sessionStorage:浏覽器頁面打開中會存在,關閉頁面,資料消失;
API:setItem(),getItem(),removeItem(),clear(),addEventListener()
14,
跨域問題
js語言安全機制--同源政策(同一協定,同一域名,同一端口号)引起的跨域問題。
解決方案:
1)jsonp實作跨域
動态建立script标簽,src屬性值為 跨域位址+傳入的資料+回調函數。執行完之後再動态删除之前建立的script.
jsonp.png
2)H5的postMessage(message,targetOrigin)
向其他window對象發送message,通過監聽其他對象message事件,來擷取傳過來的資訊。
postMessage.png
3)document.domain
試用情況:主域相同,子域不同的情況;通過控制iframe
document.png
15,
擷取url的指定參數:
字元串切割.png
16,
事件監聽
事件流:捕獲型事件(從外向内)和冒泡型事件(從内向外)
使用‘return false’阻止預設行為(送出按鈕,超連結)
1)綁定HTML元素上
image.png
2)綁定到DOM上
image.png
3)addEvent:可以添加多個事件
image.png
17,
前端性能優化
content方面:
1)減少HTTP請求(CSS Sprites,合并多個CSS檔案和js檔案)
2)減少DNS查找(主流浏覽器都是有自己獨有的緩存,而不是作業系統的;一個網站最少2個域,但不多餘四個)
3)使用AJAX緩存
4)延遲加載元件,預加載元件
5)減少DOM節點數量
6)最小化Iframe的數量
server方面:
1)使用内容分發網絡(CDN)(網站内容分散到多個CDN,處在不同地域位置的通路下載下傳速度快)
2)使用Etag(判斷浏覽器緩存和伺服器的原始内容是否比對)
3)對Ajax請求用Get
cookie方面:
1)減少cookie大小
Css方面
1)避免使用css表達式
2)使用link代提import
3)放在head中
圖檔方面:
1)優化圖檔大小
2)通過CSS Sprites整合圖檔
JS方面:
1)減少對DOM的操作
2)js和CSS檔案外部引入
3)放在頁面底部
18,
promise
函數回調成功:
resolve.png
函數回調失敗:
then文法兩個參數--成功和失敗.png
catch文法:(和失敗文法意義相同)
image.png
不同點:
出錯可以繼續執行.png
19,
js單線程,執行完主線程,浏覽器維護一個任務隊列task queue;主線程的任務執行完,去task queue中拿最先放進queue的task放到主線程,循環反複event loops
macro-task: script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, 原生Promise, Object.observe, MutationObserver
在執行完主線程的任務後,會去看micro-task隊列,把所有任務依次執行,之後再去看macro-task隊列。
image.png
20,
js子產品化的發展曆程
第一階段:無子產品化
一個JS檔案相當于一個子產品,引入多個JS檔案
第二階段:CommonJS規範
起初是用在node端的,前端的webpack也支援原生CommonJS的。
通過require方法同步加載所需要依賴的子產品,然後通過module.exports或者exports導出對外暴露的接口,解決了全局變量污染的問題。
注意:因為module.exports本身就是一個對象,是以,我們在導出時可以使用 module.exports = {foo: 'bar'} 和 module.exports.foo = 'bar'。但是, exports 是 module.exports 的一個引用,或者了解為exports是一個指針,exports指向module.exports,這樣,我們就隻能使用 exports.foo = 'bar' 的方式,而不能使用exports = {foo: 'bar'}這種方式,因為exports = {foo: 'bar'}這種方式的使用就會導緻exports指向了别的對象。
第三階段:AMD規範
非同步加載子產品,實作是require.js。适合浏覽器端。異步加載,依賴前置。
requrie([module],callback)//引用子產品
define('id',[depends],callback)//定義子產品
第四階段:CMD規範
按需加載,依賴就近,同樣實作了浏覽器端的子產品化加載。sea.js
AMD---CMD.png
第五階段:ES6子產品化
import導入---export導出
21,
js中數組方法:
forEach:讓數組中每個item做一件事(例如:輸出item);
map:讓數組中每個item進行某種運算,傳回新數組(例如:*2);
filter:選出符合條件的item,組合成新數組(例如:>4);
reduce:數組中前後兩項進行相應操作,傳回最終結果(例如:相乘);
every:數組中 所有item都滿足條件才會傳回true;
some:隻要有一個滿足條件,就傳回true;
image.png
22,
數組去重
ES6:
image.png
ES5:
image.png
reduce.png
23,
轉義符.png
24,
box-sizing:content-box
标準盒子總寬度 = margin + border + padding + content(width)
W3C标準盒模型.png
IE盒子總寬度 = margin + width(margin + padding + border)
box-sizing:border-box
怪異盒模型.png
***background填充padding
絕對定位不包含border.png
25,
vue資料雙向綁定原理及實作
1,對資料劫持監聽
Obj.defineProperty()監聽所有屬性是否變化,給屬性設定set函數,當資料改變了就會觸發set函數。讀取的時候觸發get函數。
2,結合釋出者-訂閱者模式
通知變化給訂閱者(watcher),訂閱者看是否需要更新。同時需要一個指令解析器(compile),掃描解析每個元素節點,根據相關指令初始化成一個訂閱者,并且替換模闆資料或者綁定更新函數。
釋出者-訂閱者模式.png
26,
DOM,Jquery,React
DOM:文檔對應的對象模型;
jQuery和react都是庫。
jQuery是一個JS庫,開發者使用它直接和DOM進行溝通。
React:給開發者和DOM直接建立了聯系。他的三項核心技術:
1)響應式UI
2)虛拟DOM
3)元件
27,
this 在js中的使用
this .png
28,
斐波那契數列
數列.png
29,
增加原生字元串方法
字元串重複次數方法.png
30,
同字母異序(兩個字元串,由相同字母組成,字母順序可以不同)
比較.png
31,
CSS3屬性
CSS3 2D轉換:
translate(50px,100px)平移
rotate(30deg) 旋轉
scale(2,4) 放大或縮小
skew(30deg,30deg) 翻轉
CSS3 3D轉換:
translateX/Y/Z平移
rotateX/Y/Z 旋轉
scaleX/Y/Z 放大或縮小
CSS3過渡
transition : width 2s liner 2s(CSS屬性、持續時間、動畫曲線、開始時間)
CSS3動畫
@keyframes myfirstdiv {
from{ background:yellow}
to{background:green}
}
或者
@keyframes myfirstdiv
{
0% {background: red;}
25% {background: yellow;}
50% {background: blue;}
100% {background: green;}
}
animation: myfirstdiv 5s
32,
css hack手段
解決浏覽器相容問題,跨平台應用
1)IE條件注釋法
IE條件注釋法.png
2)css屬性字首法
屬性字首.png
3)選擇器字首法
選擇器字首.png
33,
var 重複聲明
var.png
var可以重複聲明,如果重複聲明的一個變量有初始值,那就相當于複制語句;如果沒有初始值,則對之前聲明不會有任何影響.
34,
js繼承
1)
原型鍊.png
2)
構造.png
3)
執行個體.png
4)
組合.png
5)
寄生組合.png
35,
判斷一個數組是數組
1)instanceof
arr instanceof Array//true
2)constructor
arr.constructor === Array //true
arr._ _proto_ _.constructor === Array //true
instanceof 和constructor 判斷的變量,必須在目前頁面聲明的,比如,一個頁面(父頁面)有一個架構,架構中引用了一個頁面(子頁面),在子頁面中聲明了一個ary,并将其指派給父頁面的一個變量,這時判斷該變量,Array == object.constructor;會傳回false;
原因:
1、array屬于引用型資料,在傳遞過程中,僅僅是引用位址的傳遞。
2、每個頁面的Array原生對象所引用的位址是不一樣的,在子頁面聲明的array,所對應的構造函數,是子頁面的Array對象;父頁面來進行判斷,使用的Array并不等于子頁面的Array;切記,不然很難跟蹤問題!
3) Object.prototype.toString.call(a) //[object Array]
4 ) Array.isArray(arr) //true
36,
回文字元串判斷
回文.png
37,
解決for循環輸出最後一個值的問題
JS單線程原因,後調用setTimeout,此時for循環已經執行完了
閉包.png
38,
npm install react --save
npm install安裝所有依賴
webpack 進行打包
babel-loader 把ES6轉換成ES5
loader.png
webpack dev server 搭建本地伺服器;自動重新整理
node server 把app挂載到本地伺服器上
webpack dev serve --hot --inline 要想讓HMR生效,就要在應用熱替換子產品或者根子產品加入允許熱替換的代碼
jQuery 事件驅動。使用者點選button,派發事件,根據事件更新操作UI
react 資料驅動。會把資料映射到UI上,不用管UI。核心思想就是子產品化元件化。
資料:state(元件本身的資料)和props(其他元件傳入的資料)
第一次加載元件涉及到的元件生命周期順序:
image.png
image.png
react-router:
browserHistory: baidu.com/a/b
hashHistory: baidu.com/#a/b
react-router元件: 裝載頁面的元件,把元件傳給他來展示頁面
indexRoute:第一次進入系統,沒有存入URL的時候
Route
頁面切換的時候元件會被銷毀,是以根據需求把相應功能放在根元件裡。
事件訂閱:全局事件管理器,釋出事件操作,隻要訂閱事件的部分,就會監聽到事件,做事件處理。
virtual Dom : 存儲DOM資訊的資料結構,存在記憶體當中,也就是JS對象中,能夠完整描述DOM的結構。
DOM Diff:對比兩個virtual Dom ,資料更新的時候會生成新的virtual Dom 。
image.png
解決方案:immutable
元件間通信方式:
1、事件回調,
2、事件訂閱(缺乏統一管理),
3、redux(統一對系統事件的管理)
39,
ES6解構指派
image.png
變量名必須和屬性名一緻,node.name的值存給了變量名為name的變量。
40,
new四部曲
1.首先在記憶體堆上開辟一個空間存儲對象
2.this會指向執行個體也就是指向目前對象
3.設定屬性和方法,執行代碼塊
4.傳回執行個體,也就是目前對象
41,
重排序數組
image.png
42,
image.png
淺拷貝和深拷貝
淺拷貝:兩個對象同時指向一個引用位址,一個修改,其他也跟着變。位址存放在棧中。資料在堆中。
數組淺copy.png
深拷貝:
1.單層對象,沒有嵌套
對象深copy方法一.png
對象深copy方法二.png
ES6擴充運算符.png
克隆數組.png
//數組深拷貝
var arr2 = arr.slice(0);
var arr3 = arr.concat();
2.多層嵌套(以上三種 方法不好使了)
JSON對象的parse和stringify
const newObj = JSON.parse(JSON.stringify(oldObj));
JSON字元串反序列化成JS對象,stringify方法可以将JS對象序列化成JSON字元串,
// 構造函數
function person(pname) {
this.name = pname;
}
const Messi = new person('Messi');
// 函數
function say() {
console.log('hi');
};
const oldObj = {
a: say,
b: new Array(1),
c: new RegExp('ab+c', 'i'),
d: Messi
};
const newObj = JSON.parse(JSON.stringify(oldObj));
console.log(newObj.a, oldObj.a);
//undefined , ƒ say() {console.log('hi');}
console.log(newObj.b[0], oldObj.b[0]);
//null , undefined
console.log(newObj.c, oldObj.c);
// {} ,/ab+c/i
console.log(newObj.d.constructor, oldObj.d.constructor);
// ƒ Object() { [native code] }, ƒ person(pname) {this.name = pname;}
const oldObj = {};
oldObj.a = oldObj;
const newObj = JSON.parse(JSON.stringify(oldObj));
console.log(newObj.a, oldObj.a); // TypeError: Converting circular structure to JSON
1)對于正規表達式類型、函數類型等無法進行深拷貝(而且會直接丢失相應的值)。
2)它會抛棄對象的constructor。也就是深拷貝之後,不管這個對象原來的構造函數是什麼,在深拷貝之後都會變成Object。
3).對象有循環引用,會報錯
43,
this問題
全局作用域中的this指向window
函數體内的this 哪個對象調用這個函數,this指向誰
call和apply改變函數内this的指向.png
44,
ajax請求過程
1,建立XMLHttpRequest對象(異步調用對象)
2,建立新的HTTP請求,指定方法,URL和驗證資訊
3,發送HTTP請求
4,異步處理請求的資料
ajax.png
45,
url轉換成json
參數url--json.png
46,
js中的周遊
object獨有周遊方法
1
Object.keys.png
2
getOwnPropertyNames.png
3
Reflect.ownKeys.png
數組獨有周遊方法
image.png
for..of.png
for...in周遊數組index,對象key
for...in.png
47,
ES6數組的擴充
1.複制、合并數組
image.png
2.rest參數必須在數組最後一項
image.png
3.類數組轉為數組
from.png
4,
filter.png
Array()存在不足,當參數為1個時候,參數為數組長度,當參數大于1時,參數為數組值
Array.of.png
Array.prototype.copyWithin(target, start = 0, end = this.length):
target:複制到哪裡去
start:從哪裡開始
end:從哪裡結束
start和end若為負數,則是倒數 數組
copyWithin.png
find傳回第一個符合條件的成員,若沒有,傳回undefind;
findIndex:傳回第一個符合條件的成員位置,若沒有,傳回-1;
includes:傳回true或者false,第二個參數為從哪裡開始查找,若是負數,則倒數。
find.png
findIndex.png
includes.png
image.png
8.fill:填充數組
fill.png
9.flat 拉平數組
image.png
48,
js建立對象屬性加引号和不加引号對差別
var info = {
'first-name':'ss',
name:'lh'
}
在使用非法命名規則的時候,必須加引号,其他情況兩者都是可以的。還要注意的是:使用非法命名規則在擷取屬性的時候,不能用點文法(.first-name),必須使用中括号(info[first-name])。
49,
簡潔的if-else判斷寫法
當case2和case3邏輯一樣當時候,可以省去執行語句和break。
// status 活動狀态:1 開團進行中 2 開團失敗 3 商品售完 4 開團成功
const onButtonClick = (status) => {
switch (status) {
case 1:
sendLog('processing')
jumpTo('IndexPage')
break
case 2:
case 3:
sendLog('fail')
jumpTo('FailPage')
break
case 4:
sendLog('success')
jumpTo('SuccessPage')
break
default:
sendLog('other')
jumpTo('Index')
break
}
}
更新寫法:
const actions = {
'1': ['processing', 'IndexPage'],
'2': ['fail', 'FailPage'],
'3': ['fail', 'FailPage'],
'4': ['success', 'SuccessPage'],
'default': ['other', 'Index']
}
const onButtonClick1 = (status) => {
let action = actions[status] || actions['default'],
logName = action[0],
pageName = action[1];
sendLog(logName);
jumpTo(pageName);
}
Map對象: 打破了傳統對象 鍵(字元串)--值對,而現在是值--值。
const actions = new Map([
[1, ['processing', 'IndexPage']],
[2, ['fail', 'FailPage']],
[3, ['fail', 'FailPage']],
[4, ['success', 'SuccessPage']],
['default', ['other', 'Index']],
])
const onButtonClick1 = (status) => {
let action = actions.get(status) || actions.get('default');
sendLog(action[0]);
jumpTo(action[1]);
}
如果判斷條件更新為兩個,status 和 identity
最原始if--else判斷方法:
const onButtonClick = (status, identity) => {
if (identity == 'guest') {
if (status == 1) {
//do sth
} else if (status == 2) {
//do sth
} else if (status == 3) {
//do sth
} else if (status == 4) {
//do sth
} else {
//do sth
}
} else if (identity == 'master') {
if (status == 1) {
//do sth
} else if (status == 2) {
//do sth
} else if (status == 3) {
//do sth
} else if (status == 4) {
//do sth
} else {
//do sth
}
}
}
更新為Map後(把兩個判斷條件拼接成字元串):
const actions = new Map([
['guest_1', () => {}],
['guest_2', () => {}],
['guest_3', () => {}],
['guest_4', () => {}],
['master_1', () => {}],
['master_2', () => {}],
['master_3', () => {}],
['master_4', () => {}],
['default', () => {}],
]);
const onButtonClick1 = (identity, status) => {
let action = actions.get(`${identity}_${status}`) || actions.get('default');
action.call(this)
}
再更新一下,去掉字元串拼接(Map可以是任意類型對資料作為key):
const actions = new Map([
[{
identity: 'guest',
status: 1
}, () => {}],
[{
identity: 'guest',
status: 2
}, () => {}],
[{
identity: 'guest',
status: 3
}, () => {}],
])
const onButtonClick2 = (identity, status) => {
// 過濾出和參數相同的數組item
let action = [...actions].filter(([key, value]) => (key.identity == identity && key.status == status));
action.forEach(([key, value]) => value.call(this));
}
如果1和2的處理邏輯一樣呢(functionA),如下:
const actions = new Map([
[{
identity: 'guest',
status: 1
}, () => {}],
[{
identity: 'guest',
status: 2
}, () => {}],
[{
identity: 'guest',
status: 3
}, () => {}],
])
可以把處理邏輯函數進行緩存:
const actions = () => {
const functionA = () => {}
const functionB = () => {}
return new Map([
[{
identity: 'guest',
status: 1
}, functionA],
[{
identity: 'guest',
status: 2
}, functionA],
[{
identity: 'guest',
status: 3
}, functionB],
])
}
console.log([...actions()]);//[arr1, arr2, arr3]
const onButtonClick2 = (identity, status) => {
// 過濾出和參數相同的數組item
let action = [...actions()].filter(([key, value]) => (key.identity == identity && key.status == status));
action.forEach(([key, value]) => value.call(this));
}
相同處理邏輯的函數寫了好多遍,看着還是備援,可以再次更新(正規表達式作為key):
const actions = () => {
const functionA = () => {}
const functionB = () => {}
return new Map([
[/^guest_[1-2]$/, functionA],
[/^guest_3$/, functionB],
])
}
const onButtonClick2 = (identity, status) => {
// 過濾出和參數相同的數組item
let action = [...actions()].filter(([key, value]) => (key.test(`${identity}_${status}`));
action.forEach(([key, value]) => value.call(this));
}
50,編寫一個js函數,傳回一個數組,數組由實作随機生成n個11-41之間的整數,且不重複。
function foo(n) {
var arr = [];
var isNum = !isNaN(Number(n));//判斷n是不是一個數字,包含字元串類型的數字
var isRandOk = (n >= 11 && n <= 41 && n <= 30) ? true : false;//判斷n的取值是否符合要求
if (n && isRandOk && isNum) {
for (var i = 0; i < n; i++) {
var rand = Math.ceil(Math.random()*30+11);
if(arr.indexOf(rand) > -1){
i--
}else {
arr.push(rand)
}
}
}
console.log(arr);
}
foo(11);
51,不使用循環,生成一個長度100的數組,且每一個元素等同于它的下标
var arr = [...Array(100).keys()];
console.log(arr);
var arr = Array.from({length:100}, (v,k) => k);
console.log(arr);