代码笔记

/**
 * 1. ??
 */
const a = null
const a1 = a ?? 1
console.log(a1) // 1

/**
 * 2. ?.
 */
const obj = {
  a: {
    b: 1
  }
}
console.log(obj?.a?.b) // 1

/**
 * 3. reduce 可找max min
 */
const arr = [1, 3, 4, 5, 2, 31]
arr.reduce((a, b) => a > b ? a : b) // max
arr.reduce((a, b) => a < b ? a : b) // min
arr.reduce((a, b) => a + b) // sum

/**
 * 4. String.prototype.localeCompare()
 *
 * a.localeCompare(b)
 * a < b ---->  -1
 */
const objectArr = [{ first_name: 'Lazslo', last_name: 'Jamf' }, { first_name: 'Pig', last_name: 'Bodine' }, { first_name: 'Pirate', last_name: 'Prentice' }]
objectArr.sort((a, b) =>
  a?.last_name?.localeCompare(b.last_name)
)

/**
 * 4. Array.prototype.filter()
 *
 * 参数为Boolean || Number时可过滤 0,undefined,null,false,"",''
 */
const arr1 = [1, 2, 3, null, undefined, '', false, true]
arr1.filter(Boolean) // [1,2,3,true]

/**
 * 5. Object.entries()
 *
 * 对象转为数组
 */
const obj1 = {
  t1: {
    name: 1
  }
}
Object.entries(obj1) // [t1, [name, 1]]

/**
 * 6. 判断数据类型
 */
function typeOf (obj) {
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
}
typeOf({}) // object
typeOf([]) // array
typeOf(new Date()) // date

/**
 * 7. 寄生式组合继承
 */

function Animal (name) {
  this.name = name
  this.colors = ['black', 'white']
}
Animal.prototype.getName = function () {
  return this.name
}
function Dog (name, age) {
  Animal.call(this, name)
  this.age = age
}

// 封装
function object (o) {
  function F () {}
  F.prototype = o
  return new F()
}
function inheritPrototype (child, parent) {
  const prototype = object(parent.prototype)
  prototype.constructor = child
  child.prototype = prototype
}
inheritPrototype(Dog, Animal)

/**
 * 8. concat & ... 的使用  实现数组扁平化
 * concat  ...  会进行解数组层级
 */
function flatten (arr) {
  while (arr.some(item => Array.isArray(item))) {
    arr = [].concat(...arr)
  }
  return arr
}
flatten([[1, 2, [3, [4]]]]) // [1, 2, 3, 4]

/**
 * 9. 浅拷贝   (巧妙运用  hasOwnProperty 来对数组或对象进行操作 判断当前是否有某元素 )
 */
function shallowCopy (obj) {
  if (typeof obj !== 'object') return

  const newObj = obj instanceof Array ? [] : {}
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key]
    }
  }
  return newObj
}
shallowCopy()

/**
 * 10. 深拷贝
 */

const isObject = (target) => (typeof target === 'object' || typeof target === 'function') && target !== null

function deepClone (target, map = new WeakMap()) {
  if (map.get(target)) {
    return target
  }
  // 获取当前值的构造函数:获取它的类型
  const constructor = target.constructor
  // 检测当前对象target是否与正则、日期格式对象匹配
  if (/^(RegExp|Date)$/i.test(constructor.name)) {
    // 创建一个新的特殊对象(正则类/日期类)的实例
    return new constructor(target)
  }
  if (isObject(target)) {
    map.set(target, true) // 为循环引用的对象做标记
    const cloneTarget = Array.isArray(target) ? [] : {}
    for (const prop in target) {
      if (target.hasOwnProperty(prop)) {
        cloneTarget[prop] = deepClone(target[prop], map)
      }
    }
    return cloneTarget
  } else {
    return target
  }
}

deepClone()

/**
 * 11 .事件总线
 */
class EventEmitter {
  constructor () {
    this.cache = {}
  }

  on (name, fn) {
    if (this.cache[name]) {
      this.cache[name].push(fn)
    } else {
      this.cache[name] = [fn]
    }
  }

  off (name, fn) {
    const tasks = this.cache[name]
    if (tasks) {
      const index = tasks.findIndex(f => f === fn || f.callback === fn)
      if (index >= 0) {
        tasks.splice(index, 1)
      }
    }
  }

  emit (name, once = false, ...args) {
    if (this.cache[name]) {
      // 创建副本,如果回调函数内继续注册相同事件,会造成死循环
      const tasks = this.cache[name].slice()
      for (const fn of tasks) {
        fn(...args)
      }
      if (once) {
        delete this.cache[name]
      }
    }
  }
}

// 测试
const eventBus = new EventEmitter()
const fn1 = function (name, age) {
  console.log(`${name} ${age}`)
}
const fn2 = function (name, age) {
  console.log(`hello, ${name} ${age}`)
}
eventBus.on('aaa', fn1)
eventBus.on('aaa', fn2)
eventBus.emit('aaa', false, '布兰', 12)
// '布兰 12'
// 'hello, 布兰 12'

/**
 * 12. 模板字符串
 */
