function creatNew () { // 实现 new 方法
let obj = {} // 1.创建一个空对象
let constructor = [].shift.call(arguments)
obj._proto_ = constructor.prototype // 2.链接到原型
let result = constructor.apply(obj, arguments) // 3.绑定this值
return typeof result === 'object' ? result : obj // 4.返回新对象
}
class promise { // 实现一个promise函数
constructor (fn) {
this.state = 'pending'
this.value = undefined
this.reson = undefined
var resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
}
}
var reject = value => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reson = value
}
}
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
then (onFulfilled, onRejected) {
switch (this.state) {
case 'fulfilled':
onFulfilled(this.value)
break
case 'rejected':
onRejected(this.value)
break
default:
}
}
},
Function.prototype.mycall = function (context) { // 实现一个call函数 本质上是要将this方法挂到目标this上并执行返回
if (typeof this !== 'function') {
throw new TypeError('not function')
}
context = context || window
context.fn = this
var arg = [...arguments].slice(1)
var reslut = context.fn(...arg)
delete context.fn
return reslut
}
Function.prototype.myapply = function (context) { // 实现一个apply函数 类似call,但返回的是函数
if (typeof this !== 'function') {
throw new TypeError('not function')
}
context = context || window
context.fn = this // #endregion
let result
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
Function.prototype.mybind = function (context) { // 实现一个bind函数 类似于call 但是返回的是一个函数
if (typeof this !== 'function') {
throw new TypeError('erro')
}
const _this = this
const arg = [...arguments].slice(1)
return function f () {
if (this instanceof f) {
return new _this(...arg, ...arguments)
} else {
return _this.apply(context, arg.concat(...arguments))
}
}
}
let copy1 = { ...{ x: 1 } } // 浅拷贝
let copy2 = Object.assign({}, { x: 1 }) // 浅拷贝
const obj = { a: 1, b: { x: 3 } } // 深拷贝
JSON.parse(JSON.stringify(obj)) // 缺点:拷贝对象包含 正则表达式,函数,或者undefined等值会失败
function deepClone (obj) { // 递归拷贝
let copy = obj instanceof Arry ? [] : {}
for (const i in obj) {
if (object.hasOwnProlet(i)) {
copy[i] = typeof obj[i] === 'object' ? deepCloen(obj(i)) : obj[i]
}
}
return copy
}
function throtte (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(111)
}
addEventListener('scroll', throtte(fn,1000))
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))
function instanceOf () { // instanceof的原理 右边变量的原型存在于左边变量的原型链上
let leftvalue = left._proto_
let rightvalue = right.prototype
while(true) {
if(leftvalue === null) {
return false
}
if(leftvalue ===rightvalue) {
return true
}
leftvalue = leftvalue._proto_
}
}
function creat(obj) { // Object.create 的基本实现原理 将传入的对象作为原型
function F() {}
F.prototype = obj
return new F()
}
class EventEmitter { // 实现一个基本的 Event Bus 组件通信,一个触发与监听的过程
constructor () { // 储存事件
this.events = this.events || new Map()
}
addEventListener (type, fn) { // 监听事件
if(!this.events.get(type)){
this.events.set(type,fn)
}
}
emit (type) { // 触发事件
let handle = this.events.get(type)
handle.apply(this, [...arguments].slice(1))
}
}
let obj = {} // 实现一个双向数据绑定
let input = document.getElementById('input')
let span = document.getElementById('span')
Object.defineProperty(obj,'text',{
enumerable : true,
configurable : true,
get() {
console.log('获取数据')
},
set() {
console.log('数据更新')
input.value = newVal
span.value = newVal
}
})
input.addEventListener('keyup',function(e) {
obj.text = e.target.value
})
class Router { // 实现一个简单路由
constructor() {
this.routes = {} // 路由储存对象
this.currentHash = '' // 当前的hash
this.freshRoute = this.freshRoute.bind(this) // 绑定this 防止后期this被修改指向
window.addEventListener('load',this.freshRoute,false) // 增加监听
window.addEventListener('hashchange',this.freshRoute,false) // 增加监听
}
storeRoute(path,cb) { // 对当前路由进行储存
this.routes[path] = cb || function() {}
}
freshRoute() { // 路由更新
this.currentHash = location.hash.slice(1) || '/'
this.routes[this.currentHash]()
}
}
// 手写实现 AJAX
// 1. 简单模式
let xhr = new XMLHttpRequest() // 实例化小黄人
xhr.open(method,url,async) // 初始化通讯连接
xhr.send(data) // 发送请求
xhr.onreadystatechange = () =>{ // 设置状态回调处理请求结果
if(xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
// 2. 基于promise实现
function ajax(options) {
const url = options.url // 请求地址
const method = options.method.toLocaleLowerCase() || 'get' //请求方式
const async = options.async // 默认设置为异步
const data = options.data // 设置请求参数
const xhr = new XMLHttpRequest() // 实例小黄人
if(options.timeout && options.timeout >0) { // 请求超时
xhr.timeout = options.timeout
}
// 返回一个Promise实例
return new Promise((resolve,reject) =>{
xhr.ontimeout = ()=>reject&&reject('请求超时')
xhr.onreadystatechange = () => { // 监听回调函数
if(xhr.readyState ===4) {
if(xhr.status >=200 && xhr.status<300 || xhr.status===304) { // 200-300 之间表示请求成功,304资源未变,取缓存
resolve && resolve(xhr.responseText)
} else {
reject && reject()
}
}
}
xhr.onerror = err => reject && reject(err) // 错误回调
let paramArr = []
let encodeData
if(data instanceof Object) { // 处理请求参数
for (let key in data) { // 参数拼接需要通过 encodeURIComponent 进行编码
paramArr.push(encodeURIComponent(key) + '=' +encodeURIComponent(data[key]))
}
encodeData = paramArr.join('&')
}
if(method ==='get') { // get请求拼接参数
const index = url.indexOf('?') // 检测url中是否已存在 ? 及其位置
if (index ===1) url+='?'
else if(index!=url.length-1) url+='&'
url += encodeData // 拼接url
}
xhr.open(method,url,async) // 初始化
if(method === 'get') xhr.send(null)
else {
xhr.getResponseHeader('Content-Type','application/x-www-form-urlencoded;charset=UTF-8') // post 方式需要设置请求头
xhr.send(encodeData)
}
})
}