ES6高级技巧(五)

Set

由于Set结构没有键名,只有键值所有keys方法和values方法的行为完全一致

let a=new Set([1,2,3,4])
             //a.keys()    a.values() 或者直接用of遍历
for (let item of a) {
    console.log(item)
}
/*
* 1,2,3,4
* */

forEach()

let a = new Set([1, 2, 3, 4])
let b = [];
a.forEach(v=>b.push(v))
console.log(b)

数组的map和filter方法也可以间接用于Set

let set =new Set([1,2,3])
let set1=new Set([...set].map(v=>v*2))
console.log(set1)
//Set { 2, 4, 6 }
let set2=new Set([...set].filter(v=>v%2==0))
console.log(set2)
// Set { 2 }

使用Array.from()

let set = new Set([1, 2, 3, 4])
let set1 = Array.from(set, val => val * 2)
console.log(set1)
//[ 2, 4, 6, 8 ]

WeakSet

WeakSet是一种构造函数,可以使用new命令,创建WeakSet数据结构

weakSet可以接受一个数组或类似数组的对象
weakSet 的成员只能是对象,而不能是其他类型的值
add
has
delete
WeakSet没有size属性以及clear()属性,没有办法遍历他的成员
WeakSet的一个用处,是存储DOM节点,是弱引用

Map

size()
constructor
set()
get()
has()
delete()
clear()
遍历方法
keys()
values()
entries()
forEach()
Map本身没有map和filter方法,结合数组的方法,实现过滤
let map1 = new Map()
map1.set(1, 'a')
map1.set(2, 'b')
console.log([...map1])
//[ [ 1, 'a' ], [ 2, 'b' ] ]
let b = [...map1].filter(([key, value]) => key <2)
console.log(b)
//[ [ 1, 'a' ] ]
let c=[...map1].map(([key,value])=>key*2)
console.log(c)

WeakMap

WeakMap结构与Map结构基本类似,唯一的区别是他只接受对象作为键名,不接受其他类型的值作为键名

let myElement = document.getElementById('logo')
let myWeakmap = new WeakMap()
myWeakmap.set(myElement, { times: 0 })
myElement.addEventListener('click', function () {
  let login = myWeakmap.get(myElement)
  login.times++
})

Object.assign

console.log(Object.assign([1, 2, 3], [4, 5]))
//把数组视为属性民0,1,2的对象,所以后面的[4,5]覆盖了前面的1,2
//[4,5,4]

为对象添加方法

function SomeClass() {

}
Object.assign(SomeClass.prototype, {
  add(arg1, arg2) {
    return arg1 + arg2
  },
  multi(arg1, arg2) {
    return arg1 - arg2
  }
})
let some = new SomeClass()
console.log(some.add(1, 2))
console.log(some.multi(1, 2))

合并对象

let a=[{name:'zhangasn'},{age:12}]
console.log(Object.assign({}, ...a))
// { name: 'zhangasn', age: 12 }

Symbol

const sym = Symbol('foo');
console.log(sym.description)  //'foo'

作为属性名Symbol

let mySymbol = Symbol()
let a = {}
a[mySymbol] = 'hello';
console.log(a[mySymbol]) //hello

let b={[mySymbol]:'hello'}
console.log(b[mySymbol]) //hello

let c=Object.defineProperty({},mySymbol,{value:'hello'})
console.log(c[mySymbol])//hello

注意,Symbol值作为对象属性名时,不能用点运算符

const mySymbol = Symbol()
const a = {}
a.mySymbol = 'hello'
console.log(a['mySymbol']) //"hello"
a[mySymbol]//这个是访问不到的
const obj = {}
let a = Symbol('a')
let b = Symbol('b')
obj[a] = 'hello'
obj[b] = 'World'
let cArr = Reflect.ownKeys(obj)
for (let item of cArr) {
  console.log(obj[item])
  //hello
  // World
}

Symbol.for()

Symbol.for()Symbol() 都会生成新的Symbol,他们的区别是,前者会被登记在全局进行搜索,后者不会

let s1 = Symbol('foo')
let s2 = Symbol('foo')
console.log(s1 === s2)//false
let s3 = Symbol.for('foo')
let s4 = Symbol.for('foo')
console.log(s3 === s4)//true

Symbol.iterator

对象的Symbol.iterator属性,指向该对象的默认遍历器的方法

const a = {}
a[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3
};
console.log([...a])

判断非空isEmpty

const isEmpty=val=>val===null||!(Object.keys(val)||val).length

判断一个字符串是否有重复的字符

//采用桶排序的思想
const isData = str => {
  let flag = Array.from({ length: 128 }, v => 0)
  for (let i = 0; i < str.length; i++) {
    let c = str.charCodeAt(i)
    if (flag[c] > 0) {
      return false
    } else {
      flag[c]++
    }
  }
  return true
}
console.log(isData('abc'))

判断两个字符集是否相同

