1.css命名类时不要缩写,不要类似把class="container" => class="ctn"
2.不该多写的css一句不要多写 margin-left:auto; margin-right:auto;绝对优于margin:0 auto
3.构造函数的名字要首字母大写且名词词性 比如 new Object() , new Person()
4.普通函数要动词开头且开头小写 createUser
5.用递归/循环 seTimeout去代替setInterval
6.原生JS DOM 查询元素时只用querySelector与querySelectorAll,不要使用getElementsByXXX
7.原生JS获取属性用setAttribute与getAttribute就够了
8.node.dataset-xxx 类似这种 或者是node.class 这种低级错误不用犯
- 前者正确写法node.dataset.xxx JS会把-xxx误认为是减法
- 后者呢则是保留的关键字应改为 className 9.jQuery变量声明的基本尊重
let $div = $(...)
10.meta标签去复制淘宝的即可
11.保底值
let c=10
let b;
let a=b||c;
console.log(a)
12.如果有值则执行
如果值不是null undefined 0 '' false 即可执行
- 0可能有潜在风险
let content=''
if(content){
alert("执行");
}
12.1 当前者是falsy时就执行后者
- 短路逻辑
- 但只适用于后面仅有一句话的简单操作
null||console.log('123')
12.2 如果有就维持现状,如果没有就给个空数组
// 这有一个哈希表
let arr=[{n:1,content:'a'},{n:1,content:'b'},{n:1,content:'c'},{n:2,content:'d'},{n:3,content:'e'}]
// 对这个哈希表 重新分组
let obj={};
arr.forEach((item)=>{
const {n,content}=item
obj[n]=obj[n]||[]; // 如果有就维持现状,如果没有就给个空数组
obj[n].push(item);
})
console.log(obj)
13.避免过于冗长的if else嵌套
- 就好像英语不喜欢头重脚轻,喜欢提前把主要的抛在前面
- 那么这种做法也是可以借鉴的
function func(){
var result;
if( conditionA ) {
if( condintionB ) {
result = 'Success';
} else {
result = 'Error1';
}
} else {
result = 'Error2'
}
return result;
}
function func(){
if( !conditionA ) {
return 'Error2'
}
if( !condintionB ) {
return 'Error1'
}
return 'Success';
}
14.foreach避免滥用,可以函数式编程代替以增加语义性
- 遍历的时候也经常产生大量的嵌套,
- 如下代码所示,
- 我们先对数组元素做一次合法性校验,通过后再做一次新的操作,最后把操作结果追加到新数组里。
const func = (arr) => {
const res = []
arr.forEach( (e) => {
if( e !== 'Onion' ){
res.push(`${e} Run!`)
}
})
return res;
}
仔细观察这就是一个filter加map的过程。我们不妨试试函数式编程:
const func = (arr) => {
return arr
.filer( (e) => e !== 'Onion' )
.map( (e) => `${e} Run!` );
}
15.判断一个变量的合法性,用Array.includes
- 如果一个变量的值是以下10种情况之一,那么就...
const init(type) {
if( type === 'Seminar' || type === 'Interview' ) {
console.log('valid');
}
...
console.error('invalide');
}
如果合法的类型只有两种,代码其实也没啥问题。只是一般的业务很容易有后续的延展。今后将合法类型增加到10种的话,上述代码里将是一大长串的if判断。这种代码可读性极差,我们不如转换一下思想,把非法类型储到数组里,用Array.includes来帮你完成冗长的判断。之后每增加一种新的类型,只需在数组后追加新字符串就行了。
const init(type) {
const invalidArray = ['Seminar', 'Interview']
if( invalidArray.includes(type) ) {
console.log('valid');
}
...
}
16.使用object索引 如果变量a的值为value1则返回result1,a的值为value2则返回result2,
const dateFormat = (dateTime) => {
const format = this.$i18n.locale === 'en' ? 'mmm d, yyyy' : 'yyyy年m月d日';
return DateFormat(dateTime, format);
}
// 正确写法
const localeFormats = {
en: 'mmm d, yyyy',
zh: 'yyyy年m月d日',
ja: 'yyyy/m/d',
}
const format = localeFormats[this.$i18n.locale];
- 检查一个字符串A是以...开头的
let string="http://www.baidu.com"
if(string.indexOf('http://')===0){console.log('123')}
18.从一处拿值,拿完值再做判断,如果这个值是a则给对应结果,不然就不动这个a
const localpath=path==='/'?'/index.html':path;
19.获取一个字符串的后缀
let localpath='/index.html'
let index=localpath.lastIndexOf('.');
let filetype=localpath.substring(index);
const filetypes={
'.html':'text/html',
'.css':'text/css',
'.js':'text/javascript',
}
console.log(filetypes[filetype])
- 如果数组根本是空的,最后一项.id给他一个初始值
let arr=[{id:1},{id:2},{id:3}];
arr.splice(0) // 全部删光
let lastOneId=arr[arr.length-1].id; // 错误示范,这句用下面两句去替换
console.log(lastOneId) // 直接error 因为undefined.id哪里有啊?
把错误示范替换为以下,应该去判断item有无,而不是直接取id
let lastOne=arr[arr.length-1];
let lastOneId=lastOne?lastOne.id:1
- 获取一个数据的时候永远要考虑,如果拿不到怎么办,如果是空怎么处理
- 想知道id为0的对象在不在数组内,在的话就返回这个对象
- 对象取值永远用 []
let obj={"0.7809727906203332":{"user_id":1},name:'ryan',age:18}
let a="age";
// 成功案例
console.log(obj["0.7809727906203332"])
console.log(obj[0.7809727906203332])
console.log(obj["name"])
console.log(obj.name) // 虽然可以但不推荐,要记就记通解
console.log(obj[a])
// 失败案例
console.log(obj.0.7809727906203332)
console.log(obj."0.7809727906203332")
console.log(obj."name")
console.log(obj[name])
console.log(obj.a)
- 取子字符串用slice 或者substring 而不要用substr,后者过时了 会被淘汰
- 我觉得用slice更好,因为字符串数组都可以slice,slice和substring没什么区别
25 localStorage存数据的时候只能存字符串哈 不要存数字和布尔,取出来的时候要判断一下是否为空,给个保底值
26 行为样式分离: js不要去操纵css,不好的习惯,而是去使用addClass removeClass这类
27 表驱动编程的思想
就是利用哈希表去让代码变得简化
28 解构赋值不仅数组还可以对象 三个点可以叫展开运算符, 本质是浅克隆
let obj={name:'ryan'};
let obj1={...obj};
// 可以用于webpack.config.base.js这类基础配置文件给别的配置文件继承时使用
let obj={name:{name:'ryan'}}
let aaa={...obj}
aaa.name.name=1111
console.log(obj)
28.1 函数传参时的解构赋值
function fn({data}){
let obj={};
Object.assign(obj,data)
console.log(obj)
}
fn({data:{n:1}})
- 我给fn传一个对象,这个对象中套着一个对象
- fn接收到这个对象时把里面这个对象取出来放到一个新对象里面去 29 防御性书写代码
console&&console.error&&console.error('这里才执行呢')
30 箭头函数中需要注意的点
先上结论
函数中只有一句话 且为return xxx的时候才可以简写成 { xxx },但如果唯一的一句话不是return xxx的时候就不可以简写!
现在来分析一下代码有何区别,答案是无任何区别
function f1(){
console.log(1)
// f1中虽然没有return语句但是js会自动补上return undefined
}
function f2(){
return console.log(1) 、
// 这里依旧会执行console.log(1),并且console.log()这个函数返回值是undefined因此f2()依旧return undefined
}
- 综上所述,上述两者都是先执行console.log然后再往外return undefined
那么我们接着讨论箭头函数中关于return的问题
function fn(){
return 111
}
f1=()=>{ fn() } // 1
f1() // 语句1
f2=()=>fn() // 2
f2() // 语句2
- 请问语句1与语句2一样吗? 答案当然是 语句1是得到undefined 语句2是得到111
- 因为2处其实是f2=()=>{ return fn()} 的简化 31 判断如果值是这三个中的任意一个的话,则执行业务代码
let name='a';
if(['a','b','c'].indexOf(name)===0){
console.log('值为三个中的一个现在执行业务代码')
}
let name='a';
if(['a','b','c'].includes(name)){
console.log('值为三个中的一个现在执行业务代码')
}
let name='a';
if(name==='a'||name==='b'||name==='c' ){
console.log('值为三个中的一个现在执行业务代码')
}
32 如果n存在,则n等于n,不存在则n=1
let n=window.location.hash.substr(1)
n=n||1;
33 截取子字符串的api就用substring,不要去用substr
- substring包括头不包括尾,第二个参数可以理解为是长度
- 参数不要去写负数!
- 不会对原字符串修改,要复制新的一份
let str='123'
str.substring(0,str.length) === str
str.substring(0,str.length-1) === '12'
34 对象中的方法慎用箭头函数
// 错误示例
// 箭头函数没有this;
// 对象的花括号也不存在作用域,因为这里指的是 window.bbb === undefined
window.aaa={
bbb:100,
fn:()=>{
console.log(this.bbb)
}
}
// 正确示例
window.aaa={
bbb:100,
fn(){
console.log(this.bbb)
}
}
// 正确示例
window.aaa={
bbb:100,
fn:function(){
console.log(this.bbb)
}
}
35 声明对象时 调用自身属性的两种情况
let obj={name:'ryan',name1:obj.name}
// 这是错误的,因为这里面的代码在定义的时候就会被执行对吗,
// 这不是函数体内部,思考一下,我刚进入obj的时候还没走出obj就有人说obj.name哪里能拿到呢?
let obj={name:'ryan',name1(){ console.log(obj.name) }}
// 这是正确的,因为定义的时候并不会跑进函数体内部去执行代码
36 析构语法常用于函数参数是一个对象时
let obj={name:'ryan',id:'007'}
function fn(obj){
const {name,id}=obj;
console.log(name)
console.log(id)
// 简化了一下两句
// const name=obj.name;
// const id=obj.id
// 也简化了你到处使用obj.name, obj.id
}
fn(obj)
36.1 析构在Vue中也经常用到
const {recordList}=this;
const recordList=this.recordList;
36.2 析构甚至可以用于数组
const [date,time]='今天T七点'.split('T');
console.log(date);
console.log(time);
36.3 析构重命名
let obj={value:'111'}
let {value:valuebababa}=obj
console.log(valuebababa)
37 对象的字面量中是不能够写模板字符串的,这在Vue的class书写中会遇到
let obj={`aaa`:123} // error
37.5 如果对象的key中想要使用变量则请用[]语法,这是es6的内容
let aaa=123
let obj={[aaa]:123}
console.log(obj['123']) // 123
38 const 遇到复杂类型时只能保证地址不给修改,要配合Object.freeze
const 遇到复杂类型时只能保证地址不给修改,而透过地址修改值的诸如push仍然可以修改值
const a=[1,2,3]
a.push(4) // 成功
console.log(a) // [1,2,3,4]
const aaa=Object.freeze([1,2,3])
aaa.push(4) // 不可以
39 如何避免连续多次点按钮发请求?
let isLoading=false; // 外部定义一个变量
// 触发的函数体内部
if(isLoading){return} // 写在第一行 表示你每次点进来我都判断一下,如果正在加载我就直接出去了
isLoading=true; // 第二行赋值
// 接收到参数以后,重新置false
isLoading=false;
- 获取页面宽高
const width=document.documentElement.clientWidth;
if(width<500){
做一些手机上的事情
}
- 让带有滚动条的元素滚动到最右侧/ 滚动到最底部
element.scrollLeft/scrollTop = element.scrollWidth;
- 隐藏滚动条
::-webkit-scrollbar{
}
- map函数用于从一个都是对象的数组中分组
let arr = [{name:'张三',age:40},{name:'李四',age:38}];
let nameGroup = _.map(arr,_.property('name'));
let ageGroup = _.map(arr,_.property('age'));
console.log(nameGroup,ageGroup)
- sort函数如何比较日期字符串大小
- 不能相减比较,只能比较大小
var arr=['2020-01-01','2020-02-01','2020-01-07'];
let arr1=arr.sort((a,b)=>{
if(a>b){
return 1;
}else if(a===b){
return 0;
}else{
return -1;
}
})
console.log(arr1)
filter的正确使用姿势,通常配合match一同使用
let arr=['book','abc','look']
let result=arr.filter((item)=>{
return item.match(/oo/)
})
console.log(result)
- 如何理解
filter与map之间的差异
为什么过滤用的是
filter而不是map?map不是遍历嘛? 这是因为return的逻辑不同
let arr=['book','abc','look']
let result=arr.map((item)=>{
return item.match(/oo/)
})
console.log(result) // [Array(1), null, Array(1)]
为什么 map 配合 match 得到这么奇怪的结果?
filter函数中的return用于判断true/false,如果为true则放进新的数组,如果是falsy值则不放入数组,
'book'.match(/00/) // 返回一个数组 filter便认为true
'bo'.match(/00/) // 返回null,filter便认为false
map中的return用于将结果放进新数组中
'book'.match(/00/) // 返回一个数组 map就把这个数组结果放进新数组
'bo'.match(/00/) // 返回null,map就把这个null放进新数组
- 制作导航栏的逻辑
预先在 view 中搭好'首页','上一页','下一页'的按钮,然后循环显示一个放在中间的数组
1. data 中设置一个数组 `[1,2,3,4,5,'...']` // 其中 '...' 不可点选
2. click 时选中样式 .active
3. 点击 下标为4 的元素时逐步后移,点击 下标为0 的元素时逐步前移
4. 点击上一页,下一页时将,调用jquery操作dom点击当前选中按钮的前一个/后一个,
- hover-focus-active 伪类顺序
- link--visited--hover--focus--active 在线示例
- :hover与onmouseover onmouseout区别
- 前者纯css控制,无法操纵dom,后者可以操纵dom 在线示例
- console.time
console.time(1);
setTimeout(function(){
console.timeEnd(1);
},1670);