一些JS方法

二分搜索

二分搜索法,也称折半搜索,是一种在有序数组中查找特定元素的搜索算法。
有序的二分查找,返回-1或存在的数组下标。不使用递归实现

function binarySearch (target, arr) {
    var start = 0;
    var end = arr.length - 1;

    while (start <= end) {
        var mid = parseInt(start + (end - start) / 2); // 获取中间值取整
        
        // 如果target等于中间值就直接返回
        if (target === arr[mid]) {
            return arr[mid];
        }
        // 如果target大于中间值就从右边开始寻找
        else if (target > arr[mid]) {
            start = mid + 1;
        }
        else {
            end = mid - 1;
        }
    }
    return -1;
}

无序的二分查找

// 无序的二分查找,返回-1或存在的数组下标。不使用递归实现
function binarySearch (target, arr) {
    while (arr.length > 0) {
        // 使用快速排序。以mid为中心划分大小,左边小,右边大。
        var left = [];
        var right = [];
        // 选择第一个元素作为基准元素(基准元素可以为任意一个元素)
        var pivot = arr[0];
        
        // 由于取了第一个元素,所以从第二个元素开始循环
        for (var i = 1; i < arr.length; i++) {
            var item = arr[i];
            // 大于基准的放右边,小于基准的放左边
            item > pivot ? right.push(item) : left.push(item);
        }

        // 得到经过排序的新数组
        if (target === pivot) {
            return pivot;
        }
        else if (target > pivot) {
            arr = right;
        }
        else {
            arr = left;
        }
    }
    return -1;
}

JavaScript instanceof 运算符代码

//L 表示左表达式,R 表示右表达式
function instance_of(L,R) { 
    var O = R.prototype; // 取R的显示原型
    L = L.__proto__; // 取L的隐式原型
    while(true) {
        if (L === null) {
            return false
        }
        // R.prototype === L.__proto__
        if (O === L) { // 这里重点:当 O 严格等于 L 时,返回 true  
            return true;
        }
        L = L.__proto__; 
    }
}

on(注册一个事件)

Event.prototype.on = function (type, fun) {
    let cbs = this._events[type];
    cbs ? cbs.push(fun) : this._events[type] = [];
    if(!cbs) {
        this._events[type].push(fun)
    }
}

这里为什么要将this._events设计为二维数组?因为事件可以是多个,但是事件名可能相同。
这个逻辑意图非常明显,根据type参数从this._events中获取是否存在。如果不存在,创建一个type为key的数组,并将事件句柄程序push到数组中。

off(注销一个事件)

Event.prototype.off = function (type, fun) {
    let cbs = this._events[type];
    // 事件队列中无事件
    if (!cbs) {
        return this;
    }
    // 删除所有的事件
    if (!type && !fun) {
        this._events = {};
        return this;
    }
    // 只有事件名称时
    if (type && !fun) {
        this._events[type] = null;
        return this;
    }
    // 删除某个事件队列中的某个事件
    let cb;
    let i = cbs.length;
    while (i--) {
        cb = cbs[i];
        if (cb === fun || cb.fun === fun) {
            cbs.splice(i, 1);
            break;
        }
    }
};

虽然注销事件方法的逻辑可能相比下稍许多了些,但它的实现也非常简单,只要只存在事件组key名的情况,或者删除某个事件队列中的某个事件句柄程序即可

emit(触发一个事件)

Event.prototype.emit = function(type){
    let cbs = this._events[type];
    let args = tools.toArray(arguments,1);
    if (cbs) {
        let i = 0;
        let j = cbs.length;
        for(;i<j;i++){
            let cb = cbs[i];
            cb.apply(this,args);
        }
    }
}

这里通过事件名从this._events获取相应的事件句柄程序数组,然后将arguments转成数组,(这里考虑是可能会传入参数)如果事件句柄程序数组存在,进行循环,再将args参数apply给每一个取出来的事件句柄程序。

实现一个clon,对js中的5种主要数据类型镜像复制

function clone (obj) {
    var o;
    switch (typeof obj) {
        case "undefined":
            break;
        case "string":
            o = obj + "";
            break;
        case "number":
            o = obj - 0;
            break;
        case "boolean":
            o = obj;
            break;
        case "object": // object分为两种情况一种是对象 一种是数组
            if (obj === null) {
                o = null;
            }
            else {
                if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {
                    o = [];
                    for (var i = 0; i < obj.length; i++) {
                        o.push(clone(obj[i]));
                    }
                }
                else {
                    o = {};
                    for (var k in obj) {
                        o[k] = clone(obj[k]);
                    }
                }

            }

    }
    return o;
}

消除一个数组里面重复的元素

var arr1 = [1, 2, 2, 2, 3, 3, 3, 4, 5, 6];
var arr2 = [];
for (var i = 0; i < arr1.length; i++) {
    if (arr2.indexOf(arr1[i]) < 0) { // 如果要检索的字符串值没有出现
        arr2.push(arr1[i]) // push进入数组
    }
}
console.log(arr2); // [1, 2, 3, 4, 5, 6]

消除字符串前后空格