const equls = (s1, s2) => {
  const map = new Map();
  for (let i = 0; i < s1.length; i++) {
    if (map.get(s1[i]) == null) {
      map.set(s1[i], 1)
    }
  }
  for (let i = 0; i < s2.length; i++) {
    if (map.get(s2[i]) === null) {
      return false
    }
  }
  return true
}

判断是否是旋转词

const joint = (str, s1) => {
  let a = ''
  let b = [];
  for (let i = 0; i < str.length; i++) {
    if (i == 0) {
      a = str.slice(i)
    } else {
      a = str.slice(i) + str.slice(0, i)
    }
    b.push(a)
  }
  return b.indexOf(s1) > -1 ? true : false
}

String

String.prototype.charAt(index)     0<=index<=length-1   返回特定位置的字符

String.prototype.charCodeAt(index)                      返回给定的字符的Unicode值

String.prototype.concat()                               连接两个字符串文本,返回新的字符串

String.prototype.includes()       判断字符串是否包含                      

endsWith()  判断当前字符串是否是以另外一个给定的子字符串'结尾'  Boolean
startsWith()                                          '开头' Boolean

String.localeCompare()       'abcsbda'.split('').sort((a, b) => a.localeCompare(b))

String.prototype.padEnd()       两个参数,第一个数字符串的最大长度,第一个参数是添加的字符串,长度不能超过max.length

repeat()    重复的次数
replace()    替换
slice()  

比较

类型 运算规则
两个值类型进行比较 直接比较数据在序列中的大小
值类型与引用类型比较 将引用类型的数据转换为与值类型数据相同的数据
两个引用类型比较 无意义,总是返回false
console.log('b' > 'a')  //true

for--of的妙用

let arr = {
  name: 'zhangsan',
  age: 12,
  aa: 'cc'
}
for (let [key, value] of Object.entries(arr)) {
  console.log(key + '===' + value)
}

对象与数组互转

