Tips:
1、当需要给类型相同的元素循环绑定函数时,可以用给元素添加自定义标签等方法标记,在触发事件函数时,获取标记,传递给同一个事件函数,而不需要创建多个同类函数;已经生成的元素跟它之前所在的数组就没有关系了,不能反推出在之前数组所在的位置
2、拖拽排序的时候,设置“目标位置 != 当前”,可以使程序只执行一次;并且要注意有没有接触到外边框,设置条件在外边框不触发;排序逻辑:因为使用的前插入方法,所以小的插在大的后一个的前面,大的插在小的前面;排序判断条件当前索引大小和目标索引大小做比较;计算索引逻辑:不断循环用前一个节点赋值(‘=’),直到前一个节点为空,累计计算的自定义变量值就是节点的索引值
3、对象.自定义属性 = xxx相当于将xxx赋值给对象下新创建的属性
4、为了避免残留值,应当在“即将”调用和请求的地方清空再赋值。
5、滑块必须用clientX/Y计算鼠标到浏览器边框的距离,因为只有键鼠事件对象是动态值(随鼠标动态改变),而offsetLeft等都是元素对象的属性,是静态值;还有mousedown事件包裹mouseover最好不用点击的对象作为调用者,最好用window,因为鼠标滑动过快,超出点击的对象就会出现问题
6、“e.target”不会随着冒泡移动,点的是哪个元素,指向的就是哪个,即使父元素冒泡执行方法,target指向的也是点的元素,所以要用“currentTarget”可以获取绑定事件的对象,而不是点到的对象
7、三元运算的选择结果不止是字符串,还可以是表达式,比如另一个三元运算
8、“mouseenter”和“mouseleave”可以替代css“hover选择器”,“e.target”有scr属性可以更改图片地址,准确的说“e.target”包含目标的所有属性
9、表达式和语句的区别:“表达式”由运算符构成,并“运算”产生一个“结果”;而“语句”包括“声明、赋值、条件判断等”,只是一句命令或者句子。像JS和vue中需要填入“表达式”的地方,就不能用“语句”,需要注意区分,而表达式一旦加上“;”,就不再是“表达式”,而是表达式“语句”,从而不被识别报错,但是加“逗号,”是可以的
10、想要获得随机数,JS原生方法中只有“random()”,但是可以借助“Math.floor(Math.random() * num)”,用“[0~1)”的随机数乘“总数”,再向下取整,即可获得“[0~(总数-1))”的随机数了
11、想要折叠注释掉的代码,使用“//#region 代码块 //#endregion”,就可以把中间的内容全部折叠
12、实例化对象就是构造函数的调用者
13、对象中的函数可以用“名称+()”的形式,关键词function可以删掉
14、对象里的“key”都是“字符串”,所以当格式错误时,写成字符串形式用引号包裹
15、for循环是取不到数组外层定义的单独变量的
16、想要取小数点“后几位”,就“先取整再整除”——取几位就乘以10的指数,取整后再除以10的指数;另外js原生方法提供的都是向下取整,想要向上取整,加个0.5就可以了
17、对象才可以赋值修改原值,变量赋值修改原值不变;但是!对象复制后,置空再修改原值,不会影响复制的对象
18、Number没有“length”属性!
19、`阻止冒泡`只能阻止`同名的事件!`,比如@click.stop,只有父级同样是@click事件才能阻止
20、`冒泡事件的妙用!`——外层包裹mousedown(不要用click,因为鼠标抬起也会触发一次,其次`onmousedown`和`onmouseup`是一对,onmousedown事件本身并不好用,会在自动获取焦点等情况触发奇怪的问题)显示和隐藏功能,内层则是点击发送指令事件(用同样的关键字`mousedown`),就可以触发指令后隐藏选项框,而不需要遮罩
21、对象取用属性不只用点,还可以用·[ '属性名' ]·,当取用的·属性名只有后缀不同时·,可以使用·[ `前缀${动态后缀}` ]·
22、折叠注释·//#region ...代码块... //#endregion·
23、移除事件监听时,传入两个参数,第一个是想解绑的事件名,第二个是指向同一处地址的方法回调函数
24、不同层级的js文件中的函数作用域以引入js的html文件为根目录
自定义属性必须以data-开头,取值通过dataset[' ']获取(注意:data-my-name在取值时要写成myName)
小技巧:把<section>默认设为隐藏,每一个<section>绑定一个唯一的ID,把导航栏自定义属性值设置为<section>ID,再通过dataset获取,此时用判断语句判断点击的是否是对应导航栏,就将其样式设为显示
BUG问题检查:对象名用错会导致“xxx undefined”此类的没声明定义的错误;
当函数只用一次,声明后立即调用的情况下使用
(function ( ) {
statement
}) ( );//因为函数在这只是定义,还未调用,再加一个括号就是执行
函数加()表示立即执行,不加()表示触发某个事件再执行
ES6新增let和const。
var是全局变量,即使是在区块内声明也是作用全局
typeof返回数据类型;NaN的返回值是number,NaN是个特殊数字
null是空对象,返回的也是object
事件监听器:window.addEventListener('load', init, false);
function init(){ }
在绑定事件方法时:循环变量是传递不进函数的,而是会把参数当作事件触发的对象
防抖:使用“underscore”插件,使用时在“created”函数中用变量承接“_.debounce(执行函数,防抖时间)”函数,再在watch等需要使用的地方调用这个变量
Tips:
1、想要给防抖执行的方法中传入参数,可以曲线救国,将参数传入防抖函数,再在防抖函数中传给里面的方法
核心在于“闭包”,用函数包裹函数的形式可以形成闭包,就能形成作用域链,即使重新调用生成了另一个计时器,也能通过闭包的作用域链找到之前函数的变量(定时器),并清除。
思路:频繁调用的场景下,每次都设一个定时器,当小于定时再次调用时,会根据作用域链找到之前的定时任务,并清除同时再设一个新的定时任务,从而达到刷新计时的效果,当大于定时再调用,之前的定时任务已经执行完毕,变量重新回归null
节流:每隔一段时间执行一次
思路:利用闭包记录下每次调用时的时间,并计算当前时间和上一次时间的差值大于固定值时就执行,否则跳过,并继续叠加时间,直到差值大于固定时间
上面这个实现思路有个问题,使用的Date记录的是系统时间,即上一次停止调用时开始累计,当时隔很久再次调用时会立即触发而不是重新计算从滑动开始到结束的时间段,所以使用标识符改进
对象内的方法是箭头函数,则箭头函数内的this指向对象(父级)的调用者window;使用var _this = this绑定可以解决;
this是往外层寻找最近的`{}`,就是它的父级,它的父级被谁调用就指向谁(所以说this是动态的,在被调用的时候才确定指向)
箭头函数和普通函数的this区别如下:
普通函数:调用时被决定
谁调用我,我的this就指向谁;
js中this是根据函数的执行环境动态绑定的:全局函数中this指向的是window;当函数作为某个函数的方法被调用时,this就等于那个对象
匿名函数:谁调用指向谁。而多数情况下,是由`windows方法中调用`,因此this指向window;此处解释一下为什么是window,因为不同函数方法或者全局定义的匿名函数,是由JS引擎各个模块分别管理,从一开始就已经定义好了this指向
箭头函数:定义时被决定(因为没名字,所以不能像普通函数那样由对象调用,只能在定义处调用)
箭头函数的this是父级(作用域链的上一层)的this,没有则指向window;
调用者只能是对象和window,所以父级就是找上一级的对象,{}也是对象
自执行的函数就是全局函数,this指向window;只有通过object或者say函数调用;
函数声明式写法function foo(){/*...*/},会造成函数提升,不论在何处声明都可以调用,但只有在调用的时候才启用
函数表达式写法var foo=function(){/*...*/},不会造成函数提升,所以必须先声明再调用;因为在声明foo变量的时候,会连带执行后面的function,所以表达式写法会立即执行。
函数提升:在预编译阶段将函数声明提升到对应作用域最顶端
自执行函数作用是创建独立作用域,外面访问不到,避免变量污染
不管函数,对象里面如何定义,只有在它执行的时候,谁直接调用,this就指向谁;
调用执行函数时,“.”前面是什么,this就是什么。前面没有对象,就是window了。
回调函数不在作用域内,因为回调函数只是所声明函数的实例,本体还在外面,所以不在作用域内,得通过参数传递才能使用
JS原生方法:
sort(function(a,b){a-b或b-a})数组按照function规则排序,默认返回两个值,根据计算方式返回-∞~+∞的值,根据这个值对数组元素排序,改变原数组;
Array方法:
push(‘ ’) 数组末尾添加元素,并返回新的数组
pop( )删除数组最后一个元素,并返回被删的元素
unshift(‘ ’) 数组头部添加元素
shift()数组头部删除第一个元素,无参数
splice(起始位置,删除个数,一个或多个元素)在指定位置添加元素,并返回被删元素组成的数组;注:“删除个数”不写,默认是删除起始位置之后的所有元素、如果“删除个数”写0,一个都不删除,插入的元素在“起始位置前”
join:将数组合并为一个字符串返回
reverse:反转数组中元素顺序,会改变原数组
split和join都不会改变原数组,但是reverse会改变原数组
“some((当前元素的值) => { return 条件 } )”:检查数组中是否有某元素,返回的是boolean值
“filter( (当前元素的值) => { return 条件} )”过滤器,返回指定条件的元素组成的数组,不会改变原数组;“当前值”是Arry中每一个元素,因为filter其实执行了一次遍历,将Arry中每一个元素拿出来跟return中的判断条件进行比对,再将符合条件的元素合成一个新数组
include:检测数组中是否包含指定内容
forEach( (当前值,索引)=>{ } ):foreach中回调的函数是数组中每一个元素都调用一次
`reduce( (前一次返回值,当前数组元素内容)=>{ return 统计 },初始值 )`:
“for(let i of array)”:遍历数组
“indexOf('检索值','起始位置')”:检索数组中是否有指定元素。只检索元素中部分内容是不行的;元素类型不对也是不行的
string方法:
“indexOf('检索值','起始位置')”检索字符串中是否有指定内容,有则返回位置索引,没有则返回-1;同时还必须注意,检索“空字符串 ' ' ”时,返回的值是“0”,因为所有字符串在开头都拥有空字符串(也可以用于数组)
“match(正则)”:根据正则查找并返回匹配的内容,以数组形式返回
“Object.keys(数组)”:返回对象键组成的数组
object方法:
“Object.keys(对象)”:返回对象键组成的数组
“Object.values(对象)(es8)”:返回对象值组成的数组
"Object.entries()":通常对象是不可直接遍历的,而通过`entres`可以返回一个·键值对·组成的数组(二维数组,第一层是有多少个键值对,第二层是键和值组成的数组),从而可以在es6中的新for循环·for(let i of 可迭代变量)·中使用,使用方式·for(let [key,value] of Object.entres())·,·[key,value]·是es6新提出的·解构赋值·
Tips:·Array·也可以使用,只不过是以数组索引作为·key·
"Object.assign(目标对象,源头对象)(es6)":用于对象合并,合并同类赋值,不同类的作为新增,返回值是·新的目标对象·。但也可以用·扩展运算符·更简洁
Tips:在vue中,提前准备好的属性在合并后依然具有响应性
“for(let i in object)”:遍历对象
操作符(等同与或符):delete——“delete obj.property”删除对象上的指定属性,有返回值,返回删除成功与否
window方法(window方法可以省略`window`关键字,直接写后面的方法):
弹窗:警告窗alert('xxx');确认框confirm('显示内容'),返回布尔值;提示框prompt('提示内容','预设内容'),返回的是一个字符串
history.pushState/replaceState(state,title,url)可以在不跳转页面的情况下改写当前页面的url
跳转页面:window.location.href = "地址?键值对",跳转页面后使用`location.search`获取到`?`之后的内容,对获取的内容进行字符串分割,创建对象obj = { },使用obj['key'] = '值',将分割好的键值对装入对象
sessionStroage本地存储:使用sessionStroage.自定义变量名 = 值,就可以将值存入自定义变量名,取用的时候直接用sessionStroage.自定义变量名就可以获取值;删除的时候使用sessionStroage.removeItem("自定义变量名")
document方法:
cookie:
设置cookie:document.cookie = "user=hou jie";
默认情况下浏览器关闭就清除cookie,添加保存时间: document.cookie = "user=hou jie; expires=Thu, 18 Dec 2043 12:00:00 GMT(此处时间是new Date())",通过new Date()中的setDate()可以设置当月中的某一天,用getDate()获取当天日期;
删除cookie的原理:将expires 参数设置为当前时间或者前几天即可;
同名的cookie会被覆盖,新加的cookie不会覆盖会加到string尾部;
cookie.match时`=`后面的[^;]+必须用括号括起来才会返回等号后面的值
session、cookie、token三者区别:
cookie是载体,不管是session还是token都是通过cookie传递;浏览器访问页面是会自动带上cookie,因为在第一次http请求时,服务器会返回一个“set-cookie”,告诉浏览器要保存下来,并且访问时携带“cookie”;根据不同网站保存不同的cookie
session由服务器端生成,存储在服务器端,访问时是通过把用户名密码发送至客户端进行验证,通过后服务器生成sessionID并设置结束时间,再将sessionID通过cookie发送至浏览器,并将结束时间设置为cookie有效期
token由服务器端生成,通过cookie发送到客户端,由客户端保存,可以放在cookie或者storage;
session的缺点就是如果服务器崩溃,所有用户都得重新登陆,因此,就有人想出了不用存储在服务器,而是每次访问都进行验证,通过服务器加密算法生成token发送给客户端进行保存,减少了服务器压力,用户再次访问时,发送token到服务器,服务器再通过加密算法和密匙计算一次token并进行对比,就可以知道是否是之前登陆过的用户
jQuery的$("类名/标签/Id").eq(N-1)方法返回被选元素的指定索引号的元素
object.className是覆盖class属性;object.classList 是添加属性或者删除已有属性
getElements打头的元素获取方法返回的是集合,就算只有一个元素也是集合的形式,所以没有appendChild方法
drag事件中,想要drop必须阻止dragover的默认操作
getBoundingClientRect()方法可以获取目标大小及相对于窗口的位置
而transform是相对于自身当前位置
切换按键一类添加样式时:在异步执行里设置当前点击样式,然后在异步(.then)外执行清除当前点的样式
监听事件时,只有固定格式的onclick=function(e){}或者click((e) => {})及最外层function可以获取到event
js原生事件处理函数事件名必须叫“event”
onclick = function(e)和addEventListener可以用其他标识表示event,但不能不传参;并且只能传入event参数,如果要传入其他参数,需要进行封装
总结:在HTML事件处理程序中可以直接传入多个参数,并且可以不传入event直接传参,非常看重event关键词,可以直接使用;在"οnclick=function"以及addEventListener中不再看重event关键词,可以传任意标识,但只能传event。简单来说就是“html页面”要写就写完整“event”,“js页面”可以用任意标识符表示event
addEventListener和on事件的区别是:对同一个DOM,on事件唯一,但是事件监听器可以添加多个,并先后执行,不会后一个覆盖前一个
字符串和数字累加:因为任何东西都可以转成字符串,所以js在自动判断时,会把数字转换成字符串
和服务器双向传递数据可以用SSE(Server-Sent Event):
创建SSE对象 var source =new EventSource(url);
通信刚建立触发的事件 source.onopen =function (event)
服务器发来的数据 source.onmessage
通信错误时回调方法 source.onerror
结束通信 source.close();
通信传递文件流触发事件 source.addEventListener
日期格式化或者数字替换:padStart(保持的长度,'用什么来填充')和padEnd(保持的长度,'用什么来填充')
对象有两种取值方式:obj.key 和 obj["key"],但是如果key是一个变量(传进来的参数),就只能用obj[key](注意少了引号)
Math对象方法:
“Math.floor”:向下取整(floor意为地板)
“Math.ceil”:向上取整(ceil意为天花板)
“Math.round”:四舍五入。等同于Math.floor(x+0.5),因为能四舍五入进一位的数加上0.5一定可以进一位
“Math.pow(底数,指数)”:求幂运算
console.log(i++)表示先输出再自增
有回调函数的就是闭包;
要理解闭包,关键就是理解作用域链
任务队列会保存下来作用域链中的原始值,但不进行计算
for循环是在下一次循环执行前再自增
offset返回的是绝对值,哪怕设置的是百分比,返回的也是px;offsetHeight是自身
Tips:
1、想横向滚动,可以用“@wheel”,此事件在鼠标滚轮滚动时触发,然后手动设置,事件触发一次横向滚动距离
2、wheelDelta为正则是滚轮向上,为负则向下
3、※offset偏移量是依据上一级定位元素(position:relative等)确定的
4、※·offsetParent·和·parentNode·的区别:
·offsetParent·
查找路径:有带有·position·属性的上一级→带有position属性的上一级。(body虽然没设置position,但是因为所有元素都脱离不了body文档流,所以总能找到body是最外层)
最外层:body→null
·parentNode·
查找路径:·不考虑position·,单纯的父级元素往上查找。
最外层:body→html→document→null
object.defineProperty(对象名,'键',{value:值}):为指定对象添加属性;并且该属性不可被遍历
defineProperty的好处:
1、js默认没有数据绑定,js不会帮你做这个事情,定义过的变量用变量名赋值给另一个属性后,不会随着原先的变量改变而改变。但是defineProperty中的get函数可以将其绑定
2、get函数作用是双向绑定(改原始值会跟着变动),get函数本身不会传入参数,它“return”返回的是外面定义好的变量,所以当set函数修改了外部定义的变量,get中返回值也就变了;set函数是改对象属性时触发,修改后原始值也会发生改变(原始值会发生改变是因为修改值对原始值进行了赋值操作,再触发的get函数);使用set函数时必须也要有get函数,不然set修改完值后,没有对应的属性接收
3、数据代理:通过另一个对象来操作原先的对象属性,通过get、set函数实现
下载:
1、“window.location.href = down_url”下载会打开一个空白页,体验不好
2、download属性可有可无;添加·a.target = '_blank'·在新建空白页打开更好
JSON方法:
`JSON.stringfy`:将JS值(数组、对象等)转换为JSON字符串
`JSON.parse`:将JSON字符串转换为JS值
浅拷贝和深拷贝:
“浅拷贝”:只复制对方的引用地址,并不会开辟新的内存空间,修改复制值原值也会变。包括:引用类型的赋值、
Tips:当·扩展运算符·中的数据有·引用类型·就是浅拷贝,
“深拷贝”:复制内存中存储的值,并开辟一块新内存空间用于存储。包括:ES6的·Object.assign·、·扩展运算符{ ... }·、迭代获取基本数据类型进行赋值
Tips:虽然ES6的两种方法可以实现深拷贝,但因为堆栈的性质,只能进行一层深拷贝,如果对象下还有对象,则只会进行浅拷贝
“传值和传址”:·基本·数据类型的·等号赋值·是传值,而对象这种·引用·数据类型则是·传址·
“基本数据类型”:undefined、number、string、null
“引用数据类型”:对象、数组、函数