首页 JavaScript 正文
  • 本文约11036字,阅读需55分钟
  • 1293
  • 0

总结的一些 function 开箱即用

温馨提示:本文最后更新于2022年2月23日 14:43,若内容或图片失效,请在下方留言或联系博主。

正则表达式

身份证号

function isIdCard(str) {
  return /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(str);}

手机号

function  isPhoneNumber(str) {
    return /^1[3456789]\d{9}$/.test(str);}

是否合法的http/https域名

function isHttpUrl(str) {
    return /^(http|https):\/\/[^\s]+$/.test(str);}

JavaScript

判断数据类型

/**
 * 类型检测函数
 * 为typeof关键字的增强版,可以准确判断null,date类型
 * 原理是使用V8引擎最初的toString方法观察数据类型
 * @author 不爱喝橙子汁
 * @version 1.0.0
 * @param {Object} obj 任意对象,例如null,undefined,date
 * @return {String} 类型的全小写字符串
 */function type(obj) {
   return Object.prototype.toString.call(obj).slice(8,-1).toLowerCase(); }

数组操作

数组

  1. 数组是个线性结构

  2. 在js里它没有固定的大小

  3. 它也不要求所有元素的数据类型都一样(但你最好保证他们是一样的)

创建数组的方式

字面量(推荐)

const nums = [1, 2, 3];

使用Array里的静态方法

const strs = Array.from('Hello World')

API

javascript的数组实现了栈和队列

 

追加一个元素

num.push(10)

 

追加多个元素

num.push(11,15)

 

在数组前面加一个元素

strs.unshift('a')

 

在数组尾巴删除一个元素

num.pop()

 

在数组头部删除一个元素

strs.shift()

注意以上都是命令性的操作,虽然他们都有返回值但最好不用使用他们(对于追加来说会返回你追加的元素,对于弹出来说会返回弹出来的元素)

 

 

指定区间

nums.slice(1,3); // 从1到3

记得是左闭右开区间!!!

映射

nums.map(x => x * 2) // 获取所有元素都乘2了的版本

过滤

nums.filter(x => x % 2 === 0) // 只要偶数

累积

nums.reduce((result x) => result + x, 0);

反转

strs.reverse()

拼成字符串

strs.join('')

以上为 函数式操作,不会更改原有数组,它的返回值才是有意义的结果。


获取长度

num.length

把nums.length复制为0可以清空数组

索引一项

使用下标索引即可

nums[nums.length-1]; // 最后一个元素

节流与防抖函数

/**
 * 节流
 * 在给定时间内只有第一次的操作会返回结果
 * 结合了防抖的思路:在delay时间内生成定时器,一旦到了delay的时间就返回结果
 * 当用户只点击了一次的时候,在delay时间后得到结果
 * 当用户点击了多次的时候,在delay时间后得到第一次的结果,其余的被节流阀忽视掉
 * @author 不爱喝橙子汁
 * @version 1.0.0
 * @param {Function} fn 要包装的回调函数
 * @param {number} delay 延迟时间,单位ms,默认500
 * @return {Function} 被节流函数劫持的新的函数
 */function throttle(fn, delay = 500) {
  let last = 0;
  let timer = null;
  
  return function () { 
    let args = arguments;
    let now = +new Date();
    let context = this;
    
    if (now - last < delay) {
      clearTimeout(timer);
      timer = setTimeout(() => {
        last = now;
        fn.apply(context, args);
      }, delay);
    } else {
        last = now;
        fn.apply(context, args);
    }
  }}
/**
 * 防抖
 * 在delay时间后得到结果
 * 如果没等到delay的时间一直触发则永远也得不到结果
 * @author 不爱喝橙子汁
 * @version 1.0.0
 * @param {Function} fn 要包装的回调函数
 * @param {number} delay 延迟时间,单位ms,默认500
 * @return {Function} 被防抖函数劫持的新的函数
 */function debounce(fn, delay = 500) {
  let timer = null;
  return function () {
    let args = arguments;

    if(timer) {
        clearTimeout(timer);
    }
    
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  }}

this怎么就不对

this指向问题