给每个订单的对账情况加上状态样式(successwarningdanger

// 状态码说明: 100->对账成功、101->对账中、102->审核中、103->对账失败、104->取消对账
// 规定有如下样式映射表: 
const style2StatusMap = {
  success: [100],
  warning: [101,102],
  danger: [103,104]
}
//结果
const status2styleMap = {
  100: 'success',
  101: 'warning',
  102: 'warning',
  103: 'danger',
  104: 'danger'
}

const status = obj =>
  Object.entries(obj)
    .reduce((acc, val, i, array) => {
      val[1].map(item => {
        acc[item] = array[i][0]
      })
      return acc
    }, {})

保镖模式

思考无效/边缘情况以及处理的情况

避免意外和不必要的代码

遵循自上而下的方法:

无效情况->小案例->预期案例

function transformData(rawData) {
  // 检查没有数据的情况
  if (!rawData) {
    return [];
  }
  // 具体检查的情况
  if (rawData.length == 1) {
    return [];
  }
  // 具体代码
  return rawData.map((item) => item);
}

不用switch

const contentTypes = {
  post: () => console.log("creating a post..."),
  video: () => console.log("creatinga  video..."),
  default: () => console.log('unrecognized content type')
};

const createType =(item)=> contentTypes[item] || contentTypes['default'];
createType('post')()

CSS篇

width:auto 和height:auto

width,height的默认值都是auto

对于块级元素,width:auto 自动撑满一行

对于内联元素,width:auto 则呈现出包裹性,既由子元素的宽度决定

无论内联元素还是会计元素,height:auto 都是呈现包裹性,即高度由子级元素撑开。但是父元素设置height: auto会导致子元素height: 100%百分比失效。

css的属性非常有意思,正常流下,如果块级元素的width是个固定值,marginauto,则margin会撑满剩下的空间;如果margin是固定值,widthauto,则width会撑满剩下的空间。这就是流体布局的根本所在。

margin:auto 水平垂直居中

<div class="g-container">
    <div class="g-box"></div>
</div>

.g-container {
    display: flex;
}

.g-box {
    margin: auto;
}

上面的 display: flex 替换成 display: inline-flex | grid | inline-grid 也是可以的。

实现justify-content: space-between

 <div class="ddd">
      <div class="ccc"></div>
      <div class="ccc"></div>
 </div>
<style>
.ddd{
  width: 900px;
  height: 500px;
  border:1px solid #2c3e50;
  display:flex;
  /*justify-content: space-between;*/
  .ccc{
    width: 100px;
    height: 100px;
    background-color: darkblue;
    margin:0 auto;
  }
  .ccc:first-child{
    margin-right: 0;
  }
  .ccc:last-child{
    margin-left:0;
  }
}
</style>

实现space-around

.ddd{
  width: 900px;
  height: 500px;
  border:1px solid #2c3e50;
  display:flex;
  /*justify-content: space-around;*/
  .ccc{
    width: 100px;
    height: 100px;
    background-color: darkblue;
    margin:0 auto;
  }
}

单个元素右浮动

  <div class="ddd">
      <div class="ccc"></div>
      <div class="ccc"></div>
      <div class="ccc"></div>
    </div>
.ddd{
  width: 900px;
  height: 500px;
  border:1px solid #2c3e50;
  display:flex;
  .ccc{
    width: 100px;
    height: 100px;
    background-color: darkblue;
  }
  .ccc:last-child{
    margin-left:auto;
  }
}

此时auto 的计算值就是水平方向上容器排列所有li之后的剩余空间

两个右浮动

  <div class="ddd">
      <div class="ccc"></div>
      <div class="ccc"></div>
      <div class="ccc aaa"></div>
   <div class="ccc"></div>
    </div>

.ddd{
  width: 900px;
  height: 500px;
  border:1px solid #2c3e50;
  display:flex;
  .ccc{
    width: 100px;
    height: 100px;
    background-color: darkblue;
  }
  .aaa{
    margin-left:auto;
  }
}

垂直方向居中

父  {
       display: flex;
    flex-direction:column; 
}

子{
     margin:auto 0;
}

例如

<div class="g-container">
      <p>这是第一行文案</p>
      <p>这是第二行文案</p>
      <p class="aaa">1、剩余多行文案需要垂直居中剩余空间</p>
      <p class="aaa">2、剩余多行文案需要垂直居中剩余空间</p>
      <p>这是最后一行文案</p>
 </div>
.g-container {
    width: 600px;
    height: 600px;
    border:2px solid #2c3e50;
    display: flex;
    flex-direction:column;
  }

  .aaa{
    margin:auto 0;
  }

css 权重

权重 选择器
10000 !important(!important并不是选择器,但是权重却是最高的)
1000 内联样式:style=""
100 ID选择器:#idName{...}
10 类、伪类、属性选择器:.className{...} / :hover{...} / [type="text"] ={...}
1 标签、伪元素选择器:div{...} / :after{...}
0 通用选择器(*)、子选择器(>)、相邻选择器(+)、同胞选择器(~)
body#god div.dad span.son {width: 200px;}
body#god span#test {width: 250px;}

(body+div+span=3) + (#god+.dad+.son=120) = 123
(body+span=2) + (#god+#test=200) = 202

content

css中的content属性主要用伪元素:after,:before中,其他一般不用

padding

注意点

line-height属性是不作用于padding

background-clip 设置元素的背景,是否延伸到边框下面

//三道杠
 .icon1{
   box-sizing:border-box;
   width: 20px;
   height: 30px;
   border-top:2px solid #2c3e50;
   border-bottom:2px solid #2c3e50;
   padding:2px 0;
   background-color: #2c3e50;
   background-clip:content-box;//内容裁剪
 }
//圆环
.icon1{
   box-sizing:border-box;
   width: 20px;
   height: 20px;
   border:2px solid #2c3e50;
   padding:4px;
   border-radius:50%;
   background-color: #2c3e50;
   background-clip:content-box;//内容裁剪
 }

margin

  1. 作为外边距,margin属性并不会参与盒子宽度的计算,但是通过设置margin为负值,会改变水平方向的尺寸
  <div class="aaa">
            <div class="bbb"></div>
  </div>
   .aaa {
        width: 500px;
        height: 500px;
        background-color: lightblue;
        margin-left: 500px;
    }
    .bbb {
        /*width: 100px;别设置宽度*/
        height: 200px;
        background-color: magenta;
        margin-left:-200px;
    }

如果元素设置宽度,或者元素设置了float:left /position:absolute 这样的属性改变了流体布局,那么margin为负就不能改变元素的宽度

  1. 块级元素垂直方向会发生margin合并
  • 相邻兄弟之间margin 合并
  • 父元素margin-top和子元素margin-top ,父元素margin-bottom 和子元素margin-bottom
  • 空块级元素自身的margin-topmargin-bottom合并

阻止margin合并

  • 把元素放到bfc中(bfc:格式化上下文(浮动,定位,display:inline-block))
  • 设置borderpadding 阻隔margin
  • 给父亲设置内联元素(如文字)阻隔
  • 可以给父元素设置overflow:hidden是利用bfc的特性阻止子元素的margin 和父元素合并,换成其他bfc特性,或者设置1px的border/padding都可以达到效果

line-heightvertical-align

  • line-height定义的就是两基线之间的距离
  • vertical-align 的默认值就是基线,基线的定义就是字母x的下边缘
  • vertical-align:middle 就是中线对齐

vertical-align属性起作用的前提必须是作用在内联元素上 ,如果给元素设置float:left 或者position:absolute ,则其vertical-align 属性不能生效,因为这时元素的display计算值为block

说实话,我用vertical-align

calc(计算属性)

margin-left:calc(50%-45px);

posted @ 2019-07-29 12:02  猫神甜辣酱  阅读(827)  评论(0编辑  收藏  举报