ES6及ESNext規范

1、let 和 const

    1. let引入了塊級作用域的概念, 創建setTimeout函數時,變量i在作用域內。對于循環的每個迭代,引用的i是i的不同實例。
    1. 暫時性死區:不允許變量提升
    1. const就很簡單了, 在let的基礎上, 不可被修改
 

js

代碼解讀

for(var i=0;i<=3;i++)
{ setTimeout(function(){ console.log(i) }, 10); } //4~4

原因:

  1. var定義的變量是全局的, 所以全局只有一個變量i。
  2. setTimeout是異步, 在下一輪事件循環, 等到執行的時候, 去找i變量的引用。所以函數找到了遍歷完后的i, 此時它已經變成了4。
 

js

代碼解讀

for(var i = 0; i <=3; i++) {

// 通過自執行函數滿足0,1,2,3

(function (i)

?{

? ?setTimeout(function () { console.log(i); }, 10);

?})(i);

} //0~3

for(let i=0;i<=3;i++)

{

? //通過作用域 let 滿足0,1,2,3

? setTimeout(function() { console.log(i) }, 10);

}

//0~3,let為塊級作用域

2、箭頭函數

    1. 箭頭函數里的this是定義的時候決定的, 普通函數里的this是使用的時候決定的。

const teacher = {

? name: 'zhangsan',

? getName: function() { return `${this.name}` }

}

console.log(teacher.getName()); //zhangsan

const teacher = {

? name: 'zhangsan',

? getName: () => { return `${this.name}` }

}

console.log(teacher.getName()); //undefined

箭頭函數不能被用作構造函數

構造函數: 改變this指向到新實例出來的對象.

箭頭函數: this指向是定義的時候決定的.

const arrowFn = (value) => Number(value);

console.log(arrowFn('aaa'))

const arrowFn = () => {} console.log(arrowFn) //undefined

const arrowFn = () => ({}) //如果想得到對象,需要用括號包裹

console.log(arrowFn) //{}

3、Class

    1. constructor:構造函數
    1. 可以使用set和get函數
    1. static為全局函數
    1. 直接使用變量即為類變量,無需聲明
 

js

代碼解讀

復制代碼

class Test { _name = ''; constructor() { this.name = 'zhangsan'; } static getFormatName() { return `${this.name} - xixi`; } get name() { return this._name; } set name(val) { console.log('name setter'); this._name = val; } } console.log(new Test().name) //name setter zhangsan console.log(Test.getFormatName()) //name setter Test - xixi

4、模板字符串

支持變量和對象解析和換行

 

js

代碼解讀

復制代碼

const b = 'test' const a = `${b} - xxxx`; const c = `我是換行 我換行了! `;

面試題:編寫render函數, 實現template render功能.

 

js

代碼解讀

復制代碼

//要求 const year = '2021'; const month = '10'; const day = '01'; let template = '${year}-${month}-${day}'; let context = { year, month, day }; const str = render(template)({year,month,day}); console.log(str) // 2021-10-01 //實現:高階函數(函數返回函數) function render(template) { return function(context) { return template.replace(/${(.*?)}/g, (match, key) => context[key]); } } //.*表示:任意值 //?表示:匹配前面的表達式0或1個,或制定非貪婪限定符 //表達式 .* 就是單個字符匹配任意次,即貪婪匹配。 //表達式 .*? 是滿足條件的情況只匹配一次,即最小匹配. //match: ${year} ${month} ${day} //key: year month day

參考資料:replace的mdn資料

replace() 方法返回一個由替換值(replacement)替換部分或所有的模式(pattern)匹配項后的新字符串。模式可以是一個字符串或者一個正則表達式,替換值可以是一個字符串或者一個每次匹配都要調用的回調函數。如果pattern是字符串,則僅替換第一個匹配項。

 

js

代碼解讀

復制代碼

str.replace(regexp|substr, newSubStr|function)

替換字符串可以插入下面的特殊變量名:

變量名代表的值
$$插入一個 "$"。
$&插入匹配的子串。
'$插入當前匹配的子串左邊的內容。
$'插入當前匹配的子串右邊的內容。
$n假如第一個參數是 RegExp對象,并且 n 是個小于100的非負整數,那么插入第 n 個括號匹配的字符串。提示:索引是從1開始。如果不存在第 n個分組,那么將會把匹配到到內容替換為字面量。比如不存在第3個分組,就會用“$3”替換匹配到的內容。
$<Name>這里Name 是一個分組名稱。如果在正則表達式中并不存在分組(或者沒有匹配),這個變量將被處理為空字符串。只有在支持命名分組捕獲的瀏覽器中才能使用。

