自己收集的一些前端面試題,部分來(lái)自網(wǎng)絡(luò),部分自己寫(xiě)的,不保證正確,如有錯(cuò)誤可以評(píng)論告知。
前端性能優(yōu)化有哪些?
1.減少HTTP請(qǐng)求數(shù)
2.合理設(shè)置 HTTP緩存,很少變化的資源可以直接通過(guò) HTTP Header中的Expires設(shè)置
一個(gè)很長(zhǎng)的過(guò)期頭 ;變化不頻繁而又可能會(huì)變的資源可以使用 Last-Modifed來(lái)做請(qǐng)求驗(yàn)證
3.html,css,js,圖片等資源的合并/壓縮
4.CSS Sprites(精靈圖)
5.Inline Images(base64圖片)
6.懶加載
7.代碼按需加載(webpack)
8.'將js放于頁(yè)面的底部,css放于頂部',讓瀏覽器先加載css與html結(jié)構(gòu),以便更早的渲染出
頁(yè)面結(jié)構(gòu),腳本的運(yùn)行會(huì)阻礙資源的加載.
9.'為script增加async 或 defer來(lái)異步加載腳本'
10.避免過(guò)多的操作DOM節(jié)點(diǎn)
11.使用CDN(根據(jù)用戶ip,獲取就進(jìn)服務(wù)上的靜態(tài)資源,加快訪問(wèn)速度)
12.添加 link dns-prefetch 對(duì)于訪問(wèn)過(guò)的地址直接跳過(guò)dns解析
輸入url按下回車(chē)后發(fā)生了什么?
1.解析URL
2.DNS解析,將域名解析為IP(本地,DNS服務(wù)器,如果查找不到,頁(yè)面則無(wú)法訪問(wèn))
3.通過(guò)TCP協(xié)議,向服務(wù)器發(fā)送請(qǐng)求(三次握手,建立連接)
4.瀏覽器向web服務(wù)器發(fā)起HTTP請(qǐng)求
5.服務(wù)器接收請(qǐng)求,響應(yīng)請(qǐng)求
6.瀏覽器接收響應(yīng),開(kāi)始下載并渲染,將頁(yè)面呈現(xiàn)在我們面前
{
解析HTML生成DOM樹(shù),
解析CSS文件生成CSSOM樹(shù),
并解析Javascript代碼
CSS和DOM組合形成渲染樹(shù),
進(jìn)行布局,在瀏覽器中繪制渲染樹(shù)中節(jié)點(diǎn)的屬性(位置,寬度,大小等)
繪制元素,繪制各個(gè)節(jié)點(diǎn)的可視屬性(顏色背景等,此時(shí)可能會(huì)形成多個(gè)圖層)
合并圖層,將頁(yè)面呈現(xiàn)給用戶面前
}
強(qiáng)緩存和協(xié)商緩存
強(qiáng)緩存
強(qiáng)緩存是利用http的返回頭中的Expires或Cache-Control兩個(gè)字段來(lái)控制的,用來(lái)表示資源的緩存時(shí)間。
Expires是http1.0的規(guī)范,值為一個(gè)絕對(duì)時(shí)間的GMT格式的時(shí)間字符串,這個(gè)時(shí)間代
表著資源的失效時(shí)間,在此時(shí)間之前,即命中緩存。這種方式有一個(gè)明顯的缺點(diǎn),由
于失效時(shí)間是一個(gè)絕對(duì)時(shí)間,所以當(dāng)服務(wù)器與客戶端時(shí)間偏差較大時(shí),就會(huì)導(dǎo)致緩存混亂。
Cache-Control是http1.1時(shí)出現(xiàn)的,主要是利用該字段的`max-age`值來(lái)進(jìn)行判斷,它
是一個(gè)相對(duì)時(shí)間,例如Cache-Control:max-age=3600,代表著資源的有效期是3600
秒。
注: Expires與Cache-Control同時(shí)啟用的時(shí)候Cache-Control優(yōu)先級(jí)高。
協(xié)商緩存
協(xié)商緩存是由服務(wù)器來(lái)確定緩存資源是否可用,所以客戶端與服務(wù)器端要通過(guò)某種標(biāo)識(shí)來(lái)進(jìn)行通信,從而讓
服務(wù)器判斷請(qǐng)求資源是否可以緩存訪問(wèn),這主要涉及到下面兩組header字段,這兩組搭檔都是成對(duì)出現(xiàn)的,
即第一次請(qǐng)求的響應(yīng)頭帶上某個(gè)字段(Last-Modified或者Etag),則后續(xù)請(qǐng)求則會(huì)帶上對(duì)應(yīng)的請(qǐng)求字段(If-
Modified-Since或者If-None-Match),若響應(yīng)頭沒(méi)有Last-Modified或者Etag字段,則請(qǐng)求頭也不會(huì)有對(duì)應(yīng)的
字段。
Last-Modify/If-Modify-Since
第一次請(qǐng)求資源,服務(wù)器會(huì)加上Last-Modify,一個(gè)時(shí)間標(biāo)識(shí)該資源的最后修改時(shí)間,
再次請(qǐng)求時(shí),request的請(qǐng)求頭中會(huì)包含If-Modify-Since,該值為緩存之前返回的Last-
Modify。服務(wù)器收到If-Modify-Since后,根據(jù)資源的最后修改時(shí)間判斷是否命中緩存。
如果命中緩存,則返回304,并且不會(huì)返回資源內(nèi)容,并且不會(huì)返回Last-Modify。
ETag/If-None-Match
Etag/If-None-Match返回的是一個(gè)校驗(yàn)碼。ETag可以保證每一個(gè)資源是唯一的,資源
變化都會(huì)導(dǎo)致ETag變化。服務(wù)器根據(jù)瀏覽器上送的If-None-Match值來(lái)判斷是否命中緩存。
注: ETag 優(yōu)先級(jí)高于 Last-Modified
iframe有那些缺點(diǎn)?
*iframe會(huì)阻塞主頁(yè)面的Onload事件;
*爬蟲(chóng)無(wú)法解讀這種頁(yè)面,不利于SEO;
*iframe和主頁(yè)面共享連接池,而瀏覽器對(duì)相同域的連接有限制,所以會(huì)影響頁(yè)面的并行加載。
使用iframe之前需要考慮這兩個(gè)缺點(diǎn)。如果需要使用iframe,最好是通過(guò)javascript
動(dòng)態(tài)給iframe添加src屬性值,這樣可以繞開(kāi)以上兩個(gè)問(wèn)題。
CSS的盒子模型
IE 盒模型、標(biāo)準(zhǔn)盒模型
盒模型: 內(nèi)容(content)、填充(padding)、邊界(margin)、 邊框(border)
區(qū) 別: IE的content部分把 border 和 padding計(jì)算了進(jìn)去
BFC
塊級(jí)格式化上下文
具有 BFC 特性的元素可以看作是隔離了的獨(dú)立容器,'容器里面的元素不會(huì)在布局上影響到外面的元素',并且 BFC 具有普通容器所沒(méi)有的一些特性。
觸發(fā)BFC:
浮動(dòng)元素:float 除 none 以外的值
絕對(duì)定位元素:position (absolute、fixed)
display 為 inline-block、table-cells、flex
overflow 除了 visible 以外的值 (hidden、auto、scroll)
new操作符具體干了什么
1、創(chuàng)建一個(gè)空對(duì)象,并且 this 變量引用該對(duì)象,同時(shí)還繼承了該函數(shù)的原型。
2、屬性和方法被加入到 this 引用的對(duì)象中。
3、新創(chuàng)建的對(duì)象由 this 所引用,并且最后隱式的返回 this 。
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
實(shí)現(xiàn)一個(gè) new 操作符
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
var obj = New(A, 1, 2);
// equals to
var obj = new A(1, 2);
實(shí)現(xiàn)call、apply 與 bind
// call
Function.prototype.myCall = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context || window
context.fn = this
const args = [...arguments].slice(1)
const result = context.fn(...args)
delete context.fn
return result
}
// apply,apply與call的區(qū)別在于對(duì)參數(shù)的處理
Function.prototype.myApply = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context || window
context.fn = this
let result
// 處理參數(shù)和 call 有區(qū)別
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
// bind
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回一個(gè)函數(shù)
return function F() {
// 因?yàn)榉祷亓艘粋€(gè)函數(shù),我們可以 new F(),所以需要判斷
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
實(shí)現(xiàn) instanceOf
function instanceOf(left,right) {
let proto = left.__proto__;
let prototype = right.prototype
while(true) {
if(proto == null) return false
if(proto == prototype) return true
proto = proto.__proto__;
}
}
PC端常見(jiàn)兼容問(wèn)題
1.IE6浮動(dòng)的雙被邊距bug
解決方法:為其增加display:inline;屬性
2.IE8的input沒(méi)有placeholder
解決方法:內(nèi)容為空且沒(méi)有focus,為其設(shè)置默認(rèn)文字,focus時(shí)去除默認(rèn)文字;未focus且已輸入文字,則不設(shè)置默認(rèn)文字
3.不同瀏覽器的標(biāo)簽?zāi)J(rèn)的margin和padding不同
解決方法:重置所有標(biāo)簽{margin:0;padding:0;}
4.li標(biāo)簽之間有空白
解決方法:1. 標(biāo)簽不要換行,首尾連接;2. 父元素設(shè)置 display:inline;3. 父元素設(shè)置 font-size: 0;
5.margin重疊(取最大的)
解決方法:兩個(gè)元素外包一層div,為該div怎加overflow:hidden;(BFC)
手機(jī)端兼容問(wèn)題
1.字體、圖片模糊
解決方法:由于像素比的原因,可根據(jù)設(shè)備像素比,動(dòng)態(tài)設(shè)置meta的縮放比例。
2.ios fixed bug
解決方法:(1) header main footer 全部fixed,main區(qū)域overflow: hidden; mian區(qū)域的輸入框focus,就沒(méi)有問(wèn)題。
(2)focus時(shí),fixed改為absolute
3.點(diǎn)擊iOS的可點(diǎn)擊的元素時(shí),覆蓋顯示的高亮顏色。
解決方法:-webkit-tap-highlight-color:transparent;
4.ios中滾動(dòng)區(qū)域卡頓
解決方法:webkit-overflow-scrolling: touch; overflow-scrolling: touch;
5.Retina屏的1px邊框
解決方法:設(shè)置1px的div,將其縮放0.5。
6.transition閃屏
解決方法:
/設(shè)置內(nèi)嵌的元素在3D 空間如何呈現(xiàn):保留3D /
-webkit-transform-style: preserve-3d;
/ 設(shè)置進(jìn)行轉(zhuǎn)換的元素的背面在面對(duì)用戶時(shí)是否可見(jiàn):隱藏 /
-webkit-backface-visibility:hidden;
7.移動(dòng)端點(diǎn)擊300ms延遲
解決方法:產(chǎn)生的原因是手機(jī)要檢測(cè)雙擊,解決的方法可以用zepto的tap事件,或者使用fastclick.js,或者自己使用touch相關(guān)事件來(lái)取代click。
8.Retina屏的1px邊框
解決方法:設(shè)置1px的div,將其縮放0.5。
js繼承參考這里(https://www.cnblogs.com/humin/p/4556820.html)
ajax
// GET
//步驟一:創(chuàng)建異步對(duì)象
var ajax = new XMLHttpRequest();
//步驟二:設(shè)置請(qǐng)求的url參數(shù),參數(shù)一是請(qǐng)求的類(lèi)型,參數(shù)二是請(qǐng)求的url,可以帶參數(shù),動(dòng)態(tài)的傳遞參數(shù)starName到服務(wù)端
ajax.open('get','getStar.php?starName='+name);
//步驟三:發(fā)送請(qǐng)求
ajax.send();
//步驟四:注冊(cè)事件 onreadystatechange 狀態(tài)改變就會(huì)調(diào)用
ajax.onreadystatechange = function () {
if (ajax.readyState==4 &&ajax.status==200) {
//步驟五 如果能夠進(jìn)到這個(gè)判斷 說(shuō)明 數(shù)據(jù) 完美的回來(lái)了,并且請(qǐng)求的頁(yè)面是存在的
console.log(xml.responseText);//輸入相應(yīng)的內(nèi)容
}
}
// POST
//創(chuàng)建異步對(duì)象
var xhr = new XMLHttpRequest();
//設(shè)置請(qǐng)求的類(lèi)型及url
//post請(qǐng)求一定要添加請(qǐng)求頭才行不然會(huì)報(bào)錯(cuò)
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.open('post', '02.post.php' );
//發(fā)送請(qǐng)求
xhr.send('name=fox&age=18');
xhr.onreadystatechange = function () {
// 這步為判斷服務(wù)器是否正確響應(yīng)
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
};
jq大致原理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<script>
(function(window){
function Jquery (el) {
return new Jquery.fn.init(el)
}
Jquery.fn = Jquery.prototype = {
constructor: Jquery,
init: function (el) {
var el = document.querySelectorAll(el)
this.length = el.length
for (var i = 0; i < el.length; i++) {
this[i] = el[i]
}
},
each: function (cb) {
for (var i = 0; i < this.length; i++) {
cb.call(this[i], this[i], i)
}
},
get: function (index) {
return this[index]
},
html: function (param) {
if(typeof param !== "undefined"){
this.each(function(){
this.innerHTML = param
})
}else{
return this[0].innerHTML
}
return this
}
}
Jquery.fn.init.prototype = Jquery.fn
// jq的方法定義在Jquery.prototype上,
// Jquery.prototype.init的原型上并沒(méi)有方法
// 這一句Jquery.prototype.init與Jquery共享原型
window.$ = Jquery
})(window)
// 擴(kuò)展一個(gè)方法
$.fn.get1 = function (index) {
return this[index]
}
</script>
<body>
<h1 class="app">1</h1>
<h1 class="app">2</h1>
<h1 id="app"></h1>
</body>
<script>
console.log($('.app').get(0))
$('.app').each(function(e, i){
console.log(e)
console.log(i)
})
$('#app').html('FakeJquery')
</script>
</html>
vue原理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Two-way data-binding</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text">
{{ text }}
</div>
<script>
function observe (obj, vm) {
Object.keys(obj).forEach(function (key) {
defineReactive(vm, key, obj[key]);
});
}
function defineReactive (obj, key, val) {
var dep = new Dep();
Object.defineProperty(obj, key, {
get: function () {
// 添加訂閱者watcher到主題對(duì)象Dep
if (Dep.target) dep.addSub(Dep.target);
return val
},
set: function (newVal) {
if (newVal === val) return
val = newVal;
// 作為發(fā)布者發(fā)出通知
dep.notify();
}
});
}
function nodeToFragment (node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
compile(child, vm);
flag.appendChild(child); // 將子節(jié)點(diǎn)劫持到文檔片段中
}
return flag;
}
function compile (node, vm) {
var reg = /\{\{(.*)\}\}/;
// 節(jié)點(diǎn)類(lèi)型為元素
if (node.nodeType === 1) {
var attr = node.attributes;
// 解析屬性
for (var i = 0; i < attr.length; i++) {
if (attr[i].nodeName == 'v-model') {
var name = attr[i].nodeValue; // 獲取v-model綁定的屬性名
node.addEventListener('input', function (e) {
// 給相應(yīng)的data屬性賦值,進(jìn)而觸發(fā)該屬性的set方法
vm[name] = e.target.value;
});
node.value = vm[name]; // 將data的值賦給該node
node.removeAttribute('v-model');
}
};
new Watcher(vm, node, name, 'input');
}
// 節(jié)點(diǎn)類(lèi)型為text
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1; // 獲取匹配到的字符串
name = name.trim();
new Watcher(vm, node, name, 'text');
}
}
}
function Watcher (vm, node, name, nodeType) {
Dep.target = this;
this.name = name;
this.node = node;
this.vm = vm;
this.nodeType = nodeType;
this.update();
Dep.target = null;
}
Watcher.prototype = {
update: function () {
this.get();
if (this.nodeType == 'text') {
this.node.nodeValue = this.value;
}
if (this.nodeType == 'input') {
this.node.value = this.value;
}
},
// 獲取data中的屬性值
get: function () {
this.value = this.vm[this.name]; // 觸發(fā)相應(yīng)屬性的get
}
}
function Dep () {
this.subs = []
}
Dep.prototype = {
addSub: function(sub) {
this.subs.push(sub);
},
notify: function() {
this.subs.forEach(function(sub) {
sub.update();
});
}
};
function Vue (options) {
this.data = options.data;
var data = this.data;
observe(data, this);
var id = options.el;
var dom = nodeToFragment(document.getElementById(id), this);
// 編譯完成后,將dom返回到app中
document.getElementById(id).appendChild(dom);
}
var vm = new Vue({
el: 'app',
data: {
text: 'hello world'
}
});
</script>
</body>
</html>
算法
// 1.冒泡 O(n2)
// <1>.比較相鄰的元素。如果第一個(gè)比第二個(gè)大,就交換它們兩個(gè);
// <2>.對(duì)每一對(duì)相鄰元素作同樣的工作,從開(kāi)始第一對(duì)到結(jié)尾的最后一對(duì),這樣在最后的元素應(yīng)該會(huì)是最大的數(shù);
// <3>.針對(duì)所有的元素重復(fù)以上的步驟,除了最后一個(gè);
// <4>.重復(fù)步驟1~3,直到排序完成。
var arr1 = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
function bubbleSort (arr) {
var len = arr.length
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) {
var t = arr[j+1]
arr[j+1] = arr[j]
arr[j] = t
}
}
console.log(arr)
}
return arr
}
console.log(bubbleSort(arr1))
// 2.快排 O(nlogn)
// <1>.從數(shù)列中挑出一個(gè)元素,稱(chēng)為 “基準(zhǔn)”(pivot);
// <2>.重新排序數(shù)列,所有元素比基準(zhǔn)值小的擺放在基準(zhǔn)前面,所有元素比基準(zhǔn)值大的擺在基準(zhǔn)的后面(相同的數(shù)可以到任一邊)。在這個(gè)分區(qū)退出之后,該基準(zhǔn)就處于數(shù)列的中間位置。這個(gè)稱(chēng)為分區(qū)(partition)操作;
// <3>.遞歸地(recursive)把小于基準(zhǔn)值元素的子數(shù)列和大于基準(zhǔn)值元素的子數(shù)列排序。
var arr2 = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
function quickSort (arr) {
console.time('2.快速排序耗時(shí)')
if (arr.length <= 1) return arr
var num = arr.splice(0, 1)
// console.log(num)
var left = []
var right = []
for (var i = 0; i < arr.length; i++) {
if (arr[i] < num) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
// console.log(left)
// console.log(right)
console.timeEnd('2.快速排序耗時(shí)')
return quickSort(left).concat(num, quickSort(right))
}
console.log(quickSort(arr2))
// 3.選擇排序 O(n2)
// <1>.初始狀態(tài):無(wú)序區(qū)為R[1..n],有序區(qū)為空;
// <2>.第i趟排序(i=1,2,3…n-1)開(kāi)始時(shí),當(dāng)前有序區(qū)和無(wú)序區(qū)分別為R[1..i-1]和R(i..n)。該趟排序從當(dāng)前無(wú)序區(qū)中-選出關(guān)鍵字最小的記錄 R[k],將它與無(wú)序區(qū)的第1個(gè)記錄R交換,使R[1..i]和R[i+1..n)分別變?yōu)橛涗泜€(gè)數(shù)增加1個(gè)的新有序區(qū)和記錄個(gè)數(shù)減少1個(gè)的新無(wú)序區(qū);
// <3>.n-1趟結(jié)束,數(shù)組有序化了。
// 每次循環(huán)選擇最小的數(shù),將其放到前面
var arr3 = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
function selectionSort (arr) {
var minIndex // 當(dāng)前循環(huán)最小索引
for (var i = 0; i < arr.length - 1; i++) { // arr.length - 1 最后一個(gè)就是最大的
minIndex = i // 默認(rèn)當(dāng)前最小索引為外層循環(huán)的第一個(gè)
for (var j = i + 1; j < arr.length; j++) { // 內(nèi)循環(huán)比外循環(huán)索引多1
if( arr[j] < arr[minIndex] ){ // 內(nèi)循環(huán)的沒(méi)一個(gè)與當(dāng)前外循環(huán)對(duì)比
// 保存當(dāng)前最小索引為 j
minIndex = j
// console.log(minIndex)
}
}
// 交換當(dāng)前最小值
var t = arr[i]
arr[i] = arr[minIndex]
arr[minIndex] = t
// console.log(arr[i])
// console.log(arr[minIndex])
}
return arr
}
console.log(selectionSort(arr3))
// 4.插入排序 O(n2)
// <1>.從第一個(gè)元素開(kāi)始,該元素可以認(rèn)為已經(jīng)被排序;
// <2>.取出下一個(gè)元素,在已經(jīng)排序的元素序列中從后向前掃描;
// <3>.如果該元素(已排序)大于新元素,將該元素移到下一位置;
// <4>.重復(fù)步驟3,直到找到已排序的元素小于或者等于新元素的位置;
// <5>.將新元素插入到該位置后;
// <6>.重復(fù)步驟2~5。
var arr4 = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
function insertionSort (arr) {
if (arr.length <= 1) return arr
for (var i = 0; i < arr.length; i++) {
var key = arr[i]
var j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
return arr
}
console.log(insertionSort(arr4))
// 5.歸并排序 O(nlogn)
// <1>.把長(zhǎng)度為n的輸入序列分成兩個(gè)長(zhǎng)度為n/2的子序列;
// <2>.對(duì)這兩個(gè)子序列分別采用歸并排序;
// <3>.將兩個(gè)排序好的子序列合并成一個(gè)最終的排序序列。
var arr5 = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
function mergeSort (arr) {
var len = arr.length
if(len <= 1) return arr
var middle = Math.floor(len / 2) // 中間值
var left = arr.slice(0, middle) //
var right = arr.slice(middle)
return merge(mergeSort(left), mergeSort(right))
}
function merge (left, right) {
var result = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length)
result.push(left.shift());
while (right.length)
result.push(right.shift());
return result;
}
console.log(mergeSort(arr))
/* */
// 數(shù)組去重1
var arr6 = [3,2,3,5,47,15,3,26,4,2,46,4,19,5,48]
var removeReapt = new Set(arr6)
console.log([...removeReapt])
// 數(shù)組去重2
var arr7 = [3,2,3,5,47,15,3,26,4,2,46,4,19,5,48]
function rReapt (arr) {
var array = []
for (var i = 0; i < arr.length; i++) {
if (array.indexOf(arr[i]) == -1) {
array.push(arr[i])
}
}
return array
}
console.log(rReapt(arr7))
// 數(shù)組去重3
var arr8 = [3,2,3,5,47,15,3,26,4,2,46,4,19,5,48]
function rReapt2 (arr) {
var obj = {}
var array = []
for (var i = 0; i < arr.length; i++) {
if (!arr[i] in obj) {
obj[arr[i]] = true
}
}
for (var x in obj){
array.push(x)
}
return array
}
console.log(rReapt(arr7))
參考:
移動(dòng)端兼容:https://blog.csdn.net/hardgirls/article/details/51722519
js繼承:https://www.cnblogs.com/humin/p/4556820.html
vue原理:http://www.itdecent.cn/p/c2fa36835d77
算法:https://www.cnblogs.com/beli/p/6297741.html