1.重繪和重排問(wèn)題
2.add(2,3)和add(2)(3)問(wèn)題(再考慮他的拓展性拓展),其實(shí)是考察js函數(shù)柯里化問(wèn)題。
curry 的概念很簡(jiǎn)單:只傳遞給函數(shù)一部分參數(shù)來(lái)調(diào)用它涉兽,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)。
function add1(a){
var sum=a
var tmp=function(b){
sum= sum+ b;
return tmp;
}
tmp.valueOf=function(){
return sum;
}
return tmp;
}
var result=add1(2)(3)(4)(5)(6);
console.log('%d',result); //輸出14 '%d'會(huì)把result轉(zhuǎn)換為10進(jìn)制痊臭,從而觸發(fā)tmp的valueOf函數(shù)
因?yàn)榈阶詈髏mp(6)之后厂画,返回的是個(gè)tmp,如果輸出tmp
的話稚茅,打印的是tmp這個(gè)函數(shù)對(duì)象纸淮,如下:
console.log(result) :
{ [Function: tmp] valueOf: [Function] }
所以我們要把result轉(zhuǎn)換為10進(jìn)制,console.log('%d',result);
'%d'會(huì)把result轉(zhuǎn)換為10進(jìn)制,從而觸發(fā)tmp的valueOf函數(shù)亚享,輸出sum
還有一種方法是利用ES6語(yǔ)法中的Proxy咽块,這個(gè)方法是我在StackOverflow上看到的
function add(n) {
sum = n;
const proxy = new Proxy(function a() {}, {
get (obj, key) {
return () => sum;
},
apply (receiver, ...args) {
sum += args[1][0];
return proxy;
}
});
return proxy
}
console.log(add(1)(2)(3)); //6
console.log(add(1)(2)(3)(4)(5)(6)); //21
proxy可以理解是對(duì)目標(biāo)對(duì)象進(jìn)行代理,外界對(duì)該對(duì)象的訪問(wèn)虹蒋,都必須先通過(guò)這層攔截糜芳。
ES6 原生提供 Proxy 構(gòu)造函數(shù),用來(lái)生成 Proxy 實(shí)例魄衅。
var proxy = new Proxy(target, handler);
Proxy 對(duì)象的所有用法峭竣,都是上面這種形式,不同的只是handler參數(shù)的寫(xiě)法晃虫。其中皆撩,new Proxy()表示生成一個(gè)Proxy實(shí)例,target參數(shù)表示所要攔截的目標(biāo)對(duì)象哲银,handler參數(shù)也是一個(gè)對(duì)象扛吞,用來(lái)定制攔截行為。上面的代碼就主要用到了proxy的get 和 apply
具體Proxy的使用可以學(xué)習(xí)阮一峰的ECMAScript 6 入門(mén)
其實(shí)我在看完P(guān)roxy和他的用法之后荆责,并不知道proxy有什么優(yōu)勢(shì)滥比,只覺(jué)得它是另一種方法,而且有點(diǎn)難理解做院∶し海可能是我還不知道proxy的優(yōu)勢(shì)吧。
3.ES6中箭頭函數(shù)和普通函數(shù)的區(qū)別键耕。
1.this的區(qū)別寺滚。普通函數(shù)如果是作為對(duì)象的方法被調(diào)用的,則其 this 指向了那個(gè)調(diào)用它的對(duì)象;但是箭頭函數(shù)的則會(huì)捕獲其所在上下文的 this 值屈雄,作為自己的 this 值村视。箭頭函數(shù)需要記著這句話:“箭頭函數(shù)中沒(méi)有 this 綁定,必須通過(guò)查找作用域鏈來(lái)決定其值酒奶,如果箭頭函數(shù)被非箭頭函數(shù)包含蚁孔,則 this 綁定的是最近一層非箭頭函數(shù)的 this.
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b(); // prints undefined, Window
obj.c(); // prints 10, Object {...}
2.箭頭函數(shù)不綁定arguments,取而代之用rest參數(shù) … 解決 (rest參數(shù)介紹 )
function consol() {
console.log(arguments)
}
consol('haha',1) // { '0': 'haha', '1': 1 }
var conso = (...args)=>{ console.log(args)}
conso('hahaha',1) // [ 'hahaha', 1 ]
4.javascript閉包問(wèn)題奶赔。在網(wǎng)上看了很多關(guān)于對(duì)于什么是閉包的解釋。
看過(guò)一個(gè)答案勒虾,我覺(jué)得挺通俗易懂的纺阔。
閉包
就是把函數(shù)以及其所依賴的所有外部自由變量保存在一起的結(jié)合體
閉包
就是一個(gè)函數(shù)把外部的那些不屬于自己的對(duì)象也包含(閉合)進(jìn)來(lái)了。
參見(jiàn):如何通俗易懂的理解閉包
閉包的牛逼解答
這兩者都很好理解修然〉讯郏看一段代碼:
var foo = function(){
var name = "exe";
return function inner(){
console.log( name );
}
}
var bar = foo();//這里雖然得到的是函數(shù)inner的引用,而不是那一坨代碼
bar();//這里開(kāi)始執(zhí)行inner函數(shù) "exe" 讀取foo函數(shù)內(nèi)部的變量
這里面的 name 就是相對(duì)于函數(shù) inner( )的外部自由變量愕宋。所以inner函數(shù)就是一個(gè)閉包玻靡。
閉包的作用
它的最大用處有兩個(gè),一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量中贝,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中囤捻。(因?yàn)殚]包引用了上一級(jí)的環(huán)境,所以導(dǎo)致上一級(jí)也釋放不了邻寿。拿上例來(lái)說(shuō)蝎土,inner()函數(shù)引用name,而這個(gè)name是上一級(jí)的變量。這導(dǎo)致inner始終在內(nèi)存中绣否,而inner的存在依賴于foo誊涯,因此foo也始終在內(nèi)存中,不會(huì)在調(diào)用結(jié)束后蒜撮,被垃圾回收機(jī)制回收暴构。
閉包的原理(為什么能夠訪問(wèn)外部的自由變量)
其實(shí)就是作用域鏈。關(guān)于作用域?qū)ο蠹白饔糜蜴湹闹v解:
推薦一篇博客: JavaScript閉包的底層運(yùn)行機(jī)制
最后:
閉包是什么時(shí)候被創(chuàng)建的段磨?因?yàn)樗蠮avaScript對(duì)象都是閉包取逾,因此,當(dāng)你定義一個(gè)函數(shù)的時(shí)候苹支,你就定義了一個(gè)閉包砾隅。
閉包是什么時(shí)候被銷(xiāo)毀的?當(dāng)它不被任何其他的對(duì)象引用的時(shí)候债蜜。
5.實(shí)現(xiàn)數(shù)組扁平化處理琉用。
一種方法是用遞歸的方式。
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]))
}
else {
result.push(arr[i])
}
}
return result;
}
console.log(flatten(arr))
另一種是用ES6的擴(kuò)展運(yùn)算符 ...
擴(kuò)展運(yùn)算符 ... 可以把一個(gè)數(shù)組轉(zhuǎn)換為參數(shù)序列
var arr = [1, [2, [3, 4]]];
console.log(...arr) // ...運(yùn)算符把數(shù)組arr 轉(zhuǎn)換為 1 [2,[3,4]] 兩個(gè)參數(shù)
再用
arr = [].contact(...arr) // [1,2,[3,4]
這樣就去掉了數(shù)組的一層 順著這個(gè)方法一直繼續(xù)下去策幼,就寫(xiě)出了如下代碼
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) { //some函數(shù)會(huì)對(duì)每一個(gè)數(shù)組元素執(zhí)行一次箭頭函數(shù)
var arr = [].concat(...arr);
}
return arr;
}
console.log(flatten(arr))
中間可以輸出一下函數(shù)執(zhí)行的過(guò)程。
1 [ 2, [ 3, [ 4, 5 ] ] ]
[ 1, 2, [ 3, [ 4, 5 ] ] ]
1 2 [ 3, [ 4, 5 ] ]
[ 1, 2, 3, [ 4, 5 ] ]
1 2 3 [ 4, 5 ]
[ 1, 2, 3, 4, 5 ]
奇數(shù)行是...arr 的執(zhí)行結(jié)果
偶數(shù)行是[].concat(...arr); 的執(zhí)行結(jié)果
6.es6和es5中的繼承
ES5繼承
es5的繼承實(shí)際上是用原型鏈實(shí)現(xiàn)的奴紧,將子類的原型設(shè)置為父類的實(shí)例特姐,從而實(shí)現(xiàn)繼承
function father(){
this.flag = true;
}
function child(){
this.childFlag = false;
}
// 將子類的prototype對(duì)象指向父類的實(shí)例,實(shí)現(xiàn)繼承
child.prototype = new father();
var child1 = new child();
console.log(child1.__proto__ === child.prototype) // true
這張圖好像是我在知乎上看到的。
ES6繼承
es6繼承就很容易理解了黍氮,差不多就是java的class
詳細(xì)學(xué)習(xí)可以看阮一峰的ES6入門(mén)
7.數(shù)組去重
indexOf
var array = [1, 1, '1'];
function unique(array) {
var res = [];
for (var i = 0, len = array.length; i < len; i++) {
var current = array[i];
if (res.indexOf(current) === -1) {
res.push(current)
}
}
return res;
}
console.log(unique(array));
由于indexOf是一個(gè)一個(gè)進(jìn)行比較唐含,效率不高浅浮。
可以先對(duì)數(shù)組進(jìn)行排序,排序后,相同的值就會(huì)被排在一起捷枯,然后我們就可以只判斷當(dāng)前元素與上一個(gè)元素是否相同滚秩,相同就說(shuō)明重復(fù),不相同就添加進(jìn) res淮捆。這種方法效率高于使用 indexOf郁油。
8.淺拷貝和深拷貝
淺拷貝
對(duì)于數(shù)組和對(duì)象這種屬于引用類型的,如果淺拷貝(例如用 = 直接賦值,或者只遍歷第一層 )那么對(duì)于復(fù)雜的攀痊,具有嵌套結(jié)構(gòu)的數(shù)據(jù)來(lái)說(shuō)桐腌,淺拷貝只是拷貝了同一個(gè)引用,而這個(gè)引用指向存儲(chǔ)在堆中的一個(gè)對(duì)象苟径“刚荆拷貝完成后,兩個(gè)變量實(shí)際上將引用同一個(gè)對(duì)象棘街,如果改變其中一個(gè)變量蟆盐,就會(huì)影響另一個(gè)變量。
// 引用類型值復(fù)制
var object1 = {a: 1};
var object2 = object1;
object1.a = 2
console.log(object1) // { a: 2 }
console.log(object2) // { a: 2 }
可以看出來(lái)遭殉,改變其中一個(gè)變量石挂,另一個(gè)也會(huì)改變
深拷貝
第一種方法:使用 JSON.stringify 和 JSON.parse 方法
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
var new_arr = JSON.parse( JSON.stringify(arr));
console.log(new_arr); // [ 'old', 1, true, [ 'old1', 'old2' ], { old: 1 } ]
但是這種方法有一個(gè)問(wèn)題,不能拷貝函數(shù)恩沽。
第二種方法誊稚。利用遞歸
function deepClone(source) {
// 遞歸終止條件
if (!source || typeof source !== 'object') {
return source;
}
var targetObj = source instanceof Array ? [] : {};
for (var key in source) {
if (source.hasOwnProperty(key)){
if (source[key] && typeof source[key] === 'object') { //數(shù)組 typeof的結(jié)果也是object
targetObj[key] = deepClone(source[key]);
} else {
targetObj[key] = source[key];
}
}
}
return targetObj;
}
var object1 = {'year':12, arr: [1, 2, 3], obj: {key: 'value' }, func: function(){return 1;}};
var object2 = [1,[2,[3,4,[5,6]]]]
var newObj= deepClone(object1);
var newObj2 = deepClone(object2)
console.log(newObj) // { year: 12,arr: [ 1, 2, 3 ],obj: { key: 'value' }, func: [Function: func] }
console.log(newObj2) // [ 1, [ 2, [ 3, 4, [Array] ] ] ]