函數的參數:

變量名代表的值
match匹配的子串。(對應于上述的$&。)
p1,p2, ...假如replace()方法的第一個參數是一個RegExp對象,則代表第n個括號匹配的字符串。(對應于上述的1,1,1,2等。)例如,如果是用 /(\a+)(\b+)/ 這個來匹配,p1 就是匹配的 \a+p2 就是匹配的 \b+

5、解構

    1. 數組的解構
 

js

代碼解讀

復制代碼

// 基礎類型解構 let [a, b, c] = [1, 2, 3] console.log(a, b, c) // 1, 2, 3 // 對象數組解構 let [a, b, c] = [{name: '1'}, {name: '2'}, {name: '3'}] console.log(a, b, c) // {name: '1'}, {name: '2'}, {name: '3'} // ...解構 let [head, ...tail] = [1, 2, 3, 4] console.log(head, tail) // 1, [2, 3, 4] // 嵌套解構 let [a, [b], d] = [1, [2, 3], 4] console.log(a, b, d) // 1, 2, 4 // 解構不成功為undefined let [a, b, c] = [1] console.log(a, b, c) // 1, undefined, undefined // 解構默認賦值 let [a = 1, b = 2] = [3] console.log(a, b) // 3, 2

    1. 對象的解構
 

js

代碼解讀

復制代碼

// 對象屬性解構 let { f1, f2 } = { f1: 'test1', f2: 'test2' } console.log(f1, f2) // test1, test2 // 可以不按照順序,這是數組解構和對象解構的區別之一 let { f2, f1 } = { f1: 'test1', f2: 'test2' } console.log(f1, f2) // test1, test2 // 解構對象重命名 let { f1: rename, f2 } = { f1: 'test1', f2: 'test2' } console.log(rename, f2) // test1, test2 // 嵌套解構 let { f1: {f11}} = { f1: { f11: 'test11', f12: 'test12' } } console.log(f11) // test11 // 默認值 let { f1 = 'test1', f2: rename = 'test2' } = { f1: 'current1', f2: 'current2'} console.log(f1, rename) // current1, current2

    1. 解構的原理 針對可迭代對象的Iterator接口,通過遍歷器按順序獲取對應的值進行賦值。
1、什么是Iterator接口

Iterator是一種接口,為各種不一樣的數據解構提供統一的訪問機制。任何數據解構只要有Iterator接口,就能通過遍歷操作,依次按順序處理數據結構內所有的成員。使用for of的語法遍歷數據結構時,自動尋找Iterator接口。

可迭代對象是Iterator接口的實現,有兩個協議:可迭代協議和迭代器協議。

  • 可迭代協議:對象必須實現iterator方法,即對象或其原型鏈上必須有一個名叫Symbol.iterator的屬性,該屬性的值為無參函數,函數返回迭代器協議。
  • 迭代器協議:產生一個有限或無限序列值,必須實現next()方法,方法返回對象有donevalue屬性。
2、Iterator有什么用
  • 為各種不同的數據解構提供統一的訪問接口
  • 使得數據解構能按次序排列處理
  • 可以使用ES6最新命令 for of進行遍歷
 

js

代碼解讀

復制代碼

// 生成Iterator對象 function generateIterator(array) { let nextIndex = 0 return { next: () => nextIndex < array.length ? { value: array[nextIndex++], done: false } : { value: undefined, done: true } }; } const iterator = generateIterator([0, 1, 2]) console.log(iterator.next()) // {value: 0, done: false} console.log(iterator.next()) // {value: 1, done: false} console.log(iterator.next()) // {value: 2, done: false} console.log(iterator.next()) // {value: undefine, done: true}

6、遍歷

1、for-in
  • 遍歷當前對象,還包括原型鏈上的非Symbol的可枚舉屬性
  • 不適合遍歷數組,主要應用于遍歷對象
  • 可與break,continue,return配合

缺點

  • for in 不僅會遍歷當前對象,還包括原型鏈上的可枚舉屬性 Object.prototype
  • for in 不適合遍歷數組,主要應用為對象
 

js

代碼解讀

復制代碼

