分享
定制
我們在面試的時候,經常會被面試官問到幾個手寫代碼的問題。手寫一個數組去重復,深拷貝,數組拍平等等。有些小伙伴面試之前準備了,但是在編寫的時候還是會忘掉,本文總結了一個如何應對手寫代碼的大綱,前面是一些基礎內容,但是也希望能幫助到你,都會就當復習一遍,嘿嘿。
手寫函數的時候,我每次給參數或者函數起名字都要猶豫那么幾秒。面試官還以為我不會寫嘞!
arr
和 arr+功能名稱
簡寫。其實直接可以使用 arr1,arr2 來代替,能區(qū)分開就好了,別在猶豫這種事浪費時間。
看完一道手寫面試題,可以先看下是否需要聲明新變量,需要返回的結果和結果類型等。
for (var num =1; num<=10; num++) {
document.write(num+" <br />"); //1 2 3 4 5 6 7 8 9 10
}
for-in 循環(huán)主要用于遍歷對象 for() 中的格式:for(keys in object){} keys 表示 obj 對象的每一個鍵值對的鍵??!所有循環(huán)中,需要使用obj[keys]來取到每一個值!?。?/p>
for-in 循環(huán),遍歷時不僅能讀取對象自身上面的成員屬性,也能延續(xù)原型鏈遍歷出對象的原型屬性 所以,可以使用 hasOwnProperty 判斷一個屬性是不是對象自身上的屬性
obj.hasOwnProperty(keys)==true 表示這個屬性是對象的成員屬性,而不是原先屬性。
//聲明一個Peson類
function Person(){
this.name = "kaola";
this.age = 24;
this.func1 = function(){
}
}
//實例化這個類
var bei = new Person();
//使用for-in遍歷這個對象
for(keys in bei){
console.log(bei[keys])
}
ES6 借鑒 C++、Java、C# 和 Python 語言,引入了 for...of 循環(huán),作為遍歷所有數據結構的統一的方法。
一個數據結構只要部署了 Symbol.iterator 屬性,就被視為具有 iterator 接口,就可以用 for...of 循環(huán)遍歷它的成員。也就是說,for...of 循環(huán)內部調用的是數據結構的 Symbol.iterator 方法。
for...of 循環(huán)可以使用的范圍包括數組、Set 和 Map 結構、某些類似數組的對象(比如arguments對象、DOM NodeList 對象)、后文的 Generator 對象,以及字符串。
關于遞歸的詳細內容可以看我的這篇文章,聊聊面試必考-遞歸思想與實戰(zhàn) 文章中常用的遞歸手寫代碼都用寫到。
★如何判斷數據類型?怎么判斷一個值到底是數組類型還是對象?
”
三種方式,分別為 typeof
、instanceof
和Object.prototype.toString.call()
通過 typeof
操作符來判斷一個值屬于哪種基本類型。
typeof'seymoe'// 'string'
typeoftrue// 'boolean'
typeof10// 'number'
typeofSymbol() // 'symbol'
typeofnull// 'object' 無法判定是否為 null
typeofundefined// 'undefined'
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
上面代碼的輸出結果可以看出,
null
的判定有誤差,得到的結果 如果使用 typeof null
得到的結果是object
操作符對對象類型及其子類型,例如函數(可調用對象)、數組(有序索引對象)等進行判定,則除了函數都會得到 object
的結果。
在對象的子類型和null
情況下,可以看出typeOf
對于判斷類型還有一些不足。
通過 instanceof
操作符也可以對對象類型進行判定,其原理就是測試構造函數的prototype
是否出現在被檢測對象的原型鏈上。
[] instanceofArray// true
({}) instanceofObject// true
(()=>{}) instanceofFunction// true
復制代碼注意:instanceof
也不是萬能的。
舉個例子:
let arr = []
let obj = {}
arr instanceofArray// true
arr instanceofObject// true
obj instanceofObject// true
obj instanceofArray// false
在這個例子中,arr
數組相當于 new Array()
出的一個實例,所以 arr.__proto__ === Array.prototype
,又因為 Array
屬于 Object
子類型,即Array.prototype.__proto__ === Object.prototype
,因此 Object
構造函數在 arr
的原型鏈上。所以 instanceof
仍然無法優(yōu)雅的判斷一個值到底屬于數組還是普通對象。
還有一點需要說明下,有些開發(fā)者會說 Object.prototype.__proto__ === null
,豈不是說 arr instanceof null
也應該為 true
,這個語句其實會報錯提示右側參數應該為對象,這也印證 typeof null
的結果為 object
真的只是javascript
中的一個bug
。
Object.prototype.toString()
(推薦款)可以說是判定 JavaScript
中數據類型的終極解決方法了,具體用法請看以下代碼:
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('seymoe') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(newDate()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(newSet()) // '[object Set]'
Object.prototype.toString.call(newWeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(newMap()) // '[object Map]'
Object.prototype.toString.call(newWeakMap()) // '[object WeakMap]'
我們可以發(fā)現該方法在傳入任何類型的值都能返回對應準確的對象類型。用法雖簡單明了,但其中有幾個點需要理解清楚:
Object.prototype.toString()
方法得到對象內部屬性 [[Class]]
null
和 undefined
能夠輸出結果是內部實現有做處理對于類型判斷,我們可以通過 Object.prototype.toString() 進行一個簡單的封裝,這樣我們再判斷類型的時候,直接使用 type 函數就可以了。
代碼如下:
var type = function(data) {
var toString = Object.prototype.toString;
var dataType = toString
.call(data)
.replace(/\[object\s(.+)\]/, "$1")
.toLowerCase()
return dataType
};
Array.isArray 也可以判斷傳遞參數是否是數組。需要注意的是這是 Array.isArray
是 ES 5.1
推出的,不支持 IE6~8
,所以在使用的時候也應注意兼容問題。
if (!Array.isArray) {
Array.isArray = function(arg) {
returnObject.prototype.toString.call(arg) === '[object Array]';
};
}
if([]) {
console.log('true');
} else {
consoel.log('false');
}
// res:true
if({}) {
console.log('true');
} else {
consoel.log('false');
}
// res:true
看這段代碼,不知道有沒有小伙伴會認為輸出false,以上對象和數組雖然為空,但是會被轉換為ture,所以在寫一些判斷條件時候要格外注意。
數組為空很簡單,通過上面的類型判斷是數組類型,然后它的length>0
即可
Object.getOwnPropertyNames()
使用Object.getOwnPropertyNames()
。返回值是對象中屬性明名成的數組
var obj = {}
Object.getOwnPropertyNames(obj).length === 0; // true
json 對象轉換為字符串
將json對象轉換為字符串,然后比較該字符串與"{}"是否相等
var obj = {};
var a = JSON.stringify(obj);
a === "{}"; // true
// a === {}; // false
for...in... 循環(huán)判斷
var obj = {};
function judgeObj(obj) {
for(let key in obj) {
returnfalse
}
returntrue
};
judgeObj(obj); // true
Object.keys()
使用Object.keys()。ES6的新方法,返回值同樣是屬性名組成的數組
var obj = {}
Object.keys(obj).length === 0; // true
直接使用對象屬性判斷 前提是要確定如果obj不為空,一定會包含name屬性
var obj = {};
obj && obj.name ? '不為空' : '為空'; //
比較過程:
(1)如果兩個值類型相同,再進行三個等號(===)的比較
(2)如果兩個值類型不同,也有可能相等,需根據以下規(guī)則進行類型轉換在比較:
1)如果一個是null,一個是undefined,那么相等
2)如果一個是字符串,一個是數值,把字符串轉換成數值之后再進行比較
(1)如果類型不同,就一定不相等
(2)如果兩個都是數值,并且是同一個值,那么相等;如果其中至少一個是NaN,那么不相等。(判斷一個值是否是NaN,只能使用isNaN( ) 來判斷)
(3)如果兩個都是字符串,每個位置的字符都一樣,那么相等,否則不相等。
(4)如果兩個值都是true,或是false,那么相等
(5)如果兩個值都引用同一個對象或是函數,那么相等,否則不相等
(6)如果兩個值都是null,或是undefined,那么相等
Array.splice(begin, deleteCount, addItem1, addItem2...)
// a的初始值:[1,2,3,4,5]
var b = arr.splice(1,2)
// a: [1,4,5]
// b: [2,3]
var c = arr.splice(1,2,777,888)
// a: [1,777,888,4,5]
// b: [2,3]
slice() 方法將數組中一部分元素淺復制存入新的數組對象,并且返回這個數組對象。
語法:arr.slice([start[, end]])
參數 start
指定復制開始位置的索引,end
如果有值則表示復制結束位置的索引(不包括此位置)。
如果 start
的值為負數,假如數組長度為 length
,則表示從 length+start 的位置開始復制,此時參數 end 如果有值,只能是比 start 大的負數,否則將返回空數組。
slice方法參數為空時,同concat方法一樣,都是淺復制生成一個新數組。
var array = ["one", "two", "three","four", "five"];
console.log(array.slice()); // ["one", "two", "three","four", "five"]
console.log(array.slice(2,3)); // ["three"]
淺復制 是指當對象的被復制時,只是復制了對象的引用,指向的依然是同一個對象。下面來說明slice為什么是淺復制。
var array = [{color:"yellow"}, 2, 3];
var array2 = array.slice(0,1);
console.log(array2); // [{color:"yellow"}]
array[0]["color"] = "blue";
console.log(array2); // [{color:"bule"}]
由于slice是淺復制,復制到的對象只是一個引用,改變原數組array的值,array2也隨之改變。
同時,稍微利用下 slice 方法第一個參數為負數時的特性,我們可以非常方便的拿到數組的最后一項元素,如下:
console.log([1,2,3].slice(-1));//[3]
join() 方法將數組中的所有元素連接成一個字符串。
語法 arr.join('xxx')
var b = arr.join(','); // b: '1,2,3'
var b = arr.join('*'); // b: '1*2*3'
數組中添加值。
concat() 方法將傳入的數組或者元素與原數組合并,組成一個新的數組并返回。
indexOf() 方法用于查找元素在數組中第一次出現時的索引,如果沒有,則返回-1。
語法:arr.indexOf(element, fromIndex=0)
element 為需要查找的元素。
fromIndex 為開始查找的位置,缺省默認為0。如果超出數組長度,則返回-1。如果為負值,假設數組長度為length,則從數組的第 length + fromIndex項開始往數組末尾查找,如果length + fromIndex<0 則整個數組都會被查找。
indexOf使用嚴格相等(即使用 === 去匹配數組中的元素)。
var array = ['abc', 'def', 'ghi','123'];
console.log(array.indexOf('def')); // 1
console.log(array.indexOf('def',-1)); // -1 此時表示從最后一個元素往后查找,因此查找失敗返回-1
console.log(array.indexOf('def',-4)); // 1 由于4大于數組長度,此時將查找整個數組,因此返回1
console.log(array.indexOf(123)); // -1, 由于是嚴格匹配,因此并不會匹配到字符串'123'
includes() 方法基于ECMAScript 2016(ES7)規(guī)范,它用來判斷當前數組是否包含某個指定的值,如果是,則返回 true,否則返回 false。
語法:arr.includes(element, fromIndex=0)
element 為需要查找的元素。
fromIndex 表示從該索引位置開始查找 element,缺省為0,它是正向查找,即從索引處往數組末尾查找。
var array = [-0, 1, 2];
console.log(array.includes(+0)); // true
console.log(array.includes(1)); // true
console.log(array.includes(2,-4)); // true
以上,includes似乎忽略了 -0 與 +0 的區(qū)別,這不是問題,因為JavaScript一直以來都是不區(qū)分 -0 和 +0 的。
你可能會問,既然有了indexOf方法,為什么又造一個includes方法,arr.indexOf(x)>-1不就等于arr.includes(x)?看起來是的,幾乎所有的時候它們都等同,唯一的區(qū)別就是includes能夠發(fā)現NaN,而indexOf不能。
var array = [NaN];
console.log(array.includes(NaN)); // true
console.log(arra.indexOf(NaN)>-1); // false
(這里大家可以考慮下 indexOf 和 includes 的效率誰高,和底層實現)
★數組函數有很多,上面只列舉了常用的幾個,發(fā)現一篇很全的數組函數文章,非常棒,感謝作者分享,推薦給大家:http://louiszhai.github.io/2017/04/28/array/
”
string.split(separator,limit)
substr() 方法返回字符串指定位置開始的指定數量的字符。
語法:str.substr(start[, length])
start 表示開始截取字符的位置,可取正值或負值。取正值時表示start位置的索引,取負值時表示 length+start位置的索引。
length 表示截取的字符長度。
var str = "Yesterday is history. Tomorrow is mystery. But today is a gift.";
console.log(str.substr(47)); // today is a gift.
console.log(str.substr(-16)); // today is a gift.
★數組函數有很多,上面只列舉了常用的幾個,發(fā)現一篇很全的字符串函數文章,非常棒,感謝作者分享,推薦給大家:http://louiszhai.github.io/2016/01/12/js.String/#substr
”
該方法僅在目標屬性為對象自身屬性時返回true,而當該屬性是從原型鏈中繼承而來或根本不存在時,返回false。
var o = {prop:1};
o.hasOwnProperty('prop'); // true
o.hasOwnProperty('toString'); // false
o.hasOwnProperty('formString'); // false
該方法主要用于創(chuàng)建一個新對象,并為其設置原型,用(上述)屬性描述符來定義對象的原型屬性。
var parent = {hi: 'Hello'};
var o = Object.create(parent, {
prop: {
value: 1
}
});
o.hi; // 'Hello'
// 獲得它的原型
Object.getPrototypeOf(parent) === Object.prototype; // true 說明parent的原型是Object.prototype
Object.getPrototypeOf(o); // {hi: "Hello"} // 說明o的原型是{hi: "Hello"}
o.hasOwnProperty('hi'); // false 說明hi是原型上的
o.hasOwnProperty('prop'); // true 說明prop是原型上的自身上的屬性。
現在,我們甚至可以用它來創(chuàng)建一個完全空白的對象,這樣的事情在ES3中可是做不到的。
var o = Object.create(null);
typeof o.toString(); // 'undefined'
★數組函數有很多,上面只列舉了常用的幾個,發(fā)現一篇很全的對象函數文章,非常棒,感謝作者分享,推薦給大家:https://www.lxchuan12.cn/js-object-api
”
什么是類似數組對象,舉個例子:
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
類數組轉換的幾種方式
ES6 擴展運算符進行轉換
var arr1 = [...arrayLike]; // ['a','b','c']
ES6 中的 Array.from
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.from()
的另一個應用是,將字符串轉為數組,然后返回字符串的長度。
function countSymbols(string) {
returnArray.from(string).length;
}
ES5中 Array.prototype.slice.call()
function test(a,b,c,d)
{
var arg = Array.prototype.slice.call(arguments,1);
alert(arg);
}
test("a","b","c","d"); //b,c,d
Array.prototype.slice.call(arguments)
能將具有length
屬性的對象轉成數組,除了IE
下的節(jié)點集合(因為ie下的dom對象是以com對象的形式實現的,js對象與com對象不能進行轉換)
高階函數相關內容可以看這篇文章?!綣S必知必會】高階函數詳解與實戰(zhàn)
在實現無限疊加,數組拍平,去重等都可以用到高階函數。
讓你手寫代碼的時候,可以考慮一下使用 ES6 方式如何簡潔實現。(這里大家可以去看一下ES6的擴展運算符...,set集合,箭頭函數等常用的ES6知識點,附上ES6阮一峰老師書籍學習地址:http://es6.ruanyifeng.com/)
Node.js 中有一個queryString模塊,可以實現將 urlStr 主機地址后面的參數轉化為對象。
let urlStr = 'http://www.inode.club?name=koala&study=js&study=node';
轉換結果如下:
{ name: 'koala', study: [ 'js', 'node' ] }
你可以現自己實現一下,看完本篇想一下流程
let urlStr = 'http://www.inode.club?name=koala&study=js&study=node'
// 參數轉成對象
function queryString(request){
let params = request.split('?')[1];
let param = params.split('&');
let obj = {};
for (let i = 0;i<param.length;i++){
let paramsA = param[i].split('=');
let key = paramsA[0];
let value = paramsA[1];
if(obj[key]){
obj[key] = Array.isArray(obj[key])?obj[key]:[obj[key]];
obj[key].push(value);
}else{
obj[key] = value;
}
}
return obj;
}
console.log(queryString(urlStr));
本文是一個應對手寫代碼的學習大綱,一些函數并沒有全部列全,但是大家有時間按照大綱復習一遍,再去看一些??嫉氖謱懘a問題,個人感覺能好記而且清晰了很多,希望本文能對大家有所幫助。
【使用錘子簡歷小程序制作簡歷】
零經驗實習簡歷模板
21254人用過
學生求職簡歷模板
52754人用過
申請研究生簡歷模板
2324人用過
經典工作簡歷模板
6254人用過
投行咨詢簡歷模板
12465人用過
產品經理簡歷模板
7532人用過
程序員簡歷模板
7457人用過
留學英文簡歷模板
4554人用過