function trim (str) {
    if (str && typeof str === 'string') {
        return str.replace(/(^\s*)|(\s*$)/g, ''); //去除前后空白符
    }
}

var str = '             ab             ';
console.log(trim(str)); // ab

求一个字符串的字节长度

function GetBytes (str) {
    var len = str.length;
    var bytes = len;
    for (var i = 0; i < len; i++) {
        if (str.charCodeAt(i) > 255) {
            bytes++;
        }
    }
    return bytes
}

简单实现 Function.bind 函数

if (!function() {}.bind) {
    Function.prototype.bind = function(context) {
        var self = this;
        var args = Array.prototype.slice.call(arguments);
        return function() {
            return self.apply(context, args.slice(1));
        }
    };
}

JavaScript中对一个对象进行深度clone

function cloneObject (obj) {
    if (!obj || 'object' !== typeof obj) {
      return obj
    }
    
    let clone = 'function' === typeof obj.pop ? [] : {};
    let value;

    // 遍历对象
    for (i in obj) {
      if (obj.hasOwnProperty(i)) {
        value = obj[i];
        if (value && 'object' !== value) {
          clone[i] = cloneObject(value)
        }
        else {
          clone[i] = value;
        }
      }
    }

    return clone
  }

URL参数解析为一个对象

function parseQueryString (url) {
    let param = {};
    let arr = url.split('?');
    if (arr.length <= 1) {
      return;
    }

    arr = arr[1].split('&');

    for (let i = 0; i < arr.length; i++) {
      let data = arr[i].split('=');

      param[data[0]] = data[1];
    }
    return param;
  }

实现ECMAScript 5中的Object.getPrototypeOf() 函数

该方法返回的是指定对象的原型(内部[[Prototype]]属性的值) 如果参数不是一个对象类型就会抛出一个异常(ES5中参数会自动转换为对象)

function proto(obj) {
  return !obj ? null : '__proto__' in obj ? obj.__proto__ : obj.constructor.prototype
}

实现Array.prototype.forEach?

Array.prototype.forEach = function (fn) {
  for (let i=0;i<this.length;i++) {
    fn(this[i],i,this)
  }
}

兼容浏览器的获取指定元素(elem)的样式属性(name)的方法

function getStyle (ele, name) {
  // 如果属性中存在style[]中就直接获取
  if (ele.style[name]) {
    return ele.style[name];
  }
  // IE方法
  else if (ele.currentStyle) {
    return ele.currentStyle[name]
  }
  // w3c方法
  else if (document.defaultView && document.defaultView.getComputedStyle) {
    name = name.replace(/(A-Z)/g,'$1').toLowerCase(); // W3C中为textAlign样式,转为text-align转换小写
    let style = document.defaultView.getComputedStyle(ele);
    
    return `${name}:${style.getPropertyValue(name)}`
  }
}

函数记忆,判断是不是质数

function isPorimel (n) {
      if (n <= 3) {
        return true;
      }
      else {
        for (let i = 2;i< Math.sqrt(n);i++) {
          // 不能被其他自然数整除的数叫做质数
          if (n % i === 0) {
            return false;
          }
        }
        return true
      }
    }

函数currying(柯里华)

let getN;
function add(n) {
  getN = function (n) {
    return n
  }
  
  return function (m) {
    n += m;
    argument.callee.toString = function() {
      return n;
    }
    return argument.callee
  }
  
}

递归

var emp={
 work:function(){//3,2,1
  var  sum=0;//+3+2+1 +2+1  +1
  for(vari=0; i<arguments.length&&arguments[0]>0;
        i++){
        sum+=arguments[i]
            +arguments.callee(
              --arguments[i]
            );
      }
      return sum;
    }
  }
  console.log(emp.work(3,2,1));//10

自定义Object.create()

Object.create = function (father) {
  // 方法1
  let obj = Object();
  Object.setPrototypeOf(obj, father)
  
  // 方法2
  function Constructor(){}
  Constructor.prototype = father
  let obj = new Constructor();
  
  return 
}

深克隆原理

function clone(obj) {
  if (typeof obj !== 'object') {
        return obj;
  }
  
  let o = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {} // 区分数组和普通对象
  
  for (let key in obj) {
     if (obj.hasOwnProperty(key)) {
       o[key] = arguments.callee(obj[key]); 
     }
  }
  
  return o      
}

every的实现原理

Array.prototype.every = function(fun){
  for (let i=0;i<this.length;i++) {
    if (this[i] !== undefined) {
      let f = fun(this[i],i,this)
      if (f === false) {
        return false
      }
    }
  }
  return true
}

some的实现原理

Array.prototype.some = function (fun) {
    for (let i = 0; i < this.length; i++) {
      if (this[i] !== undefined) {
        let r = fun(this[i], i, this);
        if (r === true) {
          return true
        }
      }
    }
    return false
};

map的实现原理

Array.prototype.map = function(fun){
  // 创建一个数组
  let newArray = []
  // 遍历当前数组的元素
  for (let i=0;i<this.length;i++) {
    if (this[i] !== undefined) {
      let r = fun(this[i],i,this)
      newArray[i] = r
    }
  }
  return newArray
}