let obj = { 'a': 'test1', 'b': 'test2' } for (const key in obj){ console.log(key, obj[key]) //遍歷數組時,key為數值下標字符串;遍歷對象,key為對象字段名 }

2、for-of
  • 可迭代對象(包括 Array,Map,Set,String,TypedArray,arguments對象,NodeList對象)上創建一個迭代循環,調用自定義迭代鉤子,并為每個不同屬性的值執行語句。
  • 僅遍歷當前對象
  • 可與break,continue,return配合
 

js

代碼解讀

復制代碼

let arr = [{age: 1}, {age: 5}, {age: 100}, {age: 34}] for(let {age} of arr) { if (age > 10) { break // for of 允許中斷 } console.log(age) }

7、Object

  1. Object.keys

該方法返回一個給定對象的自身可枚舉屬性組成的數組。

 

js

代碼解讀

復制代碼

const obj = { a: 1, b: 2 }; const keys = Object.keys(obj); // [a, b]

  1. Object.values 該方法返回一個給定對象自身的所有可枚舉屬性值的數組。
 

js

代碼解讀

復制代碼

const obj = { a: 1, b: 2 }; const keys = Object.keys(obj); // [1, 2]

  1. Object.entries

該方法返回一個給定對象自身可枚舉屬性的鍵值對數組。

 

js

代碼解讀

復制代碼

const obj = { a: 1, b: 2 }; const keys = Object.entries(obj); // [ [ 'a', 1 ], [ 'b', 2 ] ]

  1. Object.getOwnPropertyNames

該方法返回一個數組,該數組對元素是 obj自身擁有的枚舉或不可枚舉屬性名稱字符串。

 

js

代碼解讀

復制代碼

Object.prototype.aa = '1111'; const testData = { a: 1, b: 2 } for (const key in testData) { console.log(key); } console.log(Object.getOwnPropertyNames(testData)) // ['a','b']

  1. Object.defineProperty和Object.defineProperties

object包括屬性和方法,其中屬性分為數據屬性和訪問器屬性

  • 數據屬性

    • configurable:通過delete刪除并重新定義屬性,是否可修改屬性的特性,已經是否可把它改為訪問器屬性。
    • enumerable:是否可通過for-in循環。
    • writable:屬性值是否可修改。
    • value:屬性實際的值,默認為undefined
  • 訪問器屬性

    • configurable
    • enumerable
    • get:獲取函數,在讀取屬性時調用,默認undefined
    • set:設置函數,在寫入屬性時調用,默認undefined
  • 默認值:

    • configurable、enumerable、writable:false
    • get、set、value:undefined
    • 定義屬性時,數據屬性和訪問器屬性不能同時存在,報錯

Object.defineProperty(obj, propertyName, descriptor) //用于對象的單個屬性定義,參數:對象,屬性名稱,描述符對象

Object.defineProperties(obj, descriptor)//用于對象多個屬性定義,參數:對象、描述符對象(屬性與添加或修改的屬性一一對應)

 

js

代碼解讀

復制代碼

let test = {}; Object.defineProperty(test, 'name', { configurable: true, enumerable: true, writable: true, value: "Jian" }) let t = 0; Object.defineProperties(test, { age: { configurable: true, enumerable: true, get(){ return t }, set(newVal){ t = newVal } }, sex: { configurable: true, enumerable: true, //writable: true, value: "male" }, }) test.sex = 2 console.log('test.name', test.name) //Jian console.log('test.age', test.age) //0 console.log('test.sex', test.sex) //male, test.sex不生效

  1. Object.create
  • Object.create()方法創建一個新的對象,并以方法的第一個參數作為新對象的__proto__屬性的值(根據已有的對象作為原型,創建新的對象。)
  • Object.create()方法還有第二個可選參數,是一個對象,對象的每個屬性都會作為新對象的自身屬性,對象的屬性值以descriptor(Object.getOwnPropertyDescriptor(obj, 'key'))的形式出現,且enumerable默認為false
 

js

代碼解讀

復制代碼

const person = { isHuman: false, printIntroduction: function () { console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`); } }; const me = Object.create(person); me.name = "lubai"; me.isHuman = true; me.printIntroduction(); console.log(person); const myObject = Object.create(null)

傳入第二個參數是怎么操作的呢?

 

js

代碼解讀

復制代碼

function Person(name, sex) { this.name = name; this.sex = sex; } const b = Object.create(Person.prototype, { name: { value: 'coco', writable: true, configurable: true, enumerable: true, }, sex: { enumerable: true, get: function () { return 'hello sex' }, set: function (val) { console.log('set value:' + val) } } }) console.log(b.name) // coco console.log(b.sex) // hello sex

那么Object.create(null)的意義是什么呢? 平時創建一個對象Object.create({}) 或者 直接聲明一個{} 不就夠了?

Object.create(null)創建一個對象,但這個對象的原型鏈為null,即Fn.prototype = null

 

js

代碼解讀

復制代碼

const b = Object.create(null) // 返回純{}對象,無prototype b // {} b.__proto__ // undefined b.toString() // throw error

所以當你要創建一個非常干凈的對象, 沒有任何原型鏈上的屬性, 那么就使用Object.create(null). for in 遍歷的時候也不需要考慮原型鏈屬性了.

  1. Object.assign 合并對象,接收一個目標對象和一個或多個源對象作為參數,將每個源對象中可枚舉(Object.propertyIsEnumeralbe()返回true)和自有屬性(Object.hasOwnProperty()返回true)復制到目標對象。
  • 以字符串和符合為鍵的屬性會被復制。
  • 對每個符合條件的屬性,使用源對象上的[[get]]取得屬性的值,然后使用目標對象上的[[set]]設置屬性的值
  • 淺拷貝,類似于{...a, ...b},不能在兩個對象間轉移獲取函數和設置函數
 

js

代碼解讀

復制代碼

let dest = {} let src = {id: 'src', a: {}} let result = Object.assign(dest, src) console.log(dest === result) //true console.log(result) //{id: 'src'} console.log(dest.a === src.a) //true dest = { set a(val){ console.log(`Invoked dest setter with param ${val}`) } } src = { get a(){ console.log('Invoked src getter') return 'foo' } } Object.assign(dest, src) //Invoked src getter //Invoked dest setter with param foo console.log(dest) //{set a(val){}}

  1. Object.is
 

js

代碼解讀

復制代碼

const a = { name: 1 }; const b = a; console.log(Object.is(a, b)) // true console.log(Object.is({}, {})) // false

  1. Object.getOwnPropertyDescriptor和Object.getOwnPropertyDescriptors

返回指定對象的屬性描述符對象

 

js

代碼解讀

復制代碼

const obj1 = {} Object.defineProperty(obj1, 'p', { value: 'good', writable: false }) console.log(Object.getOwnPropertyDescriptor(obj1, 'p')) console.log(Object.getOwnPropertyDescriptors(obj1)) /* { value: 'good', writable: false, enumerable: false, configurable: false } { p: { value: 'good', writable: false, //可寫,修改屬性值 enumerable: false, //可被for in遍歷 configurable: false //刪除屬性或修改屬性特性 } } */

8、數組

  1. Array.flat

flat() 方法會按照一個可指定的深度遞歸遍歷數組,并將所有元素與遍歷到的子數組中的元素合并為一個新數組返回

 

js

代碼解讀

復制代碼

const arr1 = [1, 2, [3, 4]]; arr1.flat(); // [1, 2, 3, 4] const arr2 = [1, 2, [3, 4, [5, 6]]]; arr2.flat(); // [1, 2, 3, 4, [5, 6]] const arr3 = [1, 2, [3, 4, [5, 6]]]; arr3.flat(2); // [1, 2, 3, 4, 5, 6] //使用 Infinity,可展開任意深度的嵌套數組(無限大) const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]]; arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

  1. Array.includes includes() 方法用來判斷一個數組是否包含一個指定的值,根據情況,如果包含則返回 true,否則返回false。 Array.includes(valueToFind, fromIndex)
 

js

代碼解讀

復制代碼

const array1 = [1, 2, 3]; console.log(array1.includes(2)); const pets = ['cat', 'dog', 'bat']; console.log(pets.includes('cat'));

其實它有兩個參數, 只不過我們平時只使用一個.

  • valueToFind 需要查找的元素值。

  • fromIndex 可選 從fromIndex 索引處開始查找 valueToFind。如果為負值,則按升序從 array.length + fromIndex 的索引開始搜 (即使從末尾開始往前跳 fromIndex 的絕對值個索引,然后往后搜尋)。默認為 0。

 

js

代碼解讀

復制代碼

[1, 2, 3].includes(2); // true [1, 2, 3].includes(4); // false [1, 2, 3].includes(3, 3); // false [1, 2, 3].includes(3, -1); // true [1, 2, NaN].includes(NaN); // true // fromIndex 大于等于數組長度 var arr = ['a', 'b', 'c']; arr.includes('c', 3); // false arr.includes('c', 100); // false // 計算出的索引小于 0 var arr = ['a', 'b', 'c']; arr.includes('a', -100); // true arr.includes('b', -100); // true arr.includes('c', -100); // true

  1. Array.find find() 方法返回數組中滿足提供的測試函數的第一個元素的值。否則返回 undefined。 Array.find(callback(element, index, array(數組本身)))

callback 在數組每一項上執行的函數,接收 3 個參數:

  • element 當前遍歷到的元素。
  • index可選 當前遍歷到的索引。
  • array可選 數組本身。
 

js

代碼解讀

復制代碼

const test = [ {name: 'lubai', age: 11 }, {name: 'xxx', age: 100 }, {name: 'nnn', age: 50} ]; function findLubai(teacher) { return teacher.name === 'lubai'; } console.log(test.find(findLubai));

  1. Array.from
  • 4.1 Array.from() 方法從一個類似數組或可迭代對象創建一個新的,淺拷貝的數組實例。

    • arrayLike 想要轉換成數組的偽數組對象或可迭代對象。
    • mapFn 可選 如果指定了該參數,新數組中的每個元素會執行該回調函數。
  • 4.2 Array.from() 可以通過以下方式來創建數組對象:

  • 偽數組對象(擁有一個 length 屬性和若干索引屬性的任意對象)
  • 可迭代對象(可以獲取對象中的元素,如 Map和 Set 等)
 

js

代碼解讀

復制代碼

console.log(Array.from('foo')); console.log(Array.from([1, 2, 3], x => x + x)); const set = new Set(['foo', 'bar', 'baz', 'foo']); Array.from(set); // [ "foo", "bar", "baz" ] const map = new Map([[1, 2], [2, 4], [4, 8]]); Array.from(map); // [[1, 2], [2, 4], [4, 8]] const mapper = new Map([['1', 'a'], ['2', 'b']]); Array.from(mapper.values()); // ['a', 'b']; Array.from(mapper.keys()); // ['1', '2'];

所以數組去重我們可以怎么做?

 

js

代碼解讀

復制代碼

function unique (arr) { return Array.from(new Set(arr)) // return [...new Set(arr)] } const test = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a']; console.log(unique(test)); function unique(arr) { const map = new Map(); const array = []; // 數組用于返回結果 for (let i = 0; i < arr.length; i++) { if (!map.has(arr[i])) { // 如果有該key值 array.push(arr[i]); map.set(arr[i], true); } } return array; } function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return } const array = []; for (let i = 0; i < arr.length; i++) { if (!array.includes(arr[i])) { //includes 檢測數組是否有某個值 array.push(arr[i]); } } return array }

  1. Array.of

Array.of() 方法創建一個具有可變數量參數的新數組實例,而不考慮參數的數量或類型。

 

js

代碼解讀

復制代碼

Array.of(7); // [7] Array.of(1, 2, 3); // [1, 2, 3]

那怎么去模擬實現它呢?

 

js

代碼解讀

復制代碼

Array.of = function() { return Array.prototype.slice.call(arguments); };

9、反射Reflect和代理Proxy

  • 反射Reflect

    • 將Object對象上的明顯屬于語言內部的方法,放在Reflect對象上
    • 讓Object操作變為函數行為,eg:name in obj和delete,變為Reflect.has(obj,name)和Reflect.deleteProperty(obj,name)
    • Reflect對象的方法與Proxy對象的方法一一對應。讓Proxy對象可以方便的調用對應的Reflect方法,完成默認行為。
    • 通過defineProperty設置writable為false的對象,不能使用Proxy
  • 代理Proxy

    • 定義: const proxy = new Proxy(target, handler),target代理對象,handle捕獲器
    • handle參數get:trapTarget(目標對象),property(代理屬性),receiver(代理對象)
    • handle參數set:trapTarget(目標對象),property(代理屬性),value(賦給屬性的值),receiver(代理對象)
 

js

代碼解讀

復制代碼

const target = { foo: 'bar', baz: 'qux' } const handler = { get(trapTarget, property, receiver){ let decoration = '' if(property === 'foo'){ decoration = '!!!' } return Reflect.get(...arguments) + decoration }, set(trapTarget, property, value, receiver){ return Reflect.set(...arguments) + 'set' } } const proxy = new Proxy(target, handler) proxy.foo = 'good' console.log(proxy.foo) //good!!! console.log(target.foo)//good

3、 面試題

1、如何生成Iterator對象?

 

js

代碼解讀

復制代碼

function generateIterator(array) { let nextIndex = 0 return { next: () => nextIndex < array.length ? { value: array[nextIndex++], done: false } : { value: undefined, done: true } }; } const iterator = generateIterator([0, 1, 2]) console.log(iterator.next()) // {value: 0, done: false} console.log(iterator.next()) // {value: 1, done: false} console.log(iterator.next()) // {value: 2, done: false} console.log(iterator.next()) // {value: undefine, done: true}

2、如何實現一個可以for of遍歷的對象?

 

js

代碼解讀

復制代碼

// 面試題: 實現一個可以for of遍歷的對象 const obj = { count: 0, [Symbol.iterator]: () => { return { next: () => { obj.count++; if (obj.count <= 10) { return { value: obj.count, done: false } } else { return { value: undefined, done: true } } } } } } for (const item of obj) { console.log(item) }

或者

 

js

代碼解讀

復制代碼

const iterable = { 0: 'a', 1: 'b', 2: 'c', length: 3, [Symbol.iterator]: Array.prototype[Symbol.iterator], }; for (const item of iterable) { console.log(item); }

3、如何手寫實現一個函數模擬Object.keys?

 

js

代碼解讀

復制代碼

function getObjectKeys(obj) { const result = []; for (const prop in obj) { if (obj.hasOwnProperty(prop)) { //注意 當使用for in遍歷對象時,一定要進行hasOwnProperty判斷,否則會遍歷原型鏈上的值 result.push(prop); } } return result; } console.log(getObjectKeys({ a: 1, b: 2 }))

4、如何手寫實現一個函數模擬Object.values?

 

js

代碼解讀

復制代碼

function getObjectValues(obj) { const result = []; for (const prop in obj) { if (obj.hasOwnProperty(prop)) { result.push(obj[prop]); } } return result; } console.log(getObjectValues({ a: 1, b: 2 }))

5、如何手寫實現一個函數模擬Object.entries?

 

js

代碼解讀

復制代碼

function getObjectEntries(obj) { const result = []; for (const prop in obj) { if (obj.hasOwnProperty(prop)) { result.push([prop, obj[prop]]); } } return result; } console.log(getObjectEntries({ a: 1, b: 2 }))

6、如何實現一個淺拷貝函數?

 

js

代碼解讀

復制代碼

// 實現淺拷貝函數 function shallowClone(source) { const target = {}; for (const i in source) { if (source.hasOwnProperty(i)) { target[i] = source[i]; } } return target; } const a = { b: 1, c: { d: 111 } } const b = shallowClone(a); b.b = 2222; b.c.d = 333; console.log(b) // { b: 2222, c: { d: 333 } } console.log(a) // { b: 1, c: { d: 333 } }

7、如何模擬實現Array.flat?

 

js

代碼解讀

復制代碼

// 使用 reduce、concat 和遞歸展開無限多層嵌套的數組 const arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]]; function flatDeep(arr, d = 1) { if (d > 0) { return arr.reduce((res, val) => { if (Array.isArray(val)) { res = res.concat(flatDeep(val, d - 1)) } else { res = res.concat(val); } return res; }, []) } else { return arr.slice() } }; console.log(flatDeep(arr1, Infinity)) // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

如果不考慮深度, 咱們直接給他無限打平

 

js

代碼解讀

復制代碼

function flatten(arr) { let res = []; let length = arr.length; for (let i = 0; i < length; i++) { if (Object.prototype.toString.call(arr[i]) === '[object Array]') { res = res.concat(flatten(arr[i])) } else { res.push(arr[i]) } } return res } // 如果數組元素都是Number類型 function flatten(arr) { return arr.toString().split(',').map(item => +item) } function flatten(arr){ while(arr.some(item=>Array.isArray(item))){ arr = [].concat(...arr); } return arr; }

8、 for in 與 for of 的區別?

for in: 遍歷數組輸出索引,遍歷對象輸出key;

 

markdown

代碼解讀

復制代碼

缺點: 1.不僅會遍歷當前對象,還會遍歷原型鏈上的屬性; 2.不適合遍歷數組

for of: 僅遍歷當前對象

forEach 不會被break中斷

9、如何把arguments轉換成真數組?

  1. [...arguments]
  2. Array.from(arguments)
  3. Array.prototype.slice.call()

作者:揚子鱷
鏈接:https://juejin.cn/post/7067840528246636575
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/45785.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/45785.shtml
英文地址,請注明出處:http://en.pswp.cn/web/45785.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《背包亂斗》為什么好玩 蘋果電腦怎么玩《背包亂斗》游戲 mac怎么玩steam windows游戲

在當今競爭激烈的游戲市場中&#xff0c;《背包亂斗》以其獨特的魅力在眾多作品中脫穎而出&#xff0c;吸引了大量玩家的關注和喜愛。其創新的游戲機制和不斷迭代的內容&#xff0c;加之出色的視覺效果和社區建設&#xff0c;使其成為了游戲界的一股清流。 一、《背包亂斗》為…

Hadoop學習記錄一

HDFS&#xff08;Hadoop Distributed File System&#xff09;是Hadoop項目的一部分&#xff0c;用于存儲海量數據。HDFS設計為可以在廉價硬件上運行&#xff0c;同時提供高容錯性。HDFS主要由三個關鍵角色組成&#xff1a;NameNode、DataNode和SecondaryNameNode。下面我用大白…

《絕區零》是一款什么類型的游戲,Mac電腦怎么玩《絕區零》蘋果電腦玩游戲怎么樣

米哈游的《絕區零》最近在網上爆火呀&#xff0c;不過很多人都想知道mac電腦能不能玩《絕區零》&#xff0c;今天麥麥就給大家介紹一下《絕區零》是一款什么樣的游戲&#xff0c;Mac電腦怎么玩《絕區零》。 一、《絕區零》是一款什么樣的游戲 《絕區零》是由上海米哈游自主研發…

Web前端-Web開發HTML基礎1-input

一. 基礎 1. 寫一個輸入框代碼&#xff0c;類型為密碼&#xff1b; 2. 寫一個輸入框代碼&#xff0c;類型為密碼&#xff1b; 3. 寫一個輸入框代碼&#xff0c;類型為密碼&#xff0c;名稱為"password"&#xff1b; 4. 寫一個輸入框代碼&#xff0c;類型為密碼&#…

ES快速開發,ElasticsearchRestTemplate基本使用以及ELK快速部署

最近博主有一些elasticsearch的工作&#xff0c;所以更新的慢了些&#xff0c;現在就教大家快速入門&#xff0c;并對一些基本的查詢、更新需求做一下示例&#xff0c;廢話不多說開始&#xff1a; 1. ES快速上手 es下載&#xff1a;[https://elasticsearch.cn/download/]()這…

Spring Boot集成Activity7實現簡單的審批流

由于客戶對于系統里的一些新增數據&#xff0c;例如照片墻、照片等&#xff0c;想實現上級逐級審批通過才可見的效果&#xff0c;于是引入了Acitivity7工作流技術來實現&#xff0c;本文是對實現過程的介紹講解&#xff0c;由于我是中途交接前同事的這塊需求&#xff0c;所以具…

uniapp開發釘釘小程序流程

下載開發工具 1、小程序開發工具 登錄釘釘開發平臺&#xff0c;根據自己的需求下載合適的版本&#xff0c;我這里下載的是Windows &#xff08;64位&#xff09;版本 小程序開發工具 - 釘釘開放平臺 2、HBuilder X HBuilderX-高效極客技巧 新建項目及相關配置 新建項目 …

Llama - Prompting

本文翻譯整理自&#xff1a;Prompting https://llama.meta.com/docs/how-to-guides/prompting/ 文章目錄 制作有效的提示明確說明風格化格式化限制 提示使用 Zero- and Few-Shot 學習Zero-Shot PromptingFew-Shot Prompting 基于角色的提示思維鏈技術Self-Consistency檢索-增強…

單臂路由組網實驗,單臂路由的定義、適用情況、作用

一、定義 單臂路由是指通過在路由器的一個接口上配置許多子接口,從而實現原來相互隔離的不同VLAN之間的互通。 子接口:把路由器上的實際的物理接口劃分為多個邏輯上的接口,這些被劃分的邏輯接口就是子接口。 二、適用情況 用在沒有三層交換機,卻要實現不同VLAN之間的互…

Github07-16 Python開源項目日報 Top10

根據Github Trendings的統計,今日(2024-07-16統計)共有10個項目上榜。根據開發語言中項目的數量,匯總情況如下: 開發語言項目數量Python項目10C++項目1AutoGPT: 人工智能革命的先鋒 創建周期:486 天開發語言:Python協議類型:MIT LicenseStar數量:164105 個Fork數量:435…

axios 下載大文件時,展示下載進度的組件封裝——js技能提升

之前面試的時候&#xff0c;有遇到一個問題&#xff1a;就是下載大文件的時候&#xff0c;如何得知下載進度&#xff0c;當時的回復是沒有處理過。。。 現在想到了。axios中本身就有一個下載進度的方法&#xff0c;可以直接拿來使用。 下面記錄一下處理步驟&#xff1a; 參考…

深度學習 | CNN 基本原理

目錄 1?什么是 CNN2?輸入層3?卷積層3.1?卷積操作3.2?Padding 零填充3.3?處理彩色圖像 4?池化層4.1?池化操作4.2?池化的平移不變性 5?全連接層6?輸出層 前言 這篇博客不夠詳細&#xff0c;因為沒有介紹卷積操作的具體計算&#xff1b;但是它介紹了 CNN 各層次的功能…

golang AST語法樹解析

1. 源碼示例 package mainimport ("context" )// Foo 結構體 type Foo struct {i int }// Bar 接口 type Bar interface {Do(ctx context.Context) error }// main方法 func main() {a : 1 }2. Golang中的AST golang官方提供的幾個包&#xff0c;可以幫助我們進行A…

[雜談] 關于 Mac 電腦使用 Logitech 鼠標導致 Vscode 側鍵無法進行代碼前進、回退的問題

我個人使用的是一臺 14 寸的 Mac_Apple_M1&#xff0c;外接鍵盤顯示器羅技的 MX Master 3 for Mac 的鼠標。 之前一直使用的 GoLand 開發&#xff0c;查看代碼時進行代碼跳轉就很方便&#xff0c;滾輪鍵 進入函數方法&#xff0c;鼠標側鍵進行前進、后退。看代碼完全可以右手單…

【大模型入門】LLM-AI大模型介紹

大語言模型 (LLM) 背景 &#x1f379;大語言模型 (Large Language Model) 是一種人工智能模型, 它們通常包含數千億甚至更多的參數&#xff0c;并在大規模數據集上進行訓練。大語言模型可以處理多種自然語言任務&#xff0c;如文本分類、問答、翻譯、對話等等。 自然語言模型…

qt explicit 啥意思

explicit 在 Qt 和 C 中是一個關鍵字&#xff0c;主要用于修飾類的構造函數。其含義和用法可以歸納為以下幾點&#xff1a; 意義&#xff1a; explicit 英文直譯為“明確的”、“顯式的”。在 C 中&#xff0c;當一個構造函數只接受一個參數時&#xff0c;它可能會被編譯器用于…

【Nail it】ROS1 ROS2 通信(ros2/ros1_bridge)

情況說明&#xff1a;目標是實現ros2容器和ros1主機的通信&#xff0c;可以起一個ros1容器作為橋梁&#xff08;若是在一個主機同時包含ros1&ros2&#xff0c;配置更加方便&#xff09;. 1.起一個 noetic 的容器 docker run -it --network host --name my_bridge ros:noe…

Java中的成員內部類

Java中的成員內部類&#xff08;也稱為非靜態內部類&#xff09;是定義在另一個類&#xff08;外部類&#xff09;內部的類。 這種內部類與它的外部類之間有著緊密的聯系&#xff0c;主要體現在幾個方面&#xff1a;它可以訪問外部類的所有成員&#xff08;包括私有成員&#…

C++小白Python選手2小時入門C++

學習鏈接&#xff1a;C入門/2小時從C到C快速入門&#xff08;2018&#xff0c;C教程&#xff09; C在C語言的基礎上增加了面向對象和通用算法語言特征。 C頭文件不必是.h結尾&#xff0c;C頭文件舉例&#xff1a;cmath、cstdio注釋&#xff1a;單行//、多行/**/為了防止名字沖…

MQ基礎1

對應B站視頻&#xff1a; MQ入門-01.MQ課程介紹_嗶哩嗶哩_bilibili 微服務一旦拆分&#xff0c;必然涉及到服務之間的相互調用&#xff0c;目前我們服務之間調用采用的都是基于OpenFeign的調用。這種調用中&#xff0c;調用者發起請求后需要等待服務提供者執行業務返回結果后…