js高级用法----手写js原生方法

1、call 方法

/**
 * _call
 *
 * @param { context } context
 * @param { arguments } arguments
 */
Function.prototype._call = function(context) {
  // 如果没有传或传的值为空对象 context指向window
  context = context || window
  let fn = Symbol(context)
  context[fn] = this //给context添加一个方法 指向this
  // 处理参数 去除第一个参数this 其它传入fn函数
  let args = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组
  context[fn](...args) //执行fn
  delete context[fn] //删除方法
}

var obj = {
    name: 'Bob',
    age: '18',
    fn() {
        console.log(`My name is ${this.name}, my age is ${this.age}`)
    }
}

var dog = {
    name: 'Snoopy',
    age: 3
}
obj.fn.call(dog,'daddata','ttt','yuyuyuuy') // My name is Snoby, my age is 3
obj.fn._call(dog,'daddata','ttt','yuyuyuuy') // My name is Snoby, my age is 3

2、 apply 方法

Function.prototype._apply = function(context) {
    // 如果没有传或传的值为空对象 context指向window
    context = context || window
    let fn = Symbol(context)
    context[fn] = this 
    let arg = [...arguments].slice(1) 
    context[fn](arg) //执行fn
    delete context[fn] //删除方法
}

3、bind方法

/**
 * _bind
 *
 * @param {*} context
 */
Function.prototype._bind = function (context) {
  //返回一个绑定this的函数,我们需要在此保存this
  let self = this
  // 可以支持柯里化传参,保存参数
  let arg = [...arguments].slice(1)
  // 返回一个函数
  return function () {
    //同样因为支持柯里化形式传参我们需要再次获取存储参数
    let newArg = [...arguments]
    // 返回函数绑定this,传入两次保存的参数
    //考虑返回函数有返回值做了return
    return self.apply(context, arg.concat(newArg))
  }
}

4、promise方法

function MyPromise(exceptor) {
  let _this = this;
  _this.reason = '';
  _this.value = '';
  _this.resolveFnArr = [];
  _this.rejectFnArr = [];
  _this.status = 'pending';
  function resolve(val) {
    if (_this.status === 'pending') {
      _this.value = val;
      _this.status = 'fulfiled';
      _this.resolveFnArr.forEach(fn => fn())
    }
  }

  function reject(reason) {
    if (_this.status === 'pending') {
      _this.reason = reason;
      _this.status = 'reject';
      _this.rejectFnArr.forEach(fn => fn())
    }
  }

  try {
    exceptor(resolve, reject);
  } catch (error) {
    reject();
  }
}

MyPromise.prototype.then = function(resolve, reject) {
  let _this = this;
  if (_this.status === 'fulfiled') {
    resolve(_this.value);
  }
  if (_this.status === 'reject') {
    reject(_this.reason);
  }

  if (_this.status === 'pending') {
    _this.resolveFnArr.push(() => {resolve(_this.value)})
    _this.rejectFnArr.push(() => {reject(_this.reason)})
  }
}

5、全面的promise写法

(function(window,undefined){
 
  // resolve 和 reject 最终都会调用该函数
  var final = function(status,value){
      var _this = this, fn, status;
   
      if(_this._status !== 'PENDING') return;
   
      // 所以的执行都是异步调用,保证then是先执行的
      setTimeout(function(){
          _this._status = status;
          status = _this._status === 'FULFILLED'
          queue = _this[status ? '_resolves' : '_rejects'];
   
          while(fn = queue.shift()) {
              value = fn.call(_this, value) || value;
          }
   
          _this[status ? '_value' : '_reason'] = value;
          _this['_resolves'] = _this['_rejects'] = undefined;
      });
  }
   
   
  //参数是一个函数,内部提供两个函数作为该函数的参数,分别是resolve 和 reject
  var MyPromise = function(resolver){
      if (!(typeof resolver === 'function' ))
          throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
      //如果不是promise实例,就new一个
      if(!(this instanceof MyPromise)) return new MyPromise(resolver);
   
      var _this = this;
      _this._value;
      _this._reason;
      _this._status = 'PENDING';
      //存储状态
      _this._resolves = [];
      _this._rejects = [];
   
      //
      var resolve = function(value) {
          //由於apply參數是數組
          final.apply(_this,['FULFILLED'].concat([value]));
      }
   
      var reject = function(reason){
          final.apply(_this,['REJECTED'].concat([reason]));
      }
   
      resolver(resolve,reject);
  }
   
  MyPromise.prototype.then = function(onFulfilled,onRejected){
      var _this = this;
      // 每次返回一个promise,保证是可thenable的
      return new MyPromise(function(resolve,reject){
   
          function handle(value) {
              // 這一步很關鍵,只有這樣才可以將值傳遞給下一個resolve
              var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value;
   
              //判断是不是promise 对象
              if (ret && typeof ret ['then'] == 'function') {
                  ret.then(function(value) {
                      resolve(value);
                  }, function(reason) {
                      reject(reason);
                  });
              } else {
                  resolve(ret);
              }
          }
   
          function errback(reason){
              reason = typeof onRejected === 'function' && onRejected(reason) || reason;
              reject(reason);
          }
   
          if(_this._status === 'PENDING'){
              _this._resolves.push(handle);
              _this._rejects.push(errback);
          }else if(_this._status === FULFILLED){ // 状态改变后的then操作,立刻执行
              callback(_this._value);
          }else if(_this._status === REJECTED){
              errback(_this._reason);
          }
      });
  }
   
  MyPromise.prototype.catch = function(onRejected){
      return this.then(undefined, onRejected)
  }
   
  MyPromise.prototype.delay = function(ms,value){
      return this.then(function(ori){
          return MyPromise.delay(ms,value || ori);
      })
  }
   
  MyPromise.delay = function(ms,value){
      return new MyPromise(function(resolve,reject){
          setTimeout(function(){
              resolve(value);
              console.log('1');
          },ms);
      })
  }
   
  MyPromise.resolve = function(arg){
      return new MyPromise(function(resolve,reject){
          resolve(arg)
      })
  }
   
  MyPromise.reject = function(arg){
      return MyPromise(function(resolve,reject){
          reject(arg)
      })
  }
   
  MyPromise.all = function(promises){
      if (!Array.isArray(promises)) {
          throw new TypeError('You must pass an array to all.');
      }
      return MyPromise(function(resolve,reject){
          var i = 0,
              result = [],
              len = promises.length,
              count = len
   
          //这里与race中的函数相比,多了一层嵌套,要传入index
          function resolver(index) {
            return function(value) {
              resolveAll(index, value);
            };
          }
   
          function rejecter(reason){
              reject(reason);
          }
   
          function resolveAll(index,value){
              result[index] = value;
              if( --count == 0){
                  resolve(result)
              }
          }
   
          for (; i < len; i++) {
              promises[i].then(resolver(i),rejecter);
          }
      });
  }
   
  MyPromise.race = function(promises){
      if (!Array.isArray(promises)) {
          throw new TypeError('You must pass an array to race.');
      }
      return MyPromise(function(resolve,reject){
          var i = 0,
              len = promises.length;
   
          function resolver(value) {
              resolve(value);
          }
   
          function rejecter(reason){
              reject(reason);
          }
   
          for (; i < len; i++) {
              promises[i].then(resolver,rejecter);
          }
      });
  }
   
  window.MyPromise = MyPromise;
   
  })(window);

 

上一篇:【】future用法


下一篇:手写实现 MyPromise 源码 ,尽可能还原 Promise 中的每一个 API,并通过注释的方式描述思路和原理。