this应该是第一个让人对JavaScript困惑的问题了,但是实际上它的原理非常简单:函数的this在运行时绑定。

什么叫运行时绑定?就是函数的this和你写在哪里无关,而是和谁调用它有关。谁调用这个函数,this就指向谁。

你现在大概会在想:原来这么简单,我精通了!

那可就大错特错了,可千万别忘了光函数的调用方法就有两种:直接调和new一个,而能做这两个操作的地方可以说非常的多,所以还需要往下看。

注意:以下例子均为严格模式下运行,非严格模式这里不做考虑。

初级

function f1 () {
    console.log(this)}f1();

问结果是什么?先问自己:谁调用的它?你应该一下看不出来,这明明就是直接调的啊!可能有的基础比较扎实的人会说是window,那真是非常的恭喜你了,但你要注意的是以上代码在严格模式下是undefined。

正解: window / undefined

const foo = {
    bar: 10,
    fn: function() {
       console.log(this)
       console.log(this.bar)
    }}let fn1 = foo.fnfn1()

结果是什么?你可能一眼看到fn是定义在foo对象里,那this可不就是foo吗,刚刚说什么来着,先问自己:谁调用的它,来看最后一行再回答一遍。

正解:window / undefined

中级

const foo = {
    bar: 10,
    fn: function() {
       console.log(this)
       console.log(this.bar)
    }}foo.fn()

现在你应该已经有点感觉了,来,说出来,谁调用的它fn?

正解:foo

中级+

const person = {
    name: '橙子',
    brother: {
        name: '河浪',
        fn: function() {
            return this.name        }
    }}console.log(person.brother.fn())

看能不能过关斩将,谁调用的fn?

正解:brother

call / bind / apply

此为3种干预this指向的操作,限于篇幅不展开讲。

箭头函数

箭头函数可以让你省很多事,因为它的this一般来说都是符合你的直觉的:它的this就是定义时候的this。

 

计算地图上两点间的距离

计算地图上两点距离

/**
 * 获取地图上两点间距离。单位:米
 * @param {lat1} 第一个点的纬度
 * @param {lon1} 第一个点的经度
 * @param {lat2} 第二个点的纬度
 * @param {lon2} 第二个点的经度
 * @author 不爱喝橙子汁
 */export function getDistance(lat1, lon1, lat2, lon2) {
  const radLat1 = (lat1 * Math.PI) / 180.0;
  const radLat2 = (lat2 * Math.PI) / 180.0;
  const a = radLat1 - radLat2;
  const b = (lon1 * Math.PI) / 180.0 - (lon2 * Math.PI) / 180.0;
  let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
  s = s * 6378137;
  s = Math.round(s * 10000) / 10000;
  return s;}

css

我要超出显示省略号

单行显示

.oneline {
    overflow: hidden;
    word-break: break-all;
    text-overflow: ellipsis;
    -webkit-box-orient: horizontal;
    -webkit-line-clamp: 1;
    line-clamp: 1;
    display: -webkit-box;}

两行显示

.twoline {
    overflow: hidden;
    word-break: break-all;
    text-overflow: ellipsis;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    display: -webkit-box;}

其他的自己类推吧

关键帧与动画

CSS关键帧与动画

动画的原理

即静态图片的快速切换,快到人眼分辨不出来的时候就可以产生连续移动动画的效果。

需要多快

对于纯静态图片来说,需要一秒切换三十张(游戏的CG),对于拍摄来说,需要一秒切换24张(电影)。

因为摄像机拍出来的东西并不是纯静态的,它的每一帧包含有它的上一帧和下一帧的部分信息(比如如果说风扇再转,拍摄出来的效果的每一张截图都是模糊的,相反赛车游戏,你截屏的每一张都是清晰的风景壁纸)

通解即最小单元,这个概念在网络上也同样适用,在这里就是构成动画的每一张静态图片。

关键帧

对于早期动画来说,例如《大闹天宫》,30帧的动画几乎每一帧都是画出来的,但是现在在计算机的帮助下不需要了,计算机可以自动推算补帧,而你需要给出的是关键帧,关键帧与关键帧之间的动画则由计算机自己脑补。比如第一个关键帧说盒子在左边,第二个关键帧说盒子在右边,那么计算机会自动补齐从左到右的移动过程。

