美團(tuán)-前端開發(fā)面經(jīng)(五)

點(diǎn)擊上方藍(lán)字關(guān)注我們






箭頭函數(shù)和普通函數(shù)的區(qū)別
一.外形不同:箭頭函數(shù)使用箭頭定義,普通函數(shù)中沒有
代碼實(shí)例如下:
// 普通函數(shù)function func(){// code}// 箭頭函數(shù)let func=()=>{// code}
二.箭頭函數(shù)都是匿名函數(shù)
普通函數(shù)可以有匿名函數(shù),也可以有具體名函數(shù),但是箭頭函數(shù)都是匿名函數(shù)。
代碼實(shí)例如下:
// 具名函數(shù)function func(){// code}// 匿名函數(shù)let func=function(){// code}// 箭頭函數(shù)全都是匿名函數(shù)let func=()=>{// code}
三.箭頭函數(shù)不能用于構(gòu)造函數(shù),不能使用new
普通函數(shù)可以用于構(gòu)造函數(shù),以此創(chuàng)建對(duì)象實(shí)例。
代碼實(shí)例如下:
function Person(name,age){this.name=name;this.age=age;}let admin=new Person("恩諾小弦",18);console.log(admin.name);console.log(admin.age);
代碼運(yùn)行如下:
恩諾小弦
18
Person用作構(gòu)造函數(shù),通過它可以創(chuàng)建實(shí)例化對(duì)象。
但是構(gòu)造函數(shù)不能用作構(gòu)造函數(shù)。
四.箭頭函數(shù)中this的指向不同
在普通函數(shù)中,this總是指向調(diào)用它的對(duì)象,如果用作構(gòu)造函數(shù),this指向創(chuàng)建的對(duì)象實(shí)例。
1.箭頭函數(shù)本身不創(chuàng)建this
也可以說箭頭函數(shù)本身沒有this,但是它在聲明時(shí)可以捕獲其所在上下文的this供自己使用。
注意:this一旦被捕獲,就不再發(fā)生變化
var webName="捕獲成功";let func=()=>{console.log(this.webName);}func();
運(yùn)行結(jié)果如下:
捕獲成功
代碼分析:箭頭函數(shù)在全局作用域聲明,所以它捕獲全局作用域中的this,this指向window對(duì)象。
例子:
var name = "恩諾1";function wrap(){this.name="恩諾2";let func=() => {console.log(this.name);}func();}let en=new wrap();
運(yùn)行結(jié)果如下:
恩諾2
代碼分析:
(1)wrap()用作構(gòu)造函數(shù)。
(2)使用new調(diào)用wrap()函數(shù)之后,此函數(shù)作用域中的this指向創(chuàng)建的實(shí)例化對(duì)象。
(3)箭頭函數(shù)此時(shí)被聲明,捕獲這個(gè)this。
(4)所以打印的是恩諾2,而不是恩諾1。
2.結(jié)合call(),apply()方法使用
箭頭函數(shù)結(jié)合call(),apply()方法調(diào)用一個(gè)函數(shù)時(shí),只傳入一個(gè)參數(shù)對(duì)this沒有影響。
let obj2 = {a: 10,b: function(n) {let f = (n) => n + this.a;return f(n);},c: function(n) {let f = (n) => n + this.a;let m = {a: 20};return f.call(m,n);}};console.log(obj2.b(1)); // 結(jié)果:11console.log(obj2.c(1)); // 結(jié)果:11
3.箭頭函數(shù)不綁定arguments,取而代之用rest參數(shù)…解決
每一個(gè)普通函數(shù)調(diào)用后都具有一個(gè)arguments對(duì)象,用來存儲(chǔ)實(shí)際傳遞的參數(shù)。但是箭頭函數(shù)并沒有此對(duì)象。
function A(a){console.log(arguments);}A(1,2,3,4,5,8); // [1, 2, 3, 4, 5, 8, callee: ?, Symbol(Symbol.iterator): ?]let B = (b)=>{console.log(arguments);}B(2,92,32,32); // Uncaught ReferenceError: arguments is not definedlet C = (...c) => {console.log(c);}C(3,82,32,11323); // [3, 82, 32, 11323]
4.其他區(qū)別
(1).箭頭函數(shù)不能Generator函數(shù),不能使用yeild關(guān)鍵字。
(2).箭頭函數(shù)不具有prototype原型對(duì)象。
(3).箭頭函數(shù)不具有super。
(4).箭頭函數(shù)不具有new.target。
總結(jié):
(1).箭頭函數(shù)的 this 永遠(yuǎn)指向其上下文的 this ,任何方法都改變不了其指向,如 call() , bind() , apply()
(2).普通函數(shù)的this指向調(diào)用它的那個(gè)對(duì)象


