美文网首页
JS杂项备忘录

JS杂项备忘录

作者: burningalive | 来源:发表于2019-02-05 17:40 被阅读0次

快速排序

const utils = {
  swap(array, a, b) {
    [array[a], array[b]] = [array[b], array[a]]
  },
  randomNum() {
    return Math.floor(Math.random() * 100)
  },
  randomArray() {
    return Array.from(Array(this.randomNum()), _ => this.randomNum())
  }
}

function partition(array, start, end) {
  let j = start
  let index = Math.floor(Math.random()*(end -start + 1) + start)
  utils.swap(array, index, end)
  let pivot = array[end]
  for (let i = start; i <= end; i++) {
    if (array[i] <= pivot) {
      utils.swap(array, i, j++)
    }
  }
  return j - 1
}

function quickSort(array, start = 0, end = array.length -1) {
  if (end - start < 1) return array
  let pivotIndex = partition(array, start, end)
  quickSort(array, start, pivotIndex - 1)
  quickSort(array, pivotIndex + 1, end)
  return array
}
let array = utils.randomArray()
console.log(quickSort(array))

函数组合

function pipe(...funcs){
    return function(x){
        return funcs.reduce(function(accu, func){
            return func(accu);
        }, x);
    }
}
let str = 'jspool'

function stringToUpper(str) {
    return str.toUpperCase()
}

function stringReverse(str) {
    return str.split('').reverse().join('')
}

function getThreeCharacters(str){
    return str.substring(0,3)
}

function stringToArray(str) {
    return str.split('')
}

let toUpperAndGetThreeAndArray = compose(stringToArray, getThreeCharacters,stringToUpper)
let result = toUpperAndGetThreeAndArray(str) // => ["J","S","P"]

call, bind, apply

 Function.prototype.myCall = function (context, ...arg) {
        const fn = Symbol('临时属性')
        context[fn] = this
        context[fn](...arg)
        delete context[fn]
    }
    Function.prototype.myBind = function (context, ...firstarg) {
        const that = this
        const bindFn = function (...secoundarg) {
            return that.myCall(context, ...firstarg, ...secoundarg)
        }
        bindFn.prototype = Object.create(that.prototype)
        return bindFn
    }

事件

  1. DOM事件流:捕获阶段 → 目标阶段 → 冒泡阶段
  2. 事件捕获的具体流程:window document html body → 元素
    注意,第一个接收到事件的是window。
    获取HTML根元素,document.documentElement

dom操作

node.parentNode
node.removeChild()

function findParent(node) {
  let parentNode = node.parentNode;
  let root = this.el.find(item => item === parentNode);
  if (root) {
    root.removeChild();
  } else {
    findParent(parentNode);
  }
  window.addEventListener('DOMContentLoaded', function () {}, false);
}

Event对象的常见应用

event.preventDefault()阻止默认事件。
event.stopPropagation()阻止冒泡(防止父级元素响应)。
event.stopImmediatePropagation()给同一个元素注册两个同类型事件a,b;在a事件注册函数中添加这段调用,可阻止b的注册事件触发。
event.currentTarget触发时获取当前绑定的事件元素(常用于事件委托获取父级元素)。
event.target 获取当前触发的目标对象(子级元素)。

自定义事件

Event无法传参,其余与CustomEvent一致.
CustomEvent传递参数,需在new CustomEvent的第二个参数给定一个拥有detail属性的对象。

ele.addEventListener('custome', function(e){
  console.log(e.deatil.data);  // Event时为null, CustomEvent时为‘somedata’
});
var eve = new Event('custome');
var eve = new CustomEvent('custome', {
  detail: { 
    data: 'somedata'
  }
});
ele.dispatchEvent(eve);

类型转换

Number函数

转换时优先调用valueOf,后toString,这两步操作如果返回基本数据类型则将这个值重新调用Number函数,如果这两步都未返回基础数据类型则报错。
字符串:如果可以解析为数值,转换为相应值,不同于parseInt,包含非数字字符会返回NaN,为小数则返回小数,空字符串返回0.
undefined:返回NaN。
null:返回0.

[] + []答案为空字符串。 加号运算符两侧未出现字符串,优先转换为数据,左侧valueOf返回其本身,故继续调用toString,数组toString方法相当于调用join方法,返回空字符串,右侧同理。
{} + []答案为0。左侧大括号被认为为空代码块,运算表达式实为+[],对空数组调用Number方法,空数组toString后为空字符串,Number('')返回0。
[] + {}答案为'[object Object]'。空数组被转为空字符串,加号左侧为string故右侧值转为string类型。

