原生js实现一些常用的操作

create on in javascript with 0 comment and 115 view

实现一个new操作符

function New(func){ let temp = {} let ret // 更正原型链 if(func.__proto__ !== null) { temp.__proto__ = func.prototype } else { new Error('argument is not a constructor!') } // 执行函数 if(typeof func === 'function') { ret = func.apply(temp, Array.prototype.slice.call(arguments, 1)) } else { new Error('{(intermediate value)} is not a constructor') } // 返回值判断 (构造函数返回值的一个对象可作为实例) if((typeof ret === 'function' || typeof ret === 'object') && ret !== null) { return ret } return temp } // function A(val){ // this.val = val // return this // } // let a = New(A, 'a') // let a = new A('a') // console.log(a);

实现一个JSON.stringify

  • json 格式: json
  • undefined、function以及symbol,会被忽略(出现在非数组对象的属性值中时),或者被转换成 null(出现在数组中时)
  • number, boolean, string 为原始值
  • 不可枚举的属性会被忽略
  • 如果一个对象的属性值通过某种间接的方式指回该对象本身,即循环引用,属性也会被忽略
function jsonStringify(obj) { let type = typeof obj if(typeof obj !== 'object') { // string,undefined,function 直接转为字符串 if(/string|undefined|function/.test(type)) { obj = '"' + obj + '"' } return String(obj) } else { // 是否为数组,数组需要使用 [] 括起来, 对象则使用 {} // for in 用于遍历 对象和数组,json转化每一项,若该项为对象或数组,则递归 let json = [] // 用于存储单个 JSON,对象则存储为 key:value, 数组则为 value,value,... let arr = Array.isArray(obj) for(let k in obj) { let v = obj[k] let type = typeof v if(/string|undefined|function/.test(type)) { v = '"' + v + '"' } else if(type === 'object') { v = jsonStringify(v) } json.push( (arr? "": `"${k}":`) + String(v)) } return (arr? "[":"{") + String(json) + (arr? "]":"}") } } // jsonStringify(Object) // "{"x":5}" // var res = jsonStringify([1, "false", false]) // "[1,"false",false]" // jsonStringify({b: undefined}) // "{"b":"undefined"}" // console.log(res);

实现 call, apply

当一个对象调用该对象的某个函数类型的属性时,该函数内的this则指向当前对象。

// 原理 function fun(){ console.log(this.val); } var foo = { val: 1, fun: fun } // foo.fun() // 1 // 优化实现 Function.prototype.call = function(content = window) { // 函数调用call时,call函数内的this指向函数本身 content.fn = this let args = arguments && [...arguments].slice(1) // 对于 apply, 则读取第二个参数即可 arguments[1] let res = content.fn(...args) delete content.fn return res } fun.call(foo)

实现 bind

在 bind 方法存储参数,新建一个新的函数,在闭包内存储参数信息,新函数中执行this(即调用bind的函数),并将该this的this进行调整,最后,将新函数的上级原型链指向 bind 中的 this,返回这个新函数。

Function.prototype.bind = function(content = window){ let ctx = content let args = [...arguments].slice(1) let _this if(typeof this === 'function') { _this = this } else { throw Error("not a function") } let func = function(){ _this.apply(this instanceof func ? this : ctx, [...args, ...arguments]) // 是否需要 this instanceof func? } func.__proto__ = _this return func } var obj = { val: 2 } function func(val){ console.log(val || this.val); } func = func.bind(obj) // var obj2 = { // 测试 this installceof func (原生输出 2, 本实现输出 3) // val: 3 // } // obj2.__proto__ = func.prototype // obj2.fn = func // obj2.fn()

实现一个继承 (寄生组合)

function Parent(){} function Child(){ Parent.call(this) } // 0. 忘了叫什么模式,特地举例出来说明一下,该模式是存在缺陷的。 // Child.prototype = new Parent() // 该操作会造成冗余,即 Parent 类实例化的对象所拥有的属性会附加在 Child.prototype上,但是,这些属性永远不会被访问到,因为 Child 实例上已经存在这些属性。 // Child.prototype.constructor = Child // 1.使用 Object.create // Child.prototype = Object.create(Parent.prototype) // Object.create 会创建一个新对象,除了将新对象的 __proto__指向 parent.prototype 外,还将 constructor 指向 Parent (即Parent.prototype.constructor),最后将新对象赋值给 Child.prototype // Child.prototype.constructor = Child // 原本 Child.prototype.constructor 指向了 Parent, 需矫正。 // 2. 需要运行环境支持 __proto__ 属性 // Child.prototype.__proto__ = Parent.prototype // 3. 创建临时对象 // function create(proto){ // let tmp = new Function() // tmp.prototype = proto // return new tmp() // } // Child.prototype = create(Parent.prototype) // Child.prototype.constructor = Child // 原本Child.prototype的Constructor指向 Function,需矫正 let c = new Child()

实现 JS 函数柯里化

  • 柯里化:把接受多个参数的函数转化成接收一个参数的函数,并且,函数总会返回一个接收余下参数的函数。
  • 实现原理:利用一个临时函数的闭包存储参数总数以及上次的入参数量,当参数总数量与当前积累参数数量相同时,则执行函数,否则回调继续积累参数。
// es5 function curry(fn, args){ let length = fn.length // 参数总数量 args = args || [] return function(){ let newArgs = args.concat(Array.prototype.slice.call(arguments)) if (newArgs.length < length) { return curry.call(this, fn, newArgs) } else { return fn.apply(this, newArgs) } } } // es6写法 const curry = (fn, arr = []) => (...args) => ( arg => fn.length === arg.length ? fn(...arg) : curry(fn, arg) )([...arr, ...args]) // function multiFn(a, b, c) { // return a * b * c; // } // let multi = curry(multiFn) // console.log(multi(1,3)(4));

实现一个Promise

思路:

  1. 创建 primise 类,拥有 status , value, defferds 3个属性
  2. status 有3个: PENDDING、FULFILLED、 REJECTED, value 为 Promise 得到的返回值,defferds 为 defferd 列表
  3. resolve:将当前 promise 状态由 PENDDING 置于 FULFILLED, 并返回一个值给Promise,处理 defferds 列表
  4. reject:与 resolve类似,将当前 promise 状态由 PENDDING 置于 REJECTED, 并返回一个值给Promise,处理 defferds 列表
  5. then: 为 promise 注入 defferd,返回这个 defferd 内的 promise
  6. defferd: 由一个 promise, fulfilled_callback, rejected_callback 构成
const PENDDING = 1 const FULFILLED = 2 const REJECTED = 3 class Promise { constructor(fn){ this.status = PENDDING this._value this.defferds = [] if(!fn) return this.doResolve(fn, this) } then(fulfill_cb, reject_cb) { let res = new Promise() let deferred = { promise: res, fulfilled: typeof fulfill_cb === 'function'? fulfill_cb : null, rejected: typeof reject_cb === 'function'? reject_cb : null } this.handle(this, deferred) return res } handle (self, deferred) { // 处理 deferred if(this.status === PENDDING) { // PENDDING 状态下,将 deferred 存入列表 this.defferds.push(deferred) } else { // promise 非 pendding 时处理 deferred this.handleResolved(self, deferred) } } handleResolved (self, deferred) { // 需要延时执行( 延时执行(new promise 回调内为同步执行,所以 promise 在进行 then 调用时很可能状态已非 PENDDING,此时则直接调用了 handleResoved 函数,为了保证 then 参数的函数异步执行,所以这里需延迟执行) setTimeout(() => { let cb = self.status === FULFILLED ? deferred.fulfilled : deferred.rejected if (cb === null) { if (self.state === FULFILLED) { self.resolve(deferred.promise, self._value); } else { self.reject(deferred.promise, self._value); } return; } var ret = cb(self._value) self.resolve(deferred.promise, ret) }, 4); } doResolve (fn, self) { var done = false fn(function(value){ if(done) return done = true self.resolve(self, value) }, function(value){ if(done) return done = true self.reject(self, value) }) } resolve(self, newValue) { if (newValue === self) return self.reject(self, new Error('A promise cannot be resolved with itself.')) // 这里只考虑 value是基本类型值的情况 self.status = FULFILLED self._value = newValue this.finale(self) } reject(self, newValue) { self.status = REJECTED self._value = newValue this.finale(self) } finale(self) { // 遍历处理 promise 的 deferred for (let i = 0; i < self.defferds.length; i++) { self.handle(self, self.defferds[i]); } self.defferds = null } }

防抖(Debouncing)和节流(throttling)实现

  • 防抖:一次事件发生时,延时一段时间后执行,若这段时间内又发生了新事件,之前的事件则被销毁,然后从新事件开始重新计时
  • 节流:一次事件发生后,立即执行,之后一段时间内若发生了事件,则忽略
// 防抖 function debounce(fn,wait=50,immediate) { let timer return function(){ if(immediate) { fn.apply(this, [...arguments]) } if(times) clearTimeout(timer) timer = setTimeout(()=>{ fn.apply(this, [...arguments]) }, wait) } } // 节流 function throttling(fn, wait = 50) { let date = new Date() return function(){ let now = new Date() if (now - date > wait) { date = now fn.apply(this, [...arguments]) } } }

深拷贝 (简单版)

// var newObj = JSON.parse( JSON.stringify( someObj ) ); function deep(obj){ let result = {} if(typeof obj === 'object' && obj !== null) { if(Array.isArray(obj)) { result = [] } for(let k in obj) { result[k] = typeof obj[k] === 'object' ? deep(obj[k]) : obj[k] } } return result }

实现一个 instanceof

obj installOf Fun: 查询 构造函数 Fun 的原型是否在对象 obj 的原型链上.

function instanceof(obj, fn) { let pro = obj.__proto__ if(pro === null) return false if(pro === fn.prototype) { return true } else { instanceof(pro, fn) } } console.log(instanceof({}, Object));
😁😂😃😄😅😆😇😈😉😐😑😒😓😔😕😖😗😘😙😠😡😢😣😤😥😦😧😨😩😰😱😲😳😴😵😶😷😸😹🙀🙁🙂🙃🙄🙅🙆🙇🙈
🙂