文章目录
1. Array.isArray()
Array.myIsArray = function(arr){
return Object.prototype.toString.call(arr) === '[object Array]';
}
let arr = new Array(1,3,45,6,7);
var mycars=new Array("Saab","Volvo","BMW")
console.log(Array.myIsArray(arr)); //true
console.log(Array.myIsArray(mycars)); //true
console.log(Array.isArray(arr));//true
console.log(Array.isArray(mycars));//true
2. New
new方法效果:
function People(name,age) {
this.name = name
this.age = age
}
let peo = new People('Bob',22)
console.log(peo.name) // Bob
console.log(peo.age) // 22
实现思路:
- 直接通过原型创建新对象 ;
- 将this(也就是上一句中的新对象)和调用参数传给构造器,执行;
- 如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return的对象
function createNew(Parent, ...arr) {
// 1.以构造器的prototype属性为原型,创建新对象;
let obj = Object.create(Parent.prototype);
// 2.将this和调用参数传给构造器执行
let result = Parent.apply(obj, arr) //
// 3.如果构造器没有手动返回对象,则返回第一步的对象
return typeof result === 'object' ? result : obj
}
实现效果:
function People(name,age) {
this.name = name
this.age = age
}
let peo = createNew(People,'Bob',22)
console.log(peo.name) // Bob
console.log(peo.age) // 22
const
consst constangize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach((key, i) => {
if (typeof(obj[key]) === 'object') {
constantize(obj[key]);
}
});
};
3. call方法
call方法效果
// call实现
function add(c, d) {
return this.a + this.b + c + d;
}
const obj = {
a: 1,
b: 2
};
let num = add.call(obj, 3, 4)
console.log(num); // 10
方法实现:
/* 思路:将要改变this指向的方法挂到目标this上执行并返回*/
Function.prototype.myCall = function (context) {
if (typeof this !== 'function') {
throw new TypeError('not funciton');
}
let content = context || window;
content.fn = this; // 1. 将函数设为对象的属性
let args = [...arguments].slice(1); // 2. 执行属性函数
var result = content.fn(...args);
delete content.fn; // 3. 删除属性
return result;
}
let numCall = add.myCall(obj, 3, 4);
console.log(numCall); // 10
4. apply
apply方法效果
function f(x) {
console.log(x, this.y)
}
//your code here
f.bind({y: 'foo'})(); //undefined "foo"
f.bind()(); //undefined undefined
f.bind({y: 'bar'}, 'foo')(); //"foo" "bar"
方法实现:
// apply实现
// 思路:将要改变this指向的方法挂到目标this上执行并返回
Function.prototype.myApply = function (context) {
if (typeof this !== 'function') {
throw new TypeError('not funciton');
}
context = context || window;
context.fn = this; // 1. 将函数设为对象的属性
let result
// 2. 执行属性
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
delete context.fn; // 3. 删除属性
return result;
}
let numApply = add.myApply(obj, [3, 4]);
console.log(numApply); // 10
5. bind
bind方法效果
function Person(){
this.name = "zx";
this.age = "19";
this.gender = "male";
}
let obj={
hobby: "看书"
}
// 构造函数的this绑定为obj
let changeObj = Person.bind(obj,1,3)
// 直接调用构造函数操作,会给obj增加三个数属性
changeObj();
console.log(obj); // {hobby: "看书"; name = "zx"; age = "19"; gender = "male";}
// 对changeObj进行new操作
let newChangeObj = new changeObj()
// new后的构造后的newChangeObj的原型链指向Person {},之前的bind操作无效了
console.log(newChangeObj); // Person { name = "zx"; age = "19"; gender = "male";}
console.log(newChangeObj.__proto__); // Person {}
从上述代码,可以得出结论,bind获得改变this指向后的函数,在new之后,bind失效。
实现
Function.prototype.mybind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
// 保存函数
let _this = this;
// 目标对象在外的参数,赋值给数组args
let args = [...arguments].slice(1);
// 返回一个待执行的函数
return function fBound() {
/* 处理函数使用new的情况
instanceof用来检测某个实例对象的原型链上是否存在这个构造函数的prototype属性,
this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用,
此时this=fBound(){},否则this=window, 如果是的话使用新创建的this代替硬绑定的this
*/
if (this instanceof fBound) {
// 用new调用原函数,并用扩展运算符传递参数
return new _this(...args, ...arguments);
} else {
// 用apply调保存函数_this并传说第合并的参数数组
return _this.apply(context, args.concat(...arguments));
}
}
}
f.mybind({y: 'foo'})(); //undefined "foo"
f.mybind()(); //undefined undefined
f.mybind({y: 'bar'}, 'foo','bbbb')(); //"foo" "bar"
var ab = A.mybind("",1)
var ba = new ab(2) // {a: 1, b: 2}
console.log(ab);
console.log(ba); //A { a:1, b:2}
https://segmentfault.com/a/1190000021758529
https://www.cnblogs.com/chenwenhao/p/11294541.html#_label4
https://www.cnblogs.com/lxy-starry/p/11302746.html
6. 浅拷贝、深拷贝的实现
浅拷贝:
复制// 1. ...实现
let copy1 = {...{x:1}}
// 2. Object.assign实现
let copy2 = Object.assign({}, {x:1})
深拷贝:
复制// 1. JOSN.stringify()/JSON.parse()
// 缺点:拷贝对象包含 正则表达式,函数,或者undefined等值会失败
let obj = {a: 1, b: {x: 3}}
JSON.parse(JSON.stringify(obj))
// 2. 递归拷贝
// 深拷贝 类型判断+递归拷贝
function deepClone(obj, hash = new WeakMap()) {
// null或undefined
if (obj == null) return obj;
// number string boolean symbol
if (typeof obj !== 'object') return obj;
// object
// 日期
if (obj instanceof Date) return new Date(obj);
// 正则
if (obj instanceof RegExp) return new RegExp(obj);
if (hash.get(obj)) {
return hash.get(obj);
}
// 数组 / {}
let newObj = new obj.constructor;
hash.set(obj, newObj);
for (let key in obj) {
// obj无论是数组还是对象 都可以进行for in迭代
newObj[key] = deepClone(obj[key], hash);
}
return newObj;
}
7. 一个节流函数&防抖函数
节流函数:
// 思路:在规定时间内只触发一次
function throttle (fn, delay) {
// 利用闭包保存时间
let prev = Date.now()
return function () {
let context = this
let arg = arguments
let now = Date.now()
if (now - prev >= delay) {
fn.apply(context, arg)
prev = Date.now()
}
}
}
function fn () {
console.log('节流')
}
addEventListener('scroll', fn); // 事件持续发生时持续打印'节流'
addEventListener('scroll', throttle(fn, 1000); // 事件持续发生时,间隔1s打印一次'节流'
防抖函数:
// 思路:在规定时间内未触发第二次,则执行
function debounce (fn, delay) {
// 利用闭包保存定时器
let timer = null
return function () {
let context = this
let arg = arguments
// 在规定时间内再次触发会先清除定时器后再重设定时器
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(context, arg)
}, delay)
}
}
function fn () {
console.log('防抖')
}
addEventListener('scroll', debounce(fn, 1000))
8. instanceof 的原理
instanceof 用于判断一个引用类型是否属于某构造函数;还可以在继承关系中用来判断一个实例是否属于它的父类型。
instanceof 的原理是判断实例对象的 __proto__
是否与构造函数的prototype
指向同一个引用。
// 思路:右边变量的原型存在于左边变量的原型链上
function myinstanceOf(obj, type) {
let objValue = obj.__proto__
let typeValue = type.prototype
while (true) {
if (objValue === null) {
return false
}
if (objValue === typeValue) {
return true
}
objValue = objValue.__proto__
}
}
let n = 1;
console.log(myinstanceOf(n, Number));
9.柯里化函数的实现
todo
柯里化函数的主要作用还是延迟执行。
const curry = ( fn, arr = []) => (...args) => ( (a,b) => b.length === 0? fn(...a) : curry(fn, a))([...arr, ...args],[...args])
let curryPlus = curry((...x)=>x.reduce((a,b)=>a+b))
curryPlus(1) //返回一个函数
curryPlus(1)(2) //返回一个函数
//遇到参数个数为0的情况才执行
curryPlus(1)(2)(4)() //返回7
curryPlus(1,2)(4)() //返回7
10. Object.create 的基本实现原理
Object.create()
Object.myCreate = function (proto, propertyObject = undefined) {
if (propertyObject === null) {
// 这里没有判断propertyObject是否是原始包装对象
throw 'TypeError'
} else {
function Fn() {};
Fn.prototype = proto;
const obj = new Fn();
if (propertyObject !== undefined) {
Object.defineProperties(obj, propertyObject)
}
if (proto === null) {
// 创建一个没有原型对象的对象, Object.create(null)
obj.__proto__ = null
}
return obj
}
}
// 示例
// 第二个参数null时, 抛出TypeError
// const throwErr = Object.mycreate({a:'aa'}, null) //Uncaught Typetrror
// 构建
const obj1 = Object.myCreate({n
a: 'aa'
});
console.log(obj1) // {},obj1的构造函数的原型对象是{a: 'aa'}
const obj2 = Object.myCreate({a: 'aa'}, {
b: {
value: 'bb',
enumerable: true
}
});
console.log(obj2) //{b:'bb'}, obj2的构造函数的原型使{a: 'aa'}
11 待补充
实现一个基本的 Event Bus
实现一个双向数据绑定
实现一个简单路由
实现懒加载
rem 基本设置
手写实现 AJAX
Array.prototype.reduce()
实现async/awit
Array.prototype.flat()
事件代理
Vue的双向绑定
Array.prototype.map()
12. promise
const resolvePromise = (promise2, x, resolve, reject) => {
// x和promise2不能是同一个人,如果是同一个人就报错
// 加一个开关,防止多次调用失败和成功,跟pending状态值一样的逻辑一样,走了失败就不能走成功了,走了成功一定不能在走失败
if (promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<promise>')
)
}
// 判断如果x是否是一个对象,判断函数是否是对象的方法有:typeof instanceof constructor toString
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
let called
try { // 预防取.then的时候错误
let then = x.then // Object.definePropertype
if (typeof then === 'function') {
// 用then.call()为了避免在使用一次x.then报错
then.call(x, y => {
// resolve(y)// 采用promise的成功结果,并且向下传递
if (called) {
return
}
called = true
// y有可能是一个promise,那么我们就要继续使用回调函数,直到解析出来的值是一个普通值
resolvePromise(promise2, y, resolve, reject)
}, r => {
if (called) {
return
}
called = true
reject(r) // 采用promise的失败结果,并且向下传递
})
} else {
if (called) {
return
}
called = true
resolve(x) // x不是一个函数,是一个对象
}
} catch (err) {
if (called) {
return
}
called = true
reject(err)
}
} else {
// x是一个普通值
resolve(x)
}
}
class Mypromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.state == 'pending') {
this.state = 'fullFilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn())
}
}
let reject = (reason) => {
if (this.state == 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject);
} catch (err) {
reject(err)
}
}
then(onFullFilled, onRejected) {
let promise2 = new Mypromise((resolve, reject) => {
let x;
console.log('this', this)
// 同步
if (this.state == 'fullFilled') {
setTimeout(() => {
try {
x = onFullFilled(this.value)
// 添加一个resolvePromise()的方法来判断x跟promise2的状态,决定promise2是走成功还是失败
resolvePromise(promise2, x, resolve, reject)
} catch (err) { // 中间任何一个环节报错都要走reject()
reject(err)
}
}, 0)
}
if (this.state == 'rejected') {
setTimeout(() => {
try {
x = onRejected(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) { // 中间任何一个环节报错都要走reject()
reject(err)
}
}, 0)
}
// 异步
if (this.state == 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
x = onFullFilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) { // 中间任何一个环节报错都要走reject()
reject(err)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
x = onRejected(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) { // 中间任何一个环节报错都要走reject()
reject(err)
}
}, 0)
})
}
});
return promise2
}
}
// const p = new Mypromise((resolve, reject) => {
// // resolve('success') // 走了成功就不会走失败了
// throw new Error('失败') // 失败了就走resolve
// reject('failed') // 走了失败就不会走成功
// })
// p.then((res) => {
// console.log(res)
// }, (err) => {
// console.log(err)
// })
const p = new Mypromise((resolve, reject) => {
resolve(100)
})
p.then((data) => {
console.log('sucess')
return 520 * data
}, (err) => {
console.log(err)
}).then((data) => {
return new Promise((resolve, reject) => {
console.log(data)
resolve(data)
})
}).then((data) => {
console.log('result', data) // 52000
})
// function promiseTest() {
// let promise = new Mypromise((resolve, reject) => {
// let r = parseInt(Math.random() * 10)
// if (r % 2 == 0) {
// resolve('成功')
// } else {
// reject('失败')
// }
// })
// return promise
// }
// const promise = promiseTest()
// promise.then((data) => {
// console.log(data)
// }).catch((err) => {
// console.log(err)
// })