深拷貝怎么實(shí)現(xiàn)
深拷貝和淺拷貝的概念:
深拷貝拷貝的是對(duì)象或者數(shù)組內(nèi)部數(shù)據(jù)的實(shí)體,重新開辟了內(nèi)存空間存儲(chǔ)數(shù)據(jù);
淺拷貝拷貝的是引用類型的指針,副本和原數(shù)組或?qū)ο笾赶蛲粋€(gè)內(nèi)存;
另一個(gè)前提:實(shí)現(xiàn)淺復(fù)制和深復(fù)制的方法區(qū)分要看該方法是否對(duì)存在于數(shù)組或?qū)ο蟮纳顚拥囊妙愋偷闹颠M(jìn)行真實(shí)值的復(fù)制,而不是僅對(duì)引用進(jìn)行拷貝,如果這樣理解,那么下面的標(biāo)題的定義應(yīng)該要做一些修改。
一個(gè)方法是是實(shí)現(xiàn)了深拷貝還是淺拷貝,要看它是否在拷貝對(duì)象或數(shù)組時(shí),出現(xiàn)拷貝指針的情況,出現(xiàn)了就是實(shí)現(xiàn)了淺拷貝,否則就是實(shí)現(xiàn)了深拷貝;
一些建立在數(shù)組中的各項(xiàng)或?qū)ο笾械膶傩灾稻鶠榛绢愋椭档那疤嵯碌纳羁截惖睦樱?/span>
數(shù)組
1.concat方法
var arr1 = [1, 2, 3, 4]var arr2 = arr1.concat()//復(fù)制當(dāng)前數(shù)組并返回實(shí)現(xiàn)深拷貝的副本,arr1獨(dú)立而不受影響console.log(arr2);[1, 2, 3, 4]var arr3 = arr1.concat([5, 6, 7])//將數(shù)組中的每一項(xiàng)都添加到深拷貝的副本數(shù)組中console.log(arr3);//[1, 2, 3, 4, 5, 6, 7]
2.slice方法
var arr = [1, 2, 3, 4]var arr1 = arr.slice(1)//接收1到2個(gè)參數(shù),一個(gè)參數(shù)時(shí),返回參數(shù)指定調(diào)用方法數(shù)組位置到末尾的值組成的深拷貝副本console.log(arr1);//[2, 3, 4]var arr2 = arr.slice(0, 1)console.log(arr2);//[1]
3.擴(kuò)展運(yùn)算符
擴(kuò)展運(yùn)算符將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列
const arr = [1, 2, 3]const arr1 = [...arr]arr1.push(4)console.log(arr1);//[1, 2, 3, 4]console.log(arr);//[1, 2, 3]注意,對(duì)于數(shù)組項(xiàng)是引用類型的數(shù)據(jù),就無法實(shí)現(xiàn)深拷貝了。const arr = [1, 2, 3, [4, 5, 6]]const arr1 = [...arr]console.log(arr1);arr1[3].push(7)console.log(arr1);console.log(arr);//[1, 2, 3, [4, 5, 6, 7]]更改副本,原數(shù)組也被改變
對(duì)象
先看一下淺拷貝的例子
var obj = {a: 1,b: 2}var obj1 = {}obj1 = obj//淺拷貝console.log(obj1);//{a: 1, b: 2}obj1.c = 3console.log(obj);//{a: 1, b: 2, c: 3},更改obj1,obj也被改變
1.Object.assign(目標(biāo)對(duì)象, 源對(duì)象),源對(duì)象的所有可枚舉屬性都復(fù)制到目標(biāo)對(duì)象上
var obj = {a: 1,b: 2}var obj1 = {}Object.assign(obj1, obj)console.log(obj1);//{a: 1, b: 2}obj1.c = 3console.log(obj1);//{a: 1, b: 2, c: 3}console.log(obj);//{a: 1, b: 2},obj沒有被改變,實(shí)現(xiàn)了深拷貝
2.JSON
var obj = {a: 1,b: 2}// 將javascript值轉(zhuǎn)為JSON字符串var jsonText = JSON.stringify(obj)console.log(jsonText);//{"a":1,"b":2}// 把JSON字符串轉(zhuǎn)為javascript值var obj1 = JSON.parse(jsonText)console.log(obj1);//{a: 1, b: 2}// 修改obj1,看原對(duì)象值是否被改變obj1.c = 3console.log(obj1);//{a: 1, b: 2, c: 3}console.log(obj);//{a: 1, b: 2},沒被改變,實(shí)現(xiàn)了深拷貝
3.擴(kuò)展運(yùn)算符
var obj = {a: 1,b: 2}var obj1 = {...obj}console.log(obj);//{a: 1, b: 2}console.log(obj1);//{a: 1, b: 2}obj.a = 33console.log(obj);//{a: 33, b: 2}console.log(obj1);//{a: 1, b: 2}沒改變,實(shí)現(xiàn)了深拷貝
二、完全實(shí)現(xiàn)深拷貝的方法
1.JSON方法
var obj = {a: {c: 2,d: [9, 8, 7]},b: 4}var jsontext = JSON.stringify(obj)var obj1 =JSON.parse(jsontext)console.log(obj);console.log(obj1);obj.a.d[0] = 666console.log(obj);console.log(obj1);
注意,此處代碼放在node環(huán)境中運(yùn)行才會(huì)得到期望的結(jié)果;
原因?yàn)椋?/span>
并沒有什么規(guī)范或一組需求指定console.* 方法族如何工作——它們并不是JavaScript 正式的一部分,而是由宿主環(huán)境(請(qǐng)參考本書的“類型和語法”部分)添加到JavaScript 中的。因此,不同的瀏覽器和JavaScript 環(huán)境可以按照自己的意愿來實(shí)現(xiàn),有時(shí)候這會(huì)引起混淆。
尤其要提出的是,在某些條件下,某些瀏覽器的console.log(..) 并不會(huì)把傳入的內(nèi)容立即輸出。出現(xiàn)這種情況的主要原因是,在許多程序(不只是JavaScript)中,I/O 是非常低速的阻塞部分。所以,(從頁(yè)面/UI 的角度來說)瀏覽器在后臺(tái)異步處理控制臺(tái)I/O 能夠提高性能,這時(shí)用戶甚至可能根本意識(shí)不到其發(fā)生。
2.函數(shù)庫(kù)lodash的_.cloneDeep方法
var _ = require('lodash')var obj = {a: {c: 2,d: [9, 8, 7]},b: 4}var obj1 = _.cloneDeep(obj)console.log(obj === obj1);//false
3.遞歸實(shí)現(xiàn)深拷貝
function copy(object) {// 判斷傳入的參數(shù)是數(shù)組還是對(duì)象let target = object instanceof Array ? [] : {}for (const [k ,v] of Object.entries(object)) {target[k] = typeof v == 'object' ? copy(v) : v}return target}var obj1 = copy(obj)console.log(obj.a.d === obj1.a.d);//false


掃碼二維碼
獲取更多面經(jīng)
扶遙就業(yè)