实战一下

HTML部分

<body>
<div class="box"></div></body>

非常简单,一个盒子就可以了

css部分

// 设置背景颜色
body {
background: #333;}.box {
background: #fff; // 设置显眼的颜色
width: 200px; // 固定宽,为了看的见
height: 200px; // 固定高,为了看的见
position: relative; // 相对定位
animation-name: myanimation; // 动画名字,指定关键帧的名字就可以,细节在下面的定义
animation-duration: 4s; // 动画持续时间,间接控制速率,越长越慢!
}// 定义关键帧
    @keyframes myanimation {
// 必须。在动画开始时,关键帧的位置
0% {
background: #fff;
left: 0;
top: 0;
}

// 在动画四分之一时,关键帧的位置
25% {
background: #f00;
left: 300px;
top: 0;
}

// 在动画一半时,关键帧的位置
50% {
background: #0f0;
left: 300px;
top: 300px;
}

// 在动画四分之三时,关键帧的位置
75% {
background: #00f;
left: 0;
top: 300px;
}

// 必须,在动画结束时,关键帧的位置
100% {
background: #fff;
left: 0;
top: 0;
}}

CSS动画属性总结

动画基本属性总结

这里做复习和记忆

animation-name: myanimation; // 动画名字,指定关键帧的名字。
animation-duration: 4s; // 动画持续时间,间接控制速率,越长越慢!
animation-iteration-count: infinite; // 重复次数,可以填数字也可以填infinite,infinite代表无限重复
animation-timing-function: linear; // 动画速度,匀速
animation-delay: 2s; // 延迟2秒开始
animation-direction: reverse; // 动画方向,反向

这些属性的其他值就自己去查吧,并且注意他们也有all in one的简写形式。

过渡与动画

CSS过渡与动画

前言

过渡和关键帧均是实现动画的方式,但他们是两个系统的。他们的属性有相似性。

可被用来过渡的属性

background-color

background-position

border-color

border-width

border-spacing

bottom

color

font-size

font-weight

height

left

letter-spacing

line-height

magin

max-height

max-width

min-height

min-width

opacity

outline-color

outline-offset

outline-width

text-indent

text-shadow

z-index

word-spacing

visibility

verticle-align

...其他我懒得打的属性...

实战一下

HTML

<div class="box"></div>

CSS

body {
background: #333;}.box {
background: #fff;
width: 300px;
height: 300px;
position: relative;
margin: auto;
top: 200px;
transition-property: background, border-radius;
transition-duration: 1s;}.box:hover {
background: red;
border-radius: 50%;}

数据处理

对数组分组

把若干数组按指定的字段名进行分组

function groupBy(list, propName) {
 return list.reduce((acc, item) => {
   const key = item[propName];
   if (!acc[key]) {
     acc[key] = [];
   }
   acc[key].push(item);
   return acc;
 }, {});}

深拷贝对象

function deepClone(obj) {
 if (obj === null) return null;
 if (typeof obj !== 'object') return obj;
 if (obj instanceof Date) {
   let date = new Date();
   date.setTime(obj.getTime());
   return date;
 }
 if (obj instanceof RegExp) {
   let re = new RegExp(obj.source);
   re.lastIndex = obj.lastIndex;
   return re;
 }
 let newObj = new obj.constructor();
 for (let key in obj) {
   if (obj.hasOwnProperty(key)) {
     newObj[key] = deepClone(obj[key]);
   }
 }
 return newObj;}

提取数组属性

/**
* 提取若干数组中指定字段组合成一个新数组
*/function extractProps(arr, prop) {
 return arr.map((item) => item[prop]);}

提取对象属性

/**
* 提取对象中的指定的属性,返回一个新对象
*/function pickProps(obj, props) {
 if (typeof obj !== 'object') {
   return obj;
 }
 const newObj = {};
 props.forEach((prop) => {
   newObj[prop] = obj[prop];
 });
 return newObj;}

评论