ES6 箭头函数

箭头函数,ES6 中出现了一个特殊的大类,有怎么的特性,又该如何使用,与普通函数的区别又是如何?

简单谈谈

对于箭头函数的出现,我是这样理解的:

functionJavaScript 中是一种类似与流程的一种存在,一个 function 代表一种处理数据的逻辑。在 ES6 中, function 的这一特性被进一步的认可和强调,因此产生了箭头函数。

箭头函数

let f = v => v;

上面的箭头函数的约等于以下函数

var f = function(v) {
  return v;
};

当然函数参数存在没有或者多个情况

var f = () => 5;
// 约等于
var f = function () {
    return 5;
};

var sum = (num1, num2) => num1 + num2;
// 约等于
var sum = function(num1, num2) {
  return num1 + num2;
};

当箭头函数的代码块部分多于一条语句,就需要使用大括号括起来,并使用 return 语句返回。

var sum = (num1, num2) => { 
    return num1 + num2
}

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,就必须在对象外面加上大括号。

// 报错
let getTempItem = id => { id: id, name: "Temp" }

// 不报错
let getTempItem = id => ({ id: id, name: "Temp" })

当然箭头函数也是函数,拥有函数的所有功能。

  1. 参数默认值
  2. 参数的变量解构
  3. rest 参数
const full = ({ first, last } = { first:'xxx', last:'xxxx' }) => first + ' ' + last

箭头函数的使用技巧

// 正常函数写法
[1, 2, 3].map(function (x) {
  return x * x;
})

// 箭头函数写法
[1, 2, 3].map(x => x * x);

// 正常函数写法
var result = values.sort(function (a, b) {
  return a - b
});

// 箭头函数写法
var result = values.sort((a, b) => a - b)

const numbers = (...nums) => nums

numbers(1, 2, 3, 4, 5)
// [1, 2, 3, 4, 5]

使用注意点

  1. 函数体内的 this 对象,是定义时所在的对象,不会随着调用环境的变化而变化。
  2. 不可以当作构造函数,也就是不能使用 new
  3. 不可以使用 arguments 对象,该对象在函数体内不存在,可以用 rest 参数替代。
  4. 不可以使用 yield 命令,因此不能用作 Generator 函数。

箭头函数中的 this 对象

在箭头函数中 this 对象是固定的,并不会因为调用环境的不同而不同

注意这句话:这里说明的是调用环境,而不是生成环境,箭头函数的 this 指向为生成环境,所以对函数的生成环境进行修改,this 下对应的值也是会发生变化的。

function foo() {
    setTimeout(() => {
        console.log('id:', this.id)
    }, 100)
}

let id = 21

foo.call({ id: 42 })
// id: 42

这个例子中,setTimeout 中是一个箭头函数,设置在 100ms 后执行,一般的函数在执行时,才会去找 this 的指向,而箭头函数直接输出了 42 ,而这个 42 是箭头函数生成是所在的对象(这里是 { id: 42 } )所以输出的是 42

作为对比,可以用以下代码测试效果

function foo() {
    setTimeout(function() {
        console.log('id:', this.id)
    }, 100)
}

var id = 21

foo.call({ id: 42 })
// id: 21

一个更完美解释了该现象的例子

function Timer() {
    this.s1 = 0
    this.s2 = 0
    // 箭头函数
    setInterval(() => this.s1++, 1000)
    // 普通函数
    setInterval(function () {
        this.s2++
    }, 1000)
}

var timer = new Timer()

setTimeout(() => console.log('s1: ', timer.s1), 3100)
setTimeout(() => console.log('s2: ', timer.s2), 3100)
// s1: 3
// s2: 0

箭头函数可以让 this 的指向固化,因此可以用来封装回调

var handler = {
    id: '123456',

    init: function() {
        document.addEventListener('click', event => this.doSomething(event.type), false)
    },

    doSomething: function(type) {
        console.log('Handling ' + type  + ' for ' + this.id)
    }
};

例子中调用 handler.init 时,由于内部是箭头函数,那么箭头函数内部的 this 即为 init 函数的 this ,也就是 handler 对象,而如果不是使用箭头函数,那么在执行回调时,this 将会指向 document

没有 this !

this 指向的固定化,并不是因为箭头函数内部有绑定 this 的机制,实际原因是箭头函数根本没有自己的 this ,导致内部的 this 就是外层代码块的 this 。正是因为它没有 this ,所以也就不能用作构造函数。

如果把 this 仅仅当一个单纯的变量看待的话,这一切就好理解了。

因此箭头函数转成 ES5 的代码时,需要特别处理 this 的指向。

// ES6
function foo() {
    setTimeout(() => {
        console.log('id:', this.id)
    }, 100)
}

// 转换为 ES5 时需要处理 this 的指向问题
function foo() {
    var _this = this

    setTimeout(function () {
        console.log('id:', _this.id)
    }, 100)
}

箭头函数的注意点

  1. thisargumentssupernew.target4 个变量在箭头函数内部都是不存在的,指向外层函数的相应变量。
  2. 由于箭头函数没有自己的 this ,所以不能使用 callapplybind 这些方法去改变 this 的指向。

双冒号运算符

函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即 this 对象),绑定到右边的函数上面。

foo::bar
// 等同于
bar.bind(foo)

foo::bar(...arguments)
// 等同于
bar.apply(foo, arguments)

const hasOwnProperty = Object.prototype.hasOwnProperty
function hasOwn(obj, key) {
  return obj::hasOwnProperty(key);
}

因此双冒号运算符能固定函数执行的上下文环境的能力。

当需要固定的上下文环境和函数所属对象是同一个时,可以简写省略前面的对象

var method = obj::obj.foo
// 等同于
var method = ::obj.foo

let log = ::console.log
// 等同于
var log = console.log.bind(console)

Read more

Gitlab 搭建

Gitlab 搭建

为什么? 想要自己搭建一个代码仓库无非是以下几点原因: 1. 公司内部项目 2. 自己的项目,但不适合在公网 3. 大部分的 git 仓库虽然有私有服务,但价格都不便宜,甚至不如一台云服务器来的便宜 配置及安装文档 Gitlab * 由于 gitlab 会用到 22 端口端口转发的化就走不了 git clone 的默认配置,且占用内存较高,不推荐使用 docker 进行部署; * 由于 gitlab 自带 nginx 默认情况下会与属主机的 nginx 冲突,因此推荐只使用 gitlab 自带的 nginx 进行端口转发; 最小化配置 # path /etc/gitlab/gitlab.rb external_url 'http://git.

By breeze
NPM 私服

NPM 私服

verdaccio 私服搭建,搭建过程中的一些问题以及解决: * docker compose 启动后,可能会报错:配置找不到,添加 config.yaml 文件到映射的 ./conf 目录即可,config.yaml 具体内容可在官网找到,下方也有最小化配置。 services: verdaccio: image: verdaccio/verdaccio container_name: 'verdaccio' networks: - node-network environment: - VERDACCIO_PORT=4873 - VERDACCIO_PUBLIC_URL=http://npm.demo.com ports: - '10001:4873'

By breeze