/**
* 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.
*
*/