1、運行下面代碼,請依次寫出控制檯打印的順序。
console.log(1)
setTimeout(()=>console.log(2), 0)
new Promise((resolve,reject)=>{
console.log(3)
setTimeout(()=>resolve(4), 0)
}).then(res=>{
console.log(res)
console.log(5)
})
requestAnimationFrame(()=>console.log(6))
console.log(7)
答案:有可能是1 3 7 6 2 4 5
,也有可能是1 3 7 2 4 5 6
。
2、封裝方法 arr2tree,把下面數組轉化成樹結構。
# 輸入:源數組
var arr = [
{ id: 0, name: '新聞' },
{ id: 1, name: '體育', pid: 0 },
{ id: 2, name: '籃球', pid: 1 },
{ id: 3, name: '足球', pid: 1 },
{ id: 4, name: 'NBA', pid: 2 },
{ id: 5, name: 'CBA', pid: 2 },
{ id: 6, name: '娛樂', pid: 0 },
{ id: 7, name: '小品', pid: 6 },
{ id: 8, name: '相聲', pid: 6 },
]
# 輸出:樹結構
var tree = [
{
"id": 0, "name": "新聞",
"children": [
{
"id": 1, "name": "體育", "pid": 0,
"children": [
{
"id": 2, "name": "籃球", "pid": 1,
"children": [
{ "id": 4, "name": "NBA", "pid": 2 },
{ "id": 5, "name": "CBA", "pid": 2 }
]
},
{ "id": 3, "name": "足球", "pid": 1 }
]
},
{
"id": 6, "name": "娛樂", "pid": 0,
"children": [
{ "id": 7, "name": "小品", "pid": 6 },
{ "id": 8, "name": "相聲", "pid": 6 }
]
}
]
}
]
# 參考答案
function arr2tree(sourceArr) {
let obj = {}
for (let i = 0; i < sourceArr.length; i++) {
obj[sourceArr[i].id] = sourceArr[i]
}
const result = []
sourceArr.forEach(node => {
if (!obj[node.pid]) {
result.push(node)
return
}
obj[node.pid].children = obj[node.pid].children || []
obj[node.pid].children.push(node)
})
return result
}
3、什麼是跨域?什麼是瀏覽器同源策略?有哪些常用的解決跨域方案?手動封裝一個JSONP的跨域請求函數。
- 因爲瀏覽器出於安全考慮,有同源策略。也就是說,如果協議、域名或者端口有一個不同就是跨域,Ajax 請求會失敗。
- 常用的跨域解決方案有:JSONP、CORS、代理。
- JSONP跨域請求函數封裝如下:
# 使用JSONP(函數封裝)
function jsonp(url, jsonpCallback, success) {
let script = document.createElement('script')
script.src = url
script.async = true
script.type = 'text/javascript'
window[jsonpCallback] = function (data) {
success && success(data)
}
document.body.appendChild(script)
}
// 測試示例
jsonp('http://xxx', 'callback', function (value) {
console.log(value)
})
# 使用JSONP(不封裝)
let script = document.createElement('script');
script.src = 'http://www.baidu.cn/login?username=JasonShu&callback=callback';
document.body.appendChild(script);
function callback (res) {
console.log(res);
}
4、談一談 bind、call、apply的區別,並封裝實現一個 bind 函數。
- call 和 apply 都是爲了解決改變 this 的指向。作用都是相同的,只是傳參的方式不同。除了第一個參數外,call 可以接收一個參數列表,apply 只接受一個參數數組。
let a = { value: 1 }
function getValue(name, age) {
console.log(name)
console.log(age)
console.log(this.value)
}
getValue.call(a, 'geek', '10')
getValue.apply(a, ['geek', '30'])
- bind 的實現對比其他兩個函數略微地複雜了一點,因爲 bind 需要返回一個函數,需要判斷一些邊界問題,參考代碼如下。
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回一個函數
return function F() {
// 因爲返回了一個函數,我們可以 new F(),所以需要判斷
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
5、請繪製並描述Vuex的工作流程。
6、觀察下方示例代碼中的輸入與輸出關係,封裝 add()
方法。
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2,3); // 6
add(1,2)(3); // 6
add(1,2,3); // 6
function add() {
let args = [].slice.call(arguments);
let fn = function(){
let fn_args = [].slice.call(arguments)
return add.apply(null,args.concat(fn_args))
}
fn.toString = function(){
return args.reduce((a,b)=>a+b)
}
return fn
}
// 測試:
add(1,2)(3)(4,5)(6); // 21
7、羅列 ES6 的新特性。
8、封裝函數,實現千位分隔符。
// 保留三位小數
parseToMoney(1234.56); // return '1,234.56'
parseToMoney(123456789); // return '123,456,789'
parseToMoney(1087654.32123); // return '1,087,654.321'
function parseToMoney(num) {
num = parseFloat(num.toFixed(3));
let [integer, decimal] = String.prototype.split.call(num, '.')
integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,')
return integer + '.' + (decimal ? decimal : '')
}
9、常用的 CSS 佈局屬性(方案)有哪些?
10、封裝方法求任意兩個Number
數組的交集。
舉例:輸入 num1 = [1, 2, 2, 1]
,nums = [2, 2, 3]
,返回 [2, 2]
。
function union (arr1, arr2) {
return arr1.filter(item => arr2.indexOf(item)>-1)
}
// 測試
const a = [1, 2, 2, 1];
const b = [2, 3, 2];
union(a, b) // [2, 2]
本週結束,下週繼續!!!