懒加载 & 预加载
lilywei739.github.io/2017/02/06/… www.geekjc.com/post/58d94d…
防抖和节流
juejin.cn/post/684490… juejin.cn/post/684490…
深拷贝
数组去重、数组乱序
继承(ES5/ES6)
实现promise
实现promise.all
实现promise.retry
将一个同步callback包装成promise形式
写一个函数,可以控制最大并发数
jsonp的实现
eventEmitter(emit,on,off,once)
实现new
实现数组flat、filter等方法
lazyMan
函数currying
如何在ES5环境下实现const
实现instanceof
instanceof
encodeURIComponent & decodeURIComponent 用法
xhr & ajax
怎么用原生JS写一个GET请求呢?如下代码,只需3行:
let xhr = new XMLHttpRequest();
xhr.open("GET", "/list");
xhr.send();
怎么用原生JS写一个POST请求呢?如下图所示:
排序算法
instanceof
instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。
function instanceof(left, right) {
// 获得类型的原型
let prototype = right.prototype
// 获得对象的原型
left = left.__proto__
// 判断对象的类型是否等于类型的原型
while (true) {
if (left === null)
return false
if (prototype === left)
return true
left = left.__proto__
}
}
手写call、apply、bind
call
Function.prototype.myCall = function(context, ...args) {
context = context || window
let fn = Symbol()
context[fn] = this
let result = context[fn](...args)
delete context[fn]
return result
}
apply
Function.prototype.myApply = function(context) {
context = context || window
let fn = Symbol()
context[fn] = this
let result
if (arguments[1]) {
result = context[fn](...arguments[1])
} else {
result = context[fn]()
}
delete context[fn]
return result
}
bind
Function.prototype.myBind = function (context) {
var _this = this
var 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))
}
}
实现Storage类,使得该对象为单例,基于localStorage进行封装。实现方法 setItem(key,value) 和 getItem(key)?
静态方法版:
class Storage {
static create() {
if (!Storage.instance) {
Storage.instance = new Storage();
}
return Storage.instance;
}
setItem(key, value) {
return localStorage.setItem(key, value);
}
getItem(key, value) {
return localStorage.getItem(key, value);
}
}
闭包版:
function Storage() { }
Storage.prototype.setItem = function (key, value) {
return localStorage.setItem(key, value);
}
Storage.prototype.getItem = function (key) {
return localStorage.getItem(key, value);
}
const createStorage = (function () {
let instance;
return function () {
if (!instance) {
instance = new Storage();
}
return instance
}
})()
如何判断一个变量是否是数组?
- arr instanceof Array
- Array.prototype.isPrototypeOf(arr)
- Array.isArray(arr)
- Object.prototype.toString.call(arr) === '[object Array]'
- arr.constructor === Array
类数组转为数组的方式有哪些?
- [].slice.call(arguments)
- Array.from(arguments)
- [...arguments]
Symbol.iterator
//obj就是可遍历的,因为它遵循了Iterator标准,且包含[Symbol.iterator]方法,方法函数也符合标准的Iterator接口规范。
//obj.[Symbol.iterator]() 就是Iterator遍历器
let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
如何在 JS 中“深冻结”对象?
如果咱们想要确保对象被深冻结,就必须创建一个递归函数来冻结对象类型的每个属性:
浅冻结
let person = {
name: "Leonardo",
profession: {
name: "developer"
}
};
Object.freeze(person);
person.profession.name = "doctor";
console.log(person); //output { name: 'Leonardo', profession: { name: 'doctor' } }
深冻结
function deepFreeze(object) {
let propNames = Object.getOwnPropertyNames(object);
for (let name of propNames) {
let value = object[name];
object[name] = value && typeof value === "object" ?
deepFreeze(value) : value;
}
return Object.freeze(object);
}
let person = {
name: "Leonardo",
profession: {
name: "developer"
}
};
deepFreeze(person);
person.profession.name = "doctor"; // TypeError: Cannot assign to read only property 'name' of object
手写ajax
- (1)创建XMLHttpRequest对象,也就是创建一个异步调用对象
- (2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
- (3)设置响应HTTP请求状态变化的函数
- (4)发送HTTP请求
- (5)获取异步调用返回的数据
- (6)使用JavaScript和DOM实现局部刷新
sleep函数
如何判断一个对象是不是空对象?
Object.keys(obj).length === 0
浅克隆 & 深克隆 浅拷贝 & 深拷贝
浅克隆:
function shallowClone(obj) {
let cloneObj = {};
for (let i in obj) {
cloneObj[i] = obj[i];
}
return cloneObj;
}
深克隆
- 考虑基础类型
- 引用类型
- RegExp、Date、函数 不是 JSON 安全的
- 会丢失 constructor,所有的构造函数都指向 Object
- 破解循环引用
function deepCopy(obj) {
if (typeof obj === 'object') { // null -> object?
var result = obj.constructor === Array ? [] : {};
for (var i in obj) {
result[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i];
}
} else {
var result = obj;
}
return result;
}
能不能实现图片懒加载?
写个简单Loader
loader 就是一个 node 模块,它输出了一个函数。当某种资源需要用这个 loader 转换时,这个函数会被调用。并且,这个函数可以通过提供给它的 this 上下文访问 Loader API 。 reverse-txt-loader
// 定义
module.exports = function(src) {
//src是原文件内容(abcde),下面对内容进行处理,这里是反转
var result = src.split('').reverse().join('');
//返回JavaScript源码,必须是String或者Buffer
return `module.exports = '${result}'`;
}
//使用
{
test: /\.txt$/,
use: [{
'./path/reverse-txt-loader'
}]
},
使用ES5实现一个继承?
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
只调用了一次超类构造函数,效率更高。避免在SuberType.prototype上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。
因此寄生组合继承是引用类型最理性的继承范式。
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.getName = function () {
return this.name;
}
function SuberType(name, age) {
SuperType.call(this, name);
this.age = age;
}
//寄生组合式继承
SuberType.prototype = Object.create(SuperType.prototype);
SuberType.prototype.constructor = SuberType;
SuberType.prototype.getAge = function () {
return this.age;
}
let girl = new SuberType('Yvette', 18);
girl.getName();
如何实现 Promise.all ?
要实现 Promise.all,首先我们需要知道 Promise.all 的功能:
- 如果传入的参数是一个空的可迭代对象,那么此promise对象回调完成(resolve),只有此情况,是同步执行的,其它都是异步返回的。
- 如果传入的参数不包含任何 promise,则返回一个异步完成.
- promises 中所有的promise都“完成”时或参数中不包含 promise 时回调完成。
- 如果参数中有一个promise失败,那么Promise.all返回的promise对象失败
- 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let index = 0;
let result = [];
if (promises.length === 0) {
resolve(result);
} else {
function processValue(i, data) {
result[i] = data;
if (++index === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
//promises[i] 可能是普通值
Promise.resolve(promises[i]).then((data) => {
processValue(i, data);
}, (err) => {
reject(err);
return;
});
}
}
});
}
如何实现 Promise.prototype.finally ?
不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then。并且会将值原封不动的传递给后面的then.
Promise.prototype.finally = function (callback) {
return this.then((value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
}, (err) => {
return Promise.resolve(callback()).then(() => {
throw err;
});
});
}