instanceof操作符的实现
作用
instanceof的作用是查看构造函数是否在实例对象的原型链中。
使用
console.log([] instanceof Array); // true
实现
- 思路:获取实例化对象中的原型
Object.getPrototypeOf()
,判断是否和给定的原型一致。
function instanceofFunction(left, right) {
let proto = Object.getPrototypeOf(left);
let targetPrototype = right.prototype;
while (proto) {
if (proto == targetPrototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
Function.prototype.apply()函数的实现
作用
apply()函数的作用是改变函数中的上下文(this);原函数中的接收的参数使用数组或类数组接收。
使用
let person1 = {
name: "person1",
age: 18,
getName: function() {
return this.name;
}
}
let person2 = {
name: "person2",
age: 19
}
console.log(person1.getName()) // person1
console.log(person1.getName.apply(person2)) // person2
实现
- 思路:先确定上下文,然后给上下文添加属性;执行当前的函数,执行完后删除添加的属性,返回结果。
Object.prototype.apply2 = function(obj, args = []) {
// 判断当前是否执行一个函数
if (typeof this !== "function") {
throw new Error("Type Error")
}
// 上下文确定, 基本类型不能添加属性
obj = obj || window;
if (typeof obj !== 'object' && typeof obj !== 'function') {
obj = window;
}
// 给修改后的上下文添加一个属性,该属性的值为当前的执行函数
const symbol = Symbol('apply2');
obj[symbol] = this;
const res = obj[symbol](...args)
// 复原:删除第二步添加的属性
delete obj[symbol]
// 返回结果
return res;
}
Function.prototype.call()函数的实现
作用
call()函数的作用是改变函数中的上下文(this);原函数中的接收的参数使用多个参数进行接收
使用
let person1 = {
name: "person1",
age: 18,
getName: function() {
return this.name;
}
}
let person2 = {
name: "person2",
age: 19
}
console.log(person1.getName()) // person1
console.log(person1.getName.call(person2)) // person2
实现
- 思路:先确定上下文,然后给上下文添加属性;执行当前的函数,执行完后删除添加的属性,返回结果。
Object.prototype.call2 = function(obj, ...param) {
// 判断当前是否执行一个函数
if (typeof this !== "function") {
throw new Error("not function");
}
// 上下文确定, 基本类型不能添加属性
obj = obj || window;
if (typeof obj !== "object" && typeof obj !== "function") {
obj = window;
}
// 给修改后的上下文添加一个属性,该属性的值为当前的执行函数
const tempProperty = Symbol.for("temp");
obj[tempProperty] = this;
const res = obj[tempProperty](...param);
// 复原:删除第二步添加的属性
delete obj[tempProperty];
// 返回结果
return res;
}
Function.prototype.bind()函数的实现
作用
bind()函数的作用将某个函数绑定到对象上,函数的第一个参数是函数中的上下文(this),后面的参数是函数需要的参数,与call()函数相似。bind()函数并不立即执行。
使用
var name = "window";
function getName() {
return this.name;
}
let person1 = {
name: "person1",
age: 18,
}
let getName2 = getName.bind(person1);
console.log(getName()) // window
console.log(getName2()) // person1
实现
- 思路:使用apply/call进行实现。需要注意的是,bind函数不是立即执行,需要返回一个函数。
Object.prototype.bind2 = function(context, ...param) {
// 判断当前是否执行一个函数
if (typeof this !== "function") {
throw new Error("not a function")
}
let self = this;
// bind返回一个函数
return function() {
// 使用apply进行函数实现
return self.apply(context, param);
}
}
深拷贝和浅拷贝
- 深拷贝:表示拷贝之后,两个对象没有关系。
- 浅拷贝:表示拷贝之后,对象中基本类型的属性之间是没有关系的,对象中引用类型的属性之间是相互关联的。
深拷贝
- 思路:判断是基本类型、对象和函数等,进行递归创建。
function deepCopy(origin) {
let result = origin instanceof Array ? [] : {};
for ( let key in origin ) {
if (typeof origin[key] == "object") {
result[key] = deepCopy(origin[key]);
} else {
result[key] = origin[key];
}
}
return result;
}
浅拷贝
for... in ...
function simpleCopy(origin) {
let result = {};
for (let key in origin) {
result[key] = origin[key]
}
return result;
}
Object.assign()
function simpleCopy(origin) {
return Object.assign({}, origin);
}
展开语法
function simpleCopy(origin) {
return {...origin}
}
性能优化
防抖、节流都需要闭包进行防重复设置。【不要开启多个setTimeout】
防抖、节流主要使用到的是闭包的特性:能够保持外部作用域的变量,并且能够内部函数可以使用外部函数的变量。
防抖
function fangdou() {
let timeId = null;
let fn = arguments[0];
let time = arguments[1];
return function() {
let context = this;
let arg = arguments;
clearTimeout(timeId);
timeId = setTimeout(function() {
// 传递参数
fn.call(context, ...arg)
}, time)
}
}
节流
n秒内只有执行一次。注意触发条件
function jieliu() {
let timeId = null;
let fn = arguments[0];
let time = arguments[1];
return function() {
let context = this;S
let arg = arguments;
if (!timeId) {
timeId = setTimeout(function() {
timeId = null;
fn.apply(context, arg)
}, time)
}
}
}
封装一个网络请求
function Ajax(url, method, asyncValue = true) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(method, url, asyncValue);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
resolve(xhr.responseText)
} else {
reject()
}
}
}
xhr.send()
})
}
数组
forEach方法
- 参数:
forEach方法有两个参数,第一个是回调函数;第二个是上下文。其中回调函数中的参数依次是:数组中的值,数组的下标、整个数组 - 返回值:
undefined
使用
let array = [1,2,3,4,5];
array.forEach(function(item, index, arr) {
console.log(item);
})
实现
Array.prototype.forEach1 = function() {
// 表示当前的array
let array = this;
// 获取回调函数
let fn = arguments[0];
let context = arguments[1] || window;
// 遍历数组
for(let i=0; i<array.length; i++) {
fn.call(context, array[i], i, array);
}
}
map方法
参数:
map方法有两个参数,第一个是回调函数;第二个是上下文。其中回调函数中的参数依次是:数组中的值,数组的下标、整个数组返回值:
回调函数中返回值组成的数组列表。
使用
let array = [1,2,3,4,5];
let result = array.map(function(item, index, array) {
console.log(item)
return item;
})
console.log(result) // [1, 2, 3, 4, 5]
实现
Array.prototype.map1 = function() {
// 表示当前的array
let array = this;
// 获取回调函数
let fn = arguments[0];
let context = arguments[1];
// map的返回值
let result = []
// 遍历数组
for (let i = 0; i < array.length; i++) {
result.push(fn.call(context, array[i], i, array));
}
return result;
}
every方法
参数:
every方法有两个参数,第一个是回调函数;第二个是上下文。其中回调函数中的参数依次是:数组中的值,数组的下标、整个数组。返回值:
回调函数中返回值全为true,返回true;出现一个false就返回false。
使用
let array = [1,2,3,4,5];
let result = array.every(function(item, index, array) {
console.log(item)
return true;
})
console.log(result) // 1,2,3,4,5 true
实现
Array.prototype.every1 = function() {
// 表示当前的array
let array = this;
// 获取回调函数
let fn = arguments[0];
let context = arguments[1];
// 遍历数组,如果有false出现,则退出
for (let i = 0; i < array.length; i++) {
if (!fn.call(context, array[i], i, array)){
return false;
}
}
return true;
}
some方法
参数:
some方法有两个参数,第一个是回调函数;第二个是上下文。其中回调函数中的参数依次是:数组中的值,数组的下标、整个数组。返回值:
回调函数中返回值全为false,返回false;出现一个true就返回true。
使用
let array = [1,2,3,4,5];
let result = array.some(function(item, index, array) {
console.log(item)
return true;
})
console.log(result) // 1 true
实现
Array.prototype.some1 = function() {
// 表示当前的array
let array = this;
// 获取回调函数
let fn = arguments[0];
let context = arguments[1];
// 遍历数组,如果有false出现,则退出
for (let i = 0; i < array.length; i++) {
if (fn.call(context, array[i], i, array)) {
return true;
}
}
return false;
}
filter方法
参数:
filter方法有两个参数,第一个是回调函数;第二个是上下文。其中回调函数中的参数依次是:数组中的值,数组的下标、整个数组。返回值:
回调函数中返回值true,返回值的数组中有此值;返回false,返回值的数组中没有此值;。
filter是浅拷贝。
使用
let array = [[1,2,3], 2, 3, 4, 5]
let result = array.filter(function(item, index, array) {
console.log(item)
if (index === 0) {
return true;
}
return false;
})
result[0][0] = 0;
console.log(result) // [[0,2,3]]
console.log(array)// [[0,2,3], 2, 3, 4, 5]
实现
Array.prototype.filter1 = function() {
// 表示当前的array
let array = this;
// 获取回调函数
let fn = arguments[0];
let context = arguments[1];
// 返回值的数组
let result = []
// 遍历数组,如果有false出现,则退出
for (let i = 0; i < array.length; i++) {
if (fn.call(context, array[i], i, array)) {
result.push(array[i]);
}
}
return result;
}
reduce方法
参数:
filter方法有两个参数,第一个是回调函数;第二个是初始值。其中回调函数中的参数依次是:前一个返回的值,当前值、当前下标、整个数组。返回值:
回调函数中返回值true,返回值的数组中有此值;返回false,返回值的数组中没有此值;。
reduce没有指定的上下文这个参数
使用
let array = [1, 2, 3, 4, 5]
let result = array.reduce(function(pre, cur, index, array) {
console.log(cur)
return pre + cur;
}, 0)
console.log(result) // 15
实现
Array.prototype.reduce1 = function() {
// 表示当前的array
let array = this;
// 获取回调函数
let fn = arguments[0];
let init = arguments[1];
// 判断是否有初始值
let start = 0;
if (init == undefined) {
init = array[start++];
}
while (start < array.length) {
init = fn(init, array[start], start++, array);
}
return init;
}
Promise的实现
Promise.all的实现
作用:多个异步调用函数,并且多个异步调用函数的参数和结果都无必然联系。多个异步函数的执行只关注成功或失败结果。
每一个都返回成功,才返回成功;否则,将第一个失败作为整个失败的结果。
参数:
- 数组,可以是基本类型,也可以是Promise对象
返回值 - Promise对象或Promise对象数组
实现
Promise.all = function(params) {
return new Promise((resolve, reject) => {
// 先判断参数是否是数组
if (Array.isArray(params)) {
return reject("params must be an array");
}
let length = params.length;
let count = 0; // 记录当前接收到的个数
let result = new Array(length); // 与参数的位置一一对应
// 进行一个一个执行,
for (let i=0; i<length; i++) {
// 使用Promise.resolve防止不是一个Promise对象
Promise.resolve(params[i]).then((value) => {
// 与参数的位置一一对应
result[i] = value;
count++;
if (count === length) {
return resolve(result);
}
}, reason => {
return reject(reason);
})
}
})
}
Event Bus的实现
Event Bus是消息传递的一种方式,基于一个消息中心,订阅和发布消息的格式,成为发布订阅者模式。
使用
- $on("name", fn):订阅消息,name表示订阅的消息名称, fn表示订阅的消息
- $emit("name", args):发布消息,name表示发布的消息名称,args表示发布的消息
实现
class EventBus {
constructor() {
this.callback = {};
}
$on(name, fn) {
if (!this.callback.hasOwnProperty(name)) {
this.callback[name] = [];
}
this.callback[name].push(fn);
}
$emit(name, args) {
if (this.callback.hasOwnProperty(name)) {
this.callback.forEach(function(item, index) {
item(args)
})
}
}
}
解析XML文档
function parseXML(str) {
let regXML = /^</; // 判断是否xml格式
let reg = /<([\w|\W]+)>([\w|\W]*)<\/\1>/g; // 解析xml格式
let obj = {}; // 如果是xml格式,返回object
str = str.trim(); // 删除两边的空白符
// xml文档的解析
if (regXML.test(str)) {
let result;
while (result = reg.exec(str)) {
obj[result[1]] = parseXML(result[2]);
}
return obj;
} else {
return str;
}
}