目录
一、解析URL
二、功能函数实现
1、防抖和节流
(1)防抖
(2)节流
2、函数柯里化
(1)
(2)
3、setTimeout实现setInterval
三、字符串
1、清除字符串前后空格
(1) .replace()
(2) 循环
2、驼峰命名
四、数组
1、 数组拍平
(1)、递归法
(2)、toString & split
(3)、join & split
2、数组去重
3、根据属性,对象数组去重
4、数组乱序
五、浅拷贝、深拷贝
1、浅拷贝
2、深拷贝
六、bind,apply,call
1、bind函数
2、apply函数
3、call函数
七、实现原生API
1、实现new
2、实现create()
3、instanceof实现
4、实现reduce()
5、实现forEach
6、用reduce实现map
7、实现indexOf
8、实现Object.assign()
八、图片懒加载
九、实现一个简单路由
1、hash路由
2、history路由
十、 发布订阅模式(event bus)
十一、HTTP请求
1、jsonp
2、实现AJAX
(1)简易版
(2)promise实现版
十二、Promise系列
1、promise
2、promise.all
3、promise.race
4、promise经典题
十三、链表
1、单链表
2、双向链表
十四、数据双向绑定
(1)vue2.0
(2)proxy双向数据绑定
十五、判断两个对象是否相等
十六、判断一个对象是空对象
十七、实现函数判断类型的函数
十八、数据绑定基本实现
十九、有一个祖先树状 json 对象,当一个人有一个儿子的时候,其 child 为其儿子对象,如果有多个儿子,child 为儿子对象的数组。
二十、js继承
频繁操作时,只执行最后一次
频繁操作时,只有在一定时间内执行一次
//(2)
function myTrim(str) {//记录前后空格的个数,最后对字符串进行截取
let first=0,last=str.length
for (let i in str) {
if (str[i]===' ') {
first++
} else {
break
}
}
for (let i=last;i>first;i--) {
if (str[i]===' ') {
last--
} else {
break
}
}
return str.substr(first,last-first)
}
var s1 = "get-element-by-id"
// 转化为 getElementById
var f = function(s) {
return s.replace(/-\w/g, function(x) {
return x.slice(1).toUpperCase();
})
}
function flatten(res) {
// join 把数组中的所有元素转换为一个字符串
// split 会将 string 中按照括号里的内容进行分割并存入一个新数组,返回数组
// map 会对数组中的所有数据按照函数进行处理后返回一个处理后的数组
return res.join().split(',').map((item) => {
return parseInt(item)
})
}
const responseList = [
{ id: 1, a: 1 },
{ id: 2, a: 2 },
{ id: 3, a: 3 },
{ id: 1, a: 4 },
];
const result = responseList.reduce((acc, cur) => {
const ids = acc.map(item => item.id);
return ids.includes(cur.id) ? acc : [...acc, cur];
}, []);
console.log(result); // -> [ { id: 1, a: 1}, {id: 2, a: 2}, {id: 3, a: 3} ]
// 著名的Fisher–Yates shuffle 洗牌算法
function shuffle(arr){
let m = arr.length;
while(m > 1){
let index = parseInt(Math.random() * m--);
[arr[index],arr[m]] = [arr[m],arr[index]]; //解构赋值
}
return arr;
}
// 1. ...实现
let copy1 = {...{x:1}}
// 2. Object.assign实现
let copy2 = Object.assign({}, {x:1})
//get请求
let xhr = new XMLHttpRequest()
xhr.open('GET',url,true)
xhr.onreadystatechange = function(){
if(xhr.readystate === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.resopnseText);
}
}
}
xhr.send(null)
//post请求
let xhr = new XLMHttpRequest()
xhr.open('POST',url,true)
xhr.onreadystatechange = function(){
if(xhr.readystate === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.responseText);
}
}
}
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded;charset=UTF-8')
xhr.send(data)
如上代码可以说明p1.then()的结果是一个与p1不同的promise对象。
换句话说,then()会封装一个全新的promise对象p2。那既然 p2也是一个promise对象,那么,p2的状态(promiseStatus)和值(promiseValue)分别是什么?
规则如下:
如果p1的状态是pending,则p2的状态也是pending。
•如果p1的状态是resolved,then()会去执行f_ok,则p2的状态由f_ok的返回值决定。
•如果f_ok返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_ok函数的return值。•如果f_ok返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。•如果f_ok这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。
如果p1的状态是rejected,then()会去执行f_err,则p2的状态由f_err的返回值决定。
•如果f_err返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_err函数的return值。•如果f_err返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。
•如果f_err这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。
setTimeout(() => {
console.log(0); //9
}, 0);
new Promise((resolve, reject) => {
console.log(1); // 1
resolve()
}).then(() => {
console.log(2); //3
new Promise((resolve, reject) => {
console.log(3); //4
resolve()
}).then(() => {
console.log(4); //6
}).then(() => {
console.log(5); //8
})
}).then(() => {
console.log(6); //7
})
new Promise((resolve, reject) => {
console.log(7); //2
resolve()
}).then(() => {
console.log(8); //5
})
// 1 7 2 3 8 4 6 5 0
// then() 里面放入的是函数就会放进队列中等待执行,下一个then中的内容,得等上一个then中状态转变才会放入队列中
function getType(obj) {
if (obj === null) return String(obj);
return typeof obj === 'object'
? Object.prototype.toString.call(obj).replace('[object ', '').replace(']', '').toLowerCase()
: typeof obj;
}
// 调用
getType(null); // -> null
getType(undefined); // -> undefined
getType({}); // -> object
getType([]); // -> array
getType(123); // -> number
getType(true); // -> boolean
getType('123'); // -> string
getType(/123/); // -> regexp
getType(new Date()); // -> date
题目:
// 实现一个方法,可以给 obj 所有的属性添加动态绑定事件,当属性值发生变化时会触发事件
let obj = {
key_1: 1,
key_2: 2
}
function func(key) {
console.log(key + ' 的值发生改变:' + this[key]);
}
bindData(obj, func);
obj.key_1 = 2; // 此时自动输出 "key_1 的值发生改变:2"
obj.key_2 = 1; // 此时自动输出 "key_2 的值发生改变:1"
答:
function bindData(obj, fn) {
for (let key in obj) {
Object.defineProperty(obj, key, {
set(newVal) {
if (this.value !== newVal) {
this.value = newVal;
fn.call(obj, key);
}
},
get() {
return this.value;
}
})
}
}
请实现一个函数,找出这个家族中所有有多个儿子的人的名字(name),输出一个数组。
// 样例数据
let data = {
name: 'jack',
child: [
{ name: 'jack1' },
{
name: 'jack2',
child: [{
name: 'jack2-1',
child: { name: 'jack2-1-1' }
}, {
name: 'jack2-2'
}]
},
{
name: 'jack3',
child: { name: 'jack3-1' }
}
]
}
答:
function findMultiChildPerson(data) {
let nameList = [];
function tmp(data) {
if (data.hasOwnProperty('child')) {
if (Array.isArray(data.child)) {
nameList.push(data.name);
data.child.forEach(child => tmp(child));
} else {
tmp(data.child);
}
}
}
tmp(data);
return nameList;
}