命名规则
- 小驼峰:js函数和变量
- 大驼峰:js类和组件文件
- 烤肉串:组件名和模板中使用
proto,prototype,constructor之间的关系
this的指向
function x (){
console.log(this)
}
- 直接调用: x();this指向window
- 方法调用:var o = {x:x};o.x();this指向o
- 构造函数: var z = new x();this指向z
- call,apply,bind x.call(this);this指向绑定的this
无限滚动的封装
组件页面
<template>
<div>
<slot></slot>
<div v-abserve="{handler:scroll}" :style="{ height: height }" class="abserve"></div>
</div>
</template>
<script>
export default {
name: "infiniteScroll",
props: {
height: {
default() {
return "60px";
},
},
},
methods: {
scroll() {
console.log('scroll');
}
},
};
</script>
自定义指令
const intersect = {
inserted(el, binding) {
const value = binding.value;
const { handler, options = {} } = value;
const observer = new IntersectionObserver((entries = [], observer) => {
if (!el._observe) return;
if (handler && el._observe.init) {
const isIntersecting = Boolean(
entries.find((entry) => entry.isIntersecting)
);
if (isIntersecting) {
handler(entries, observer, isIntersecting);
}
}
el._observe.init = true;
}, options);
el._observe = { init: false, observer };
observer.observe(el);
},
unbind(el) {
if (!el._observe) return;
el._observe.observer.unobserve(el);
delete el._observe;
},
};
export default intersect;
函数按队列执行之迭代器
let before = (to, from, next) => {
console.log("before");
next(true)
};
let enter = (to, from, next) => {
console.log("enter");
next(true)
};
let leave = (to, from, next) => {
console.log("leave");
next(true)
};
let queueList = [leave, enter, before];
const runQueue = (queque, itr, end) => {
const step = (index) => {
if (index > queque.length) {
end();
} else {
if (queque[index]) {
itr(queque[index], () => {
step(index + 1);
});
} else {
step(index + 1);
}
}
};
step(0);
};
function iterator(hook, next) {
hook('to', 'from', (to) => {
if (to === false) {
return;
} else {
next();
}
});
}
function complete() {}
runQueue(queueList, iterator, complete);
内存管理
- 内存泄漏:一些不在使用的变量没有释放。
- 内存溢出:需要使用的空间大于可用内存。会造成客户端卡顿,甚至无响应。
提高代码的可靠性
保证函数无副作用的特性
- 函数入口使用参数运算,二不修改它
- 函数内不修改函数外的变量
- 运算结果通过函数返回给外部
函数的概念
- 函数式编程:将我们程序分解为一些更可重用、更可靠且更易于理解的部分,然后再将他们组合起来,形成一个更易推理的程序整体
- 纯函数:如果函数的调用参数相同,则永远返回相同的结果。它不依赖程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。
- 函数的副作用:当调用函数时,除了返回函数数值之外,还对主调用函数产生附加的影响ps:修改全局变量(函数外的变量)或修改参数
- 依赖注入:将不纯的函数提取出来作为参数
- 可变性:一个变量创建或可以任意修改
- 不可变性:一个变量被创建就永远不会发生改变,不可变性是函数式编程的核心概念
compose函数
compose函数:将需要嵌套执行的函数平铺。嵌套执行指的是一个函数的返回值将作为另一个函数的参数
const fn = (x)=>{return (x+10)*2}
const compose = (...args)=>(x)=>args.reduceRight((prev,next)=>next(prev),x)
高阶函数
-
高阶函数就是一个函数,它接收函数作为参数或将函数作为输出返回
-
用reduce去重
let newArr = arr.reduce((prev,next)=>{
prev.indexOf(next) === -1 && prev.push(nextt)
return prev
},[])
- flat数组扁平化 arr.flat(x);x表示数组扁平化的层数,x= Infinity表示无线层
常用函数
- 缓存函数:把参数和对应的结果数据存到一个对象中,调用时,判断参数对应的数据是否存在,存在就返回对应的结果数据。
- 柯里化函数:是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。
- 偏函数:偏函数则是固定一个函数的一个或者多个参数,也就是将一个n元函数转换成一个n-x元函数。
let add = (x,y) => x+y; let rst = add.bind(null,1); rst(2)
防抖和节流
- 、防抖(debounce):当持续触发事件时,一定时间段内没有在触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
const debounce = (fn,delay)=>{
let timer = null;
return function(...args){
if(timer){
clearTimeout(timer)
}
timer = setTimeout(()=>{
fn(...args);
},delay)
}
}
- 函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数
const throtle = (fn, delay) => {
let flag = true;
return (...args) => {
if (!flag) return;
flag = false;
setInterval(() => { fn(...args); flat = true }, delay)
}
}
js类型转换场景
- 转字符串:经常出现在+运算中,并且其中有一个操作数不是数值类型
- 转数值:经常出现在数学运算中,表示连接字符串的+运算符除外
- 转布尔:经常出现在if语句、逻辑运算中
显示类型转换
- Boolean()
- Number()
- String()
- Object()
- value.toString();ps:null、undefined没有toString方法,会报错
- number类型转换为字符串:toFixed()、toExponential()、toPrecision();
- 字符串转为数值:parseInt()和parseFloat()。
类型识别
- typeof
- instanceof obj instanceof constructor ps:obj instanceof Date/Array/Object/RegExp。 无法判断原始类型
- Object.prototype.toString.call(obj):[object Date]/[object Array]/[object RegExp]
模板字符串
- 模板字符串被转义之前的值
let msg = `Mul\nstring`;
let msg1 = String.raw`Mul\nstring`;
console.log(msg);
// Mul
// string
console.log(msg1);
// Mul\nstring
Symbol
Symbol是想给他人创建的对象添加属性,不管该属性取什么名字,理论上都存在冲突的可能。而使用Symbol作为对象的属性名就没有这个顾虑,因为它的值是唯一的。
let name = Symbol('my name');
let person = {};
person[name] = 'tian';
person[name] = 'kang';
console.log(person[name]);
console.log(name);
Symbol.for
let uid1 = Symbol.for('uid');
let uid2 = Symbol.for('uid');
console.log(uid1 === uid2); //true
let uid1 = Symbol('uid');
let uid2 = Symbol('uid');
console.log(uid1 === uid2);//false
Symob.keyFor()
let uid1 = Symbol.for('uid1');
console.log(Symbol.keyFor(uid1)); //"uid1"
原型
属性检测
- 'ind' in obj:检测自身和原型链上的属性
- obj.hasOwnProperty('ind');检测自身的属性,不会检测原型链的属性。
- this instanceof Person:判断this是不是Person的实例
- 当以构造函数的形式调用函数时,new.target指向的是构造函数的本身。
function Person(name){
if(new.target === Person){
//表示Person是已构造函数调用的
}
}
- prototype是函数对象存在的属性,当成构造函数,定义它的原型对象
- proto 是任意对象存在的属性,指向自身构造函数的原型对象
函数进阶
- 柯里化函数生成唯一id的函数
function initId(startId){
let id = startId || 0;
return function(step){
id += step || 1;
return id
}
}
let getId = initId(100);
console.log(getId(15));//115
console.log(getId());//116
面向对象
访问器属性
var company = {};
Object.defineProperty(company,'age',{
// writable:true,
// value:13,
get(value){
console.log(value);
},
set(value){
console.log('value',value);
}
})
console.log(company.age); //13
company.age = 22;
console.log(company.age) //13
批量定义属性
Object.definePropertys(company,{
'age':{
writable:true,
value:13,
},
'name':{
value:13,
}
})
获取给定属性的描述符
var company = {};
Object.definePropertys(company,{
'age':{
writable:true,
value:13,
},
'name':{
value:13,
}
})
let desc = Object.getOwnPropertyDescriptor(company,'age');
console.log(desc.value);//13
console.log(company.writable); //true
class类
class Company {
constructor (x,y){
this.a = x;
this.b = y;
}
fn(){
console.log(this.a)
}
}
Generator函数(生成器)
- es6异步编程解决方案
- 通过function*声明
- 返回值:符合可迭代协议和迭代器协议的生成器对象
- 在执行时能暂停,又能从暂停出执行
yield:只能出现在generator函数中。用来暂停和恢复生成器函数
function* createIterator (){
let first = yield 1;
let second = yield first + 2;
yield second + 3;
}
let iterator = createIterator();
console.log( iterator.next());//{ value: 1, done: false }
console.log( iterator.next(3));//{ value: 5, done: false }
console.log( iterator.next(5));//{ value: 8, done: false }
console.log( iterator.next());//{ value: undefined, done: true }
yield* 生成器函数/可迭代对象
- 委托给其他可迭代对象
- 作用:复用生成器
function* createIterator1 (){
let first = yield 1;
let second = yield first + 2;
yield second + 3;
}
function* createIterator2 (){
let first = yield 1;
let second = yield first + 2;
yield* createIterator1();
yield second + 3;
}
let iterator = createIterator2();
return(param) 给定param值终结遍历器
function* createIterator2 (){
let first = yield 1;
let second = yield first + 2;
yield second + 3;
}
let iterator = createIterator2();
console.log( iterator.next());//{ value: 1, done: false }
console.log( iterator.return(3));//{ value: 3, done: true }
关于for in 遍历
- for in 会遍历数组或对象和其原型和原型链上的可枚举的属性
- Object.defineProperty(obj,x,{ value:100, enumerable:true//可枚举 })
判断变量的类型
function typeOf(obj) {
const toString = Object.prototype.toString;
const map = {
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]' : 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regExp',
'[object Undefined]': 'undefined',
'[object Null]' : 'null',
'[object Object]' : 'object'
};
return map[toString.call(obj)];
}
冒泡排序
isok判断排序是否完成
let arr = [3, 4, 1, 6, 3, 5, 10, 9, 8, 2];
for (let j = 0; j < arr.length - 1; j++) {
let isOk = true;
for (let i = 0; i < arr.length - 1-j; i++) {
let a = arr[i];
let b = arr[i + 1];
if (a > b) {
isOk = false;
arr[i] = b;
arr[i + 1] = a;
}
}
if(isOk){
break;
}
}
数组扁平化
function flat(items) {
let newArr = [];
items.forEach(item => {
newArr.push(item)
if (Array.isArray(item.children)) {
newArr = newArr.concat(flat(item.children))
}
});
return newArr;
}
function flat (items){
return items.reduce((prev,next)=>{
return prev.concat(next,Array.isArray(next.children)?flat(next.children):[]);
},[]);
}
数组去重
[...new Set(arr)]
let obj = {}
arr.forEach(item => {
obj[item] = 1
});
Object.keys(obj).map(o=>Number(o));
解构赋值
- 数组解构赋值:ps:let [a,b,c]=[1,2,3];
- 解构的默认值:ps:let [foo = true] =[];
- let [a,b="JSPang"]=['技术胖',null];console.log(a+b); //控制台显示“技术胖null”
- 对象的解构赋值 ps:let {foo,bar} = {foo:'JSPang',bar:'技术胖'};
- 字符串的解构ps:const [a,b,c,d,e,f]="JSPang";
扩展运算符
- 扩展运算符 ps: let arr = [1,2,3]; let newArr = [...arr];
字符串的查找
- es5:let str = 'string'; str.indexOf('t');找对应下标; es6:str.includes('t');返回true/false;
- str.startsWith('s');判断开头是否存在's',返回true/false
- str.endsWith('g');判断结尾是否存在'g',返回true/false
- str.repeat(2); 'tiankang'.repeat(2) --> 'tiankangtiankang'
数字操作
- Number.isFinite( xx )只要是数字,不论是浮点型还是整形都会返回true,其他时候会返回false
- Number.isNaN(NaN)验证数字是不是NAN返回true/false
- Number.isInteger(xx)判断是否为整数
- 整数转换Number.parseInt(xxx)和浮点型转换Number.parseFloat(xxx)
- 最大安全整数Number.MAX_SAFE_INTEGER数字能取的最大值
- 最小安全整数Number.MIN_SAFE_INTEGER
- 安全整数判断isSafeInteger( )
数组的操作方法
-
Array.from(json);把json转成数组
-
Array.of(3,4,5,6);一堆文本或者变量转换成数组
-
arr.find(function(value,index,arr){ return value > 5; })value:表示当前查找的值。 index:表示当前查找的数组索引。 arr:表示当前数组;如果找到就返回找到的值,否则返回undefined
-
arr.fill('jspang',2,5);第一个参数是填充的变量,第二个是开始填充的位置,第三个是填充到的位置
-
arr.flat(num);数组扁平化,num扁平化的层数,如果是无穷num=infinity arr=[1,[1,2,3]] --> [1,1,2,3]
函数
-
默认值 function add(a,b=1){ return a+b; } console.log(add(1));
-
in是用来判断对象或者数组中是否存在某个值的; 'a' in obj 或 0 in arr
数组的遍历方法
- arr.forEach((val,index)=>console.log(index,val));forEach循环的特点是会自动省略为空的数组元素,相当于直接给我们筛空了
- arr.filter(x=>console.log(x));
- arr.some(x=>console.log(x));只要有一个条件满足就会返回true否则返回false
- arr.every(x=>console.log(x));要所有的都满足才会返回true否则返回false
- arr.map(x=>'web')
- arr.join('|')
- arr.toString() 返回1,2,3
对象
-
对象Key值构建let key='skill'; var obj={ [key]:'web' } console.log(obj.skill);
-
Object.assign( )合并对象 ps:let d=Object.assign(a,b,c)
窗口的滚动值获取
function getScroll(target, top) {
const prop = top ? 'pageYOffset' : 'pageXOffset'; //获取元素距离视口顶部和左边滚动的距离
const method = top ? 'scrollTop' : 'scrollLeft';
let ret = target[prop];
if (typeof ret !== 'number') {
ret = window.document.documentElement[method];
}
return ret;
}
function getOffset(element) {
const rect = element.getBoundingClientRect();//获取元素相对于视窗的位置集合
const scrollTop = getScroll(window, true);
const scrollLeft = getScroll(window);
const docEl = window.document.body;
const clientTop = docEl.clientTop || 0; 这两个返回的是元素周围边框的厚度
const clientLeft = docEl.clientLeft || 0;
return {
top: rect.top + scrollTop - clientTop,
left: rect.left + scrollLeft - clientLeft
};
}
元素的偏移距离和滚动距离的获取
- offsetWidth 元素的宽度(包括border和padding)
- offsetHeight 元素的高度(包括border和padding)
- offsetLeft 元素相对父元素左边偏移的距离
- offsetTop 元素相对父元素上边偏移的距离
- clientWidth 元素可视区域的宽度(不包括border和滚动条)
- clientHeight 元素可视区域的高度(不包括border和滚动条)
- clientTop 元素可视区域的宽度(border加滚动条)
- clientLeft 元素可视区域的宽度(border加滚动条)
- scrollWidth 元素可滚动高度
- scrollHeight 元素可滚动宽度
- scrollLeft 元素距离左边滚动的距离
- scrollTop 元素距离上边滚动的距离
- window.pageXOffset 窗口左边的滚动距离(比scrollLeft兼容性更好)
- window.pageYOffset 窗口上边的滚动距离