原型链

创建对象的几种方法

  1. 直接书写字面量或new Object({ })
  2. function的new调用
  3. Object.create(obj)

模拟new运算符

var myNew = function (func, ...arg){
    var obj = Object.create(func.prototype);
    var res = func.apply(obj, arg);
    if (typeof res === 'object') return res;
    else return obj;
}

function继承

function Parent() {
  this.name = 'parent';
  this.arr = [1, 2, 3];
}
function Child() {
  Parent.call(this);
  this.type = 'child';
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

运行机制类

  1. 如何理解js的单线程

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

什么是任务队列
什么是event loop: 「面试必考」从多线程到Event Loop全面梳理
将语句放入异步任务队列的时机

具体参考饿了么前端的这两篇文章
Event Loop 这个循环你晓得么?(附GIF详解)

设计模式

  1. 观察者模式 订阅发布
class Publisher {
  constructor() {
    this.eventEmitter = new EventEmitter();
  }
  publish(type, ...args) {
   this.eventEmitter.emit(type, ...args);
  }
}
class Subscriber {
  constructor() {
    this.eventEmitter = new EventEmitter();
  }
  subscribe(publisher, type) {
   publisher.eventEmitter.on(type, subscriber, cb);
  }
}
class EventEmitter {
    constructor() {
        // 定义存放事件订阅的存储变量
        this.listeners = {};
    }

    on(type, subscriber, cb) {
        let cbs = this.listeners[type];
        if (!cbs) {  // 判断是否已经有订阅
            cbs = [];
        }
        // 订阅一则事件
        cbs.push(cb);
        this.listeners[type] = cbs;
        return this;
    }

    emit(type, ...args) {
        const cbs = this.listeners[type];
        if (Array.isArray(cbs)) {
            for (let i = 0; i < cbs.length; i++) {
                const cb = cbs[i];
                if (typeof cb === 'function') {
                    // 触发一则事件
                    cb(...args);
                }
            }
        }
        return this;
    }

    off(type, cb) {
        if (cb) {  // 如果有回调,则取消订阅该回调
            let cbs = this.listeners[type];
            cbs = cbs.filter(func => func !== cb);
            this.listeners[type] = cbs;
        } else {  // 否则取消订阅整个事件
            this.listeners[type] = null;
            delete this.listeners[type];
        }
        return this;
    }
}

export default new EventEmitter();

以下这种则是给每个对象上方添加listener的实现方式, 使用WeakMap

var listeners = new WeakMap();
// 监听事件
function on(object, event, fn){
    var thisListeners = listeners.get(object);
    if(!thisListeners) thisListeners = {};
    if(!thisListeners[event]) thisListeners[event] = [];
    thisListeners[event].push(fn);
    listeners.set(object, thisListeners);
}
// 触发事件
function emit(object, event){
    var thisListeners = listeners.get(object);
    if(!thisListeners) thisListeners = {};
    if(!thisListeners[event]) thisListeners[event] = [];
    thisListeners[event].forEach(function(fn){
        fn.call(object, event);
    });
}
// 使用
var obj = {};
on(obj, 'hello', function(){
    console.log('hello');
});
emit(obj, 'hello');

一些题

  1. 完成函数changeDateFormate, 将字符串中的'MM/DD/YYYY'为替换为'YYYY/MM/DD'.
    输入: 'John was born in 02/13/1920 and died in 01/20/1970.'
    输出: 'John was born in 1920/02/13 and died in 1970/01/20.'
function changeDateFormate(str) {
  const dateReg = /\d{2}\/\d{2}\/\d{4}/g;
  var times = str.match(dateReg);
  times = times.map(item => {
    var times = item.split('/');
    times.unshift(times.pop());
    return times.join('/');
  });
  var splitDateStrs = str.split(dateReg);
  var res = [];
  splitDateStrs.forEach((item, idx) => {
     res.push(item); 
     times[idx] && res.push(times[idx]);
  });
  return res.join('');
}
  1. css3设计一个立起的圆形, 并围绕自身中轴线做360度持续旋转.
  2. css分割单行和多行截断字符串, 最后以...结尾
.单行 {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  width: xxpx;
}
.多行 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  text-overflow: ellipsis;
  -webkit-box-orient: vertical; // 好像不需要这个
}
  1. 什么是CSRF, 怎么造成的, 有什么防御方法?
  2. Cookie和Session有什么区别
  3. 如何html中开启关闭DNS预读取?
    <meta http-equiv="x-dns-prefetch-control" content="on">
  4. <script>标签defer或async属性的取用及二者的区别?
  1. defer: HTML解析完后才执行, 如果有多个, 按照加载的顺序一次执行
  2. async: 加载完之后立即执行, 如果有多个, 执行顺序和加载顺序无关
  1. 设计移到js的range算法, 如下:
    range(1, 10, 3), 返回[1, 4, 7, 10]. range('A', 'F', 2), 返回['A', 'C', 'E'].
    使用'A'.charCodeAt(0)String.fromCharCode()
function range(start , end , interval) {
    const res = [];
    if (typeof start == 'string' && typeof end =='string') {
        start = start.charCodeAt(0);
        end = end.charCodeAt(0);
        for (let i = start; i<=end; i+=interval) {
               res.push(String.fromCharCode(i));
      } 
    } else if (typeof start == 'number' && typeof end == 'number'){
      for (let i = start; i<=end; i+=interval) { 
          res.push(i);
        } 
    }
    return res;
}
  1. [{
    time: number,
    content: string
    },
    {
    time: number,
    content: string
    },
    ...]. 需要快速定位到某个时间点的弹幕, 请编码实现(不使用sort)

Object深拷贝.

目前虽然已经考虑到很多条件, 但还不太完善.
在codepen上打开

// 简化版本
function clone(target, map = new WeakMap()) {
    if (!isObject(target)) {
      return target;
    } else {
        const isArray = Array.isArray(target);
        let cloneTarget = new target.constroctor();

        if (!map.has(target)) {
          map.set(target, cloneTarget);
        } else {
          return map.get(target);
        }

        const keys = isArray ? undefined : Reflect.ownKeys(target);
        forEach(keys || target, (value, key) => {
            if (keys) {
                key = value;
            }
            cloneTarget[key] = clone(target[key], map);
        });
        return cloneTarget;
    }
}
function isObject(target) {
    const type = typeof target;
    return target !== null && (type === 'object' || type === 'function');
}
function getType(target) {
    return Object.prototype.toString.call(target);
}

function forEach(array, iteratee) {
    let index = -1;
    while (++index < array.length) {
        iteratee(array[index], index);
    }
}
const target = {
    field1: 1,
    field2: undefined,
    field3: {
        child: 'child'
    },
    field4: [2, 4, 8],
    f: { [Symbol()]: { f: { f: { f: { f: { f: { f: { f: { f: { f: { f: {} } } } } } } } } } } },
};


// 以下是更全的版本

const mapTag = 'Map'; const setTag = 'Set'; const arrayTag = 'Array'; 
const objectTag = 'Object'; const argsTag = 'Arguments'; const boolTag = 'Boolean'; 
const numberTag = 'Number'; const stringTag = 'String'; 
const symbolTag = 'Symbol';  const regexpTag = 'RegExp'; const funcTag = 'Function';

const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];

function isObject(target) {
    const type = typeof target;
    return target !== null && (type === 'object' || type === 'function');
}

function getType(target) {
    return Object.prototype.toString.call(target).slice(8, -1);
}

function cloneReg(targe) {
    const reFlags = /\w*$/;
    const result = new RegExp(targe.source, reFlags.exec(targe)[0]);
    result.lastIndex = targe.lastIndex;
    return result;
}

function cloneFunction(func) {
    const funcString = func.toString();
    if (!func.prototype) {
        return eval(funcString);
    } else {
        const bodyReg = /(?<={).*(?=})/s;
        const paramReg = /(?<=\().*(?=\)\s*{)/s;
        const param = paramReg.exec(funcString);
        const body = bodyReg.exec(funcString);
        if (body) {
            if (param) {
                return new Function(param[0], body[0]);
                const paramArr = param[0].split(',');
                // return new Function(...paramArr, body[0]);
            } else {
                return new Function(body[0]);
            }
        } else {
            return null;
        }
    }
}

function cloneOtherType(targe, type) {
    switch (type) {
        case numberTag:
        case stringTag:
        case boolTag:
        case symbolTag:
            return Object(targe.valueOf());
        case regexpTag:
            return cloneReg(targe);
        case funcTag:
            return cloneFunction(targe);
        default:
            return new targe.constructor(targe);
    }
}

function clone(target, map = new WeakMap()) {
    if (!isObject(target)) return target;    // 原始类型

    // 防止循环引用
    if (map.has(target))  return map.get(target);

    // 初始化
    const type = getType(target);
    if (!deepTag.includes(type)) {
        return cloneOtherType(target, type);
    } 

    let cloneTarget = new target.constructor();
    map.set(target, cloneTarget);

    if (type === setTag) {    // 克隆set
        target.forEach(value => {
            cloneTarget.add(clone(value, map));
        });
    }

    if (type === mapTag) {    // 克隆map
        target.forEach((value, key) => {
            cloneTarget.set(key, clone(value, map));
        });
    }

    if (type === arrayTag) { // 数组
        target.forEach(v => {
          cloneTarget.push(clone(v, map));
        });
      }

    if (type === objectTag) { // Object
      for (let key of Reflect.ownKeys(target)) {
        cloneTarget[key] = clone(target[key], map);
      }
    }
    return cloneTarget;
}

// 用例demo
const sym = Symbol('testB');
let a = {
  a: function (a, b) {
    console.log(a,b);
  },
  b: 'b',
  c: [1, 2, {a: 1}],
  
};
a[sym] = "symbol";
a.d = a;

let b = clone(a);
console.log(a.d === a, a);
console.log(b.d === b, b);

函数柯里化

柯里化是个十分实用的工具函数, 可以用于包裹一些业务逻辑, 以下是个人修改版.

function curry(func, len = func.length) {
  return function curried(...args) {
    if (args.length >= len) {
      return func.apply(this, args);
    } else {
      return function(...newArgs) {
        return curried.apply(this, args.concat(newArgs));
      }
    }
  };
}

Promise

function MyPromise(executor){
  let self = this
  self.value = undefined
  self.reason = undefined
  self.status = 'pending'
  self.onResolvedCallbacks = []
  self.onRejectedCallbacks = []
  function resolve(value){
    if(self.status === 'pending'){ //保证状态一旦变更,不能再次修改
      self.value = value
      self.status = 'resolved' // 成功状态
      self.onResolvedCallbacks.forEach(fn => {
        fn()
      })
    }
  }
  function reject(reason){
    if(self.status === 'pending'){
      self.reason = reason
      self.status = 'rejected' //失败状态
      self.onRejectedCallbacks.forEach(fn => {
        fn()
      })
    }
  }
  executor(resolve, reject) // 因为会立即执行这个执行器函数
}

MyPromise.prototype.then = function(onFulfilled, onRejected){
  let self = this
  return new MyPromise(function(resolve, reject){
    if(self.status === 'resolved'){
      onFulfilled(self.value)
    }
    if(self.status === 'rejected'){
      onRejected(self.reason)
    }
    if(self.status === 'pending'){
      self.onResolvedCallbacks.push(function(){
        onFulfilled(self.value)
      })
      self.onRejectedCallbacks.push(function(){
        onRejected(self.reason)
      })
    }
  }
}

判断url是图片的正则: const imgReg = /\.(png|jpe?g|gif|svg|bmp|raw|webp)(\?.*)?$/;

相关文章

  • JS杂项备忘录

    快速排序 函数组合 call, bind, apply 事件 DOM事件流:捕获阶段 → 目标阶段 → 冒泡阶段 ...

  • JS杂项

    1.JS对象的深克隆 早年在实习的时候,一位前辈做的,我觉得很神奇。 2.数组去重

  • 原生js杂项

    onpageshow 事件 onpageshow 事件在用户浏览网页时触发。onpageshow (支持的 HTM...

  • springmvc+spring+jdbc整合

    简单实例 实例2 杂项1 杂项2 杂项3 实例4

  • Shell脚本之杂项

    title: Shell脚本之杂项tags: shell编程, 杂项 记录一些学到的shell脚本里面的一些杂项(...

  • Linux驱动编程——misc设备驱动框架

    Linux驱动编程——misc设备驱动框架 主要概念: misc:杂项设备杂项设备是字符设备的一种,杂项设备可以自...

  • css 杂项

    css杂项

  • 杂项

    在php中self与$this的分别 在访问PHP类中的成员变量或方法时,如果被引用的变量或者方法被声明成cons...

  • 杂项

    最难熬的是有烦恼却不能跟任何人倾诉的时候, 也许那个时候正是思想上懵懂和成熟交替之际。 烟吸到肺里已经不是当初的感...

  • 杂项

    就算是太阳,也只能照到那些渴望不断生长的人。 关于单恋 大概就是,你的心情与我无关,我的心情却被你左右。 你理我了...

网友评论

      本文标题:JS杂项备忘录

      本文链接:https://www.haomeiwen.com/subject/rtspsqtx.html