函数防抖与节流

先介绍概念,函数防抖节流

函数防抖

概念

某个函数在n秒后执行,假如在n秒之内又有事件被触发了,则重新开始计时。
例如:人进入电梯之后,电梯门从人进入到关上门再到开始上下运行中间花费的时间为10秒,假如在这10秒之内又有其他的人进入电梯了,那之前的时间计算就会被终止并重新开始计算。也就是在某段时间之内一个事件被触发多次,只有最后一次会被执行
适用场景:表单提交时假如用户疯狂的快速多次点击提交按钮时,使用函数防抖只会让最后一次的点击事件被触发,即:表单提交事件只执行一次。

代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
function debounce(fn, wait) {
let timer = null;
return function() {
if (timer) {
clearTimeout(timer);
}
const args = arguments;
timer = setTimeout(() => {
fn.apply(this, args);
}, wait)
}
}

从以上代码来看,debounce函数返回了一个匿名函数(注意不能写成箭头函数),不能改变fn函数的上下文执行环境,且使用了一个闭包将timer这个变量封存了起来。所以每次能进行清除及赋值操作。

函数节流

概念

函数节流就是相同时间间隔内某个事件只能执行依次。
例如:浏览器滚动条的滚动事件window.onscroll 这个函数。一旦滚动条发生了滚动之后,每隔几十毫秒就会触发一次。触发的频率越高要处理的操作就要重复执行多次,就会造成卡顿等现象。
解决办法:通过函数节流让浏览器滚动条的事件在触发之后,隔稍长的一段时间再去执行回调函数,降低事件的执行频率。

代码
1
2
3
4
5
6
7
8
9
10
11
function throttle(fn, wait) {
let prev = new Date();
return function() {
const args = arguments;
const now = new Date();
if (now - prev > wait) {
fn.apply(this, args);
prev = new Date();
}
}
}
谈谈JS中的splice与slice

对于不熟悉JS数组和字符串操作的前端来说,这两个函数在开发中简直是没有用,可能有时候想起来用了也只是很粗浅的用一下,并且还总是忘记用法,每次用的时候还得自己去搜索,头疼。第一是为了强化自己的记忆,第二是因为今天在项目中遇到一个问题使用splice能轻松的解决在这记录一下,所以写下了这边博客。
splice:JS数组函数
用法:从一个数组中删除指定的元素,改变原数组,返回被删除的数组元素,需要传参如下

arr.splice(index, length, replace)
// 解释一下以上的参数作用
// 1. index:开始删除元素的下标
// 2. length:需要删除元素的个数
// 3. replace:替换被删除的元素(可选)
const arr = [1, 2, 3, 4, 5, 6];
const newArr = arr.splice(1, 1, "*");
console.log(arr); //[1, "*", 3, 4, 5, 6] //删除了下标为1的数组元素2,替换为*
console.log(newArr); //[2] 返回被删除的元素
// splice不仅可以删除元素还可以在数组的任意位置添加元素
const newArrAdd = arr.splice(1, 0, 9); //在下标为1的地方添加一个数组元素9,其他数组元素向后依次移动位置
// 数组最后的结果为[1, 9, 2, 3, 4, 5, 6]
// 利用splice也可实现数组元素交换位置,如元素2和5交换位置下标分别是(1和4)
arr[4] = arr.splice(1, 1, arr[4])[0];

由以上代码可见splice会改变原数组并且返回被删除的元素
slice:JS数组函数
用法:从一个数组中截取指定的元素,不会改变原数组,返回被截取的数组元素组成的新数组,需要传参如下

slice(start, end)
// 解释一下以上的参数作用
// 1. start开始的下标,可以为复数, -1则为数组中的最后一个元素 -2 则为倒数第二个元素
// 2. end(可选) 结束的下标 不选时默认为数组的长度-1
// 3. 截取的数组元素包括下标start不包括下标end
// 3. 返回值为截取的数组元素组成的新数组 不会改变原有的数组
angular中服务的依赖注入

对angular的使用是因为最近部门刚刚交接的一个项目用angularjs写的,对我这种从头到尾都使用React的人来说,突然换框架去使用angularjs是一种煎熬…… 其中的一些依赖注入什么的搞的我头大,现在来展示一下我这些天踩坑对angularjs中服务的一些理解吧
首先是模块,在angularjs中模块是一个非常重要的概念

var mainApp = angular.module('mainApp', []) //定义模块时,第二个参数是必须有的即便是空数组

然后我们使用angular的factory指令创建一个service, 用来计算两个数相加

mainApp.factory('addFactory', function() {
  let service = {
    add: function(a, b) {
      return a + b
    }
  }
  return service;
})

用angular中的service指令创建一个service,用来计算两个数相加

mainApp.service('addService', function(addFactory) {
  this.add = function(a, b) {
    return a + b;
  }
})

用angular中的provider指令创建一个service,用来计算两个数相加

mainApp.provider('addProvider', function() {
  this.$get = function() {
    var provider = {
      add: function(a, b) {
        return a + b;
      }
    }
    return provider;
  }
})

使用angular的constant指令创建两个常量

mainApp.constant('numA', 10);
mainApp.constant('numB', 20);

接下来我们定义一个controller,将我们定义的服务注入进来

mainApp.controller('mainController', function($scope, addFactory, addService, addProvider, numA, numB) {
  console.log('addFactory:', addFactory);
  console.log('addService:', addService);
  console.log('addProvider:', addProvider);
  console.log('numA:', numA);
  console.log('numB:', numB);
  $scope.result = addService(numA, numB);
})

然后写一个html,将controller引入进来

<html>
<head>
  <meta charset="utf-8">
  <title>AngularJS 依赖注入</title>
</head>
<body>
  <h2>AngularJS 简单应用</h2>
  <div ng-app="mainApp" ng-controller="mainController">
    <p>结果: {{result}}</p>
  </div>
</body>
</html>

controller中打印出来的值为,如下图

界面中result的值为

浅谈JS原型与原型链

JS的原型及原型链是在ES6之前,ES5语法因为构造函数的原型而引出来的一些列问题,不多说看以下下的代码

function Foo() {} // 定义一个构造函数  
var obj = new Foo(); // 实例化一个对象  

在chrome的控制台,打印某个对象的时候都有一个proto属性, 如

console.log(obj) // 结果如下图


相对的每一个构造函数都有一个prototype属性,如

console.log(Foo.prototype)


可能你们已经发现了

console.log(obj.__proto__===Foo.prototype) // true

一个对象的【__proto__】属性指向与它对应的构造函数的【prototype】, 这就是原型
那么原型链又是怎么回事呢??
注意看上面的第二张图Foo.prototype有一个__proto__属性,为了方便看我把它粘贴到下面


那就说明Foo的原型也是一个对象,所以也会有这个__proto__属性,那么如果我们打印一下Foo.prototype.__proto__

我们发现Foo.prototype.__proto__的构造函数是Object(),因为上面提到过对象的proto是指向对应的构造函数的prototype,则

console.log(Object.prototype)


那么我们神奇的发现

console.log(Foo.prototype.__proto__===Object.prototype) // true
                              ||
console.log(obj.__proto__.__proto__===Object.prototype) // true

有没有发现console.log(obj.__proto__.__proto__===Object.prototype)就很像一条链,一层层的指上去
那么同理Object.prototype.__proto__ 又指向什么呢?

console.log(Object.prototype.__proto__)


即到最后所有的对象都继承自null,最后我们得到的原型链即是

console.log(obj.__proto__.__proto__.__proto__===null) /// true
Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment