ES5實現ES6的一些方法-call,bind,is,promise

高大師發表於2019-02-22

Object.is

Object.is = function(x, y) {
  // SameValue algorithm
  if (x === y) { // Steps 1-5, 7-10
    // Steps 6.b-6.e: +0 != -0
    return x !== 0 || 1 / x === 1 / y;
  } else {
    // Step 6.a: NaN == NaN
    return x !== x && y !== y;
  }
};複製程式碼

call

Function.prototype.myCall = function (context) {
  var context = context || window;
  context.fn = this;

  var args = [];
  for (var i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']');
  }

  // var result = eval('context.fn(' + args + ')');
  var result = new Function('context', 'arguments', 'context.fn(' + args + ')')(context, arguments)
  delete context.fn
  return result;
}複製程式碼

bind

Function.prototype.bind = function(oThis) {
  if (typeof this !== 'function') {
    // closest thing possible to the ECMAScript 5
    // internal IsCallable function
    throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
  }

  var aArgs   = Array.prototype.slice.call(arguments, 1),
    fToBind = this,
    fNOP    = function() {},
    fBound  = function() {
      return fToBind.apply(this instanceof fNOP
        ? this
        : oThis,
        // 獲取呼叫時(fBound)的傳參.bind 返回的函式入參往往是這麼傳遞的
        aArgs.concat(Array.prototype.slice.call(arguments)));
    };

  // 維護原型關係
  if (this.prototype) {
    // Function.prototype doesn't have a prototype property
    fNOP.prototype = this.prototype;
  }
  fBound.prototype = new fNOP();

  return fBound;
};複製程式碼

節流 去抖

var throttleV1 = function(action, delay, mustRunDelay) {
  var timer = null,
    startTime;

  return function() {
    var self = this,
      args = arguments,
      currTime = new Date();

    clearTimeout(timer);

    if(!startTime) {
      startTime = currTime;
    }

    if(currTime - startTime >= mustRunDelay) {
      action.apply(self, args);
      startTime = currTime;
    }
    else {
      timer = setTimeout(function() {
        action.apply(self, args);
      }, delay);
    }
  };
};
var debounce = function(action, delay) {
  var timer = null;

  return function() {
    var self = this,
      args = arguments;

    clearTimeout(timer);
    timer = setTimeout(function() {
      action.apply(self, args)
    }, delay);
  }
}複製程式碼

四捨五入-原生toFixed() 方法不準確

function toFixed(num, s) {
  var times = Math.pow(10, s);
  var des = num * times + 0.5;
  des = parseInt(des, 10) / times;
  return des + '';
}複製程式碼

小數相乘

function accMul(arg1, arg2) {
 let m = 0,
   s1 = arg1.toString(),
   s2 = arg2.toString()
 try {
   m += s1.split('.')[1].length
 } catch (e) {} // eslint-disable-line
 try {
   m += s2.split('.')[1].length
 } catch (e) {} // eslint-disable-line

 return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m)
}複製程式碼

使物件擁有 iterator 

var myObject = { a: 2,
  b: 3 };
Object.defineProperty( myObject, Symbol.iterator, { enumerable: false,
  writable: false,
  configurable: true,
  value: function() { var o = this;
    var idx = 0;
    var ks = Object.keys( o ); return {
      next: function() { return {
        value: o[ks[idx++]],

        done: (idx > ks.length)
      };

      } };
  } } );
// 手動遍歷 myObject
var it = myObject[Symbol.iterator]();
it.next(); // { value:2, done:false } 
it.next(); // { value:3, done:false }
it.next(); // { value:unde ned, done:true }
// 用 for..of 遍歷 myObject 
for (var v of myObject) { console.log( v );
}
// 2 
// 3複製程式碼

數字轉為ABC

function convertToTitle(n) {
  let arr = []
  while (n > 0) {
    let c = ((n-1 ) % 26) + 65
    arr.unshift(String.fromCharCode(c))
    n = Math.floor((n - 1) / 26)
  }
  return arr.join('')
};複製程式碼

簡單實現promise

function myPromise (fn) {

  this.state = 'PENDING'
  this.value = null
  this.handlers = []
  
  function resolve (result) {
    var that = this
    
    // 可以不加setTimeout , 加上只為了實現像原生一樣resolve非同步
    // setTimeout(function(){
    this.state = 'FULFILLED'
    this.value = result
    this.handlers.forEach(function (callback) {
         callback( result);
      })
      // })
    }

  fn(resolve.bind(this) )
}


myPromise.prototype.then = function (onFulfilled) {

  var self = this;
  return new myPromise(function(resolve, reject) {

    function handle(value){
      var result = typeof onFulfilled === 'function' && onFulfilled(value) || value;
      if( result && typeof result['then'] == 'function'){
        result.then(function(value){
          resolve(value);
        });
      }else {
        resolve(value);
      }
    }
    if (self.state === 'PENDING') {
      self.handlers.push(handle);
    }

    if (self.state === 'FULFILLED') {

     handle(self.value)

    }

    if (this.state === 'REJECTED') {
      reject(self.value)
    }

  })

}複製程式碼


相關文章