function render (template, data) {
  const reg = /\{\{(\w+)\}\}/ // 模板字符串正则
  if (reg.test(template)) { // 判断模板里是否有模板字符串
    const name = reg.exec(template)[1] // 查找当前模板里第一个模板字符串的字段
    template = template.replace(reg, data[name]) // 将第一个模板字符串渲染
    return render(template, data) // 递归的渲染并返回渲染后的结构
  }
  return template // 如果模板没有模板字符串直接返回
}
const template = '我是{{name}},年龄{{age}},性别{{sex}}'
const person = {
  name: '布兰',
  age: 12
}
render(template, person) // 我是布兰,年龄12,性别undefined

/**
 * 13. 图片懒加载
 */
let imgList = [...document.querySelectorAll('img')]
const length = imgList.length

// 需要加上自执行
const imgLazyLoad = (function () {
  let count = 0

  return function () {
    const deleteIndexList = []
    imgList.forEach((img, index) => {
      const rect = img.getBoundingClientRect()
      if (rect.top < window.innerHeight) {
        img.src = img.dataset.src
        deleteIndexList.push(index)
        count++
        if (count === length) {
          document.removeEventListener('scroll', imgLazyLoad)
        }
      }
    })
    imgList = imgList.filter((img, index) => !deleteIndexList.includes(index))
  }
})()

// 这里最好加上防抖处理
document.addEventListener('scroll', imgLazyLoad)

/**
 * 14. 将 a.b.c 转换为 层级对象 reduce可以传两个参数  一个是fn  一个是最后一个的返回值
 */
const str = 'a.b.c'
str.split('.').reverse().reduce((a, b) => ({ [b]: a }), {})

// {a:b{c:{}}}

/**
 * 15. 减少重排
 *  1) 可以使用style.cssText += 'border: 1px;'
 *  2) 添加className的形式
 *  3)先批量处理设置display: none进行插入dom,后再display: block;
 */

// 1) style.cssText
const el = document.querySelector('test')
el.style.cssText += 'border-left: 10px; border-right: 1px;'

// 2) className
const el1 = document.getElementById('test')
el1.className += ' active'

/**
 * 16. dom操作
 *  1) li.className = ''   // 添加class
 *  2) li.id = ''          // 添加id
 *  3) li.textContent = '' // 添加innerHTML
 */

/**
 * 17. 克隆节点
 *  1) dom.cloneNode(true)
 */

/**
 * Lodash
 *
 * 1. _.merge(target, value)   合并层级对象(推荐使用)
 * 2. _.assign(obj1, obj2)     合并对象
 * 3. _.omit(obj, ['a', 'b'])  移除掉对象中属性为a b的
 * 4. _.pick(obj, ['a', 'b'])  选择obj中属性为a b的组成新的对象
 * 5. _.attempt(JSON.parse.bind(null, str)) 解决JSON.parse解析非json时的报错
 *  ① 也可通过try catch的方式进行判断返回
 *  eg: const parse = (str) => {
 *        try {
 *          return JSON.parse(str)
 *        }
 *        catch{
*           return str
*         }
 *      }
 *
 *
 */

/**
 * Vue
 * 1. @hook 定义在组件上用于处理生命周期
 *  @hook:mounted="fn"     @hook:updated="fn"  @hook:beforeUpdated="fn"
 *
 * 2. v-bind:$props  如果父组件传递很多的原生属性,那么我们在子组件中直接可以
 *
 */

/**
 * sass
  1. mixin的使用

    @mixin left($value: 10px) {
      float: left;
      margin-left: $value;
    }
      使用的时候,根据需要加入参数
    div {
      @include left(20px)
    }

  2. @import 插入外部文件

    @import "path/input.scss";

  3. @if  @else if @else 条件语句   (表达式返回值不是 false 或者 null 时,条件成立,输出 {} 内的代码)

    p {
      @if 1 + 1 == 2 { border: 1px solid; }
      @if 5 < 3 { border: 2px dotted; }
      @if null  { border: 3px double; }
    }

  4. @for 循环语句

    @for $i from 1 through 3 {
      .item-#{$i} { width: 2em * $i; }
    }

      =============
    ||             ||
    ||   转换后为   ||
    ||             ||
      =============

    .item-1 {
      width: 2em;
    }
    .item-2 {
      width: 4em;
    }
    .item-3 {
      width: 6em;
    }

  5. @while 循环语句

    eg:
      $i: 5;
      @while $i > 0 {
        .item-#{$i} {width: 2em * $i;}
        $i: $i - 2;
      }

  6. #{$test} 字符串变量用于在字符串中的定义  (类似于 => 模板字符串的使用)

  7. @function  @return  自定义函数的使用

    eg:
      @function double($n) {
        @return $n * 2;
      }

      #sidebar {
        width: double(5px);
      }

    eg1:
      $grid-width: 40px;
      $gutter-width: 10px;
      $n: 10;

      @function grid-width($n) {
        @return $n * $grid-width + ($n - 1) * $gutter-width;
      }

      #sidebar {
        width: grid-width(5);
      }

      #sidebar {
        width: grid-width($n: 5);
      }

  8.
 *
 */

 

posted @ 2022-10-28 14:32  YuyuFishSmile  阅读(28)  评论(0)    收藏  举报