前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript闭包与箭头函数

JavaScript闭包与箭头函数

作者头像
用户1203875
发布2018-07-20 09:49:23
8160
发布2018-07-20 09:49:23
举报
文章被收录于专栏:Rovo89Rovo89
闭包

闭包是JavaScript中最强大的特性之一

JavaScript允许函数嵌套

内部函数可以访问定义在外部函数中的所有变量和函数以及外部函数能访问的所有变量和函数

外部函数不能够访问定义在内部函数中的变量和函数

当内部函数生存周期大于外部函数时,由于内部函数可以访问外部函数的作用域,定义在外部函数的变量和函数的生存周期就会大于外部函数本身

当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了

代码语言:javascript
复制
var pet = function(name) {   // The outer function defines a variable called "name"
  var getName = function() {
    return name;             // The inner function has access to the "name" variable of the outer function
  }
  return getName;            // Return the inner function, thereby exposing it to outer scopes
},
myPet = pet("Vivie");
   
myPet();                     // Returns "Vivie"

下面例子,返回了一个包含可以操作外部函数的内部变量方法的对象

代码语言:javascript
复制
var createPet = function(name) {
  var sex;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    },
    
    getSex: function() {
      return sex;
    },
    
    setSex: function(newSex) {
      if(typeof newSex == "string" 
        && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
pet.getName();                  // Vivie

pet.setName("Oliver");
pet.setSex("male");
pet.getSex();                   // male
pet.getName();                  // Oliver

内嵌函数的内嵌变量就像内嵌函数的保险柜。它们会为内嵌函数保留“稳定”——而又安全——的数据参与运行。而这些内嵌函数甚至不会被分配给一个变量,或者不必一定要有名字。

代码语言:javascript
复制
var getCode = (function(){
  var secureCode = "0]Eal(eh&2";    // A code we do not want outsiders to be able to modify...
  
  return function () {
    return secureCode;
  };
})();

getCode();    // Returns the secret code

注意:如果一个闭包的函数用外部函数的变量名定义了同样的变量,那在外部函数域将再也无法指向该变量。

代码语言:javascript
复制
var createPet = function(name) {  // Outer function defines a variable called "name"
  return {
    setName: function(name) {    // Enclosed function also defines a variable called "name"
      name = name;               // ??? How do we access the "name" defined by the outer function ???
    }
  }
}

闭包中的神奇变量this是非常诡异的。 使用它必须十分的小心,因为this指代什么完全取决于函数在何处被调用,而不是在何处被定义。

使用arguments对象

函数的实际参数会被保存在一个类似数组的arguments对象中。在函数内,你可以按如下方式找出传入的引数:

arguments[i]

  • 其中i是引数的序数编号,以0开始
  • 第一个传来的参数会是arguments[0]
  • 参数的数量由arguments.length表示

例如,设想有一个用来连接字符串的函数。唯一事先确定的参数是在连接后的字符串中用来分隔各个连接部分的字符(译注:比如例子里的分号“;”)。该函数定义如下:

代码语言:javascript
复制
function myConcat(separator) {
   var result = "", // initialize list
       i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}

你可以给这个函数传递任意数量的参数,它会将各个参数连接成一个字符串“列表”:

代码语言:javascript
复制
// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");

// returns "elephant; giraffe; lion; cheetah; "
myConcat("; ", "elephant", "giraffe", "lion", "cheetah");

// returns "sage. basil. oregano. pepper. parsley. "
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

注意

  • arguments 变量只是 “类数组对象”,并不是一个数组
  • 称其为类数组对象是说它有一个索引编号和Length属性
  • 它并不拥有全部的Array对象的操作方法
函数参数

两个新的类型的参数:

  • 默认参数(default parameters)
  • 剩余参数(rest parameters)
默认参数

在JavaScript中,函数参数的默认值是undefined

代码语言:javascript
复制
function multiply(a, b) {
  b = typeof b !== 'undefined' ?  b : 1;

  return a*b;
}

multiply(5); // 5

调用函数时没有实参传递给b,那么它的值就是undefined,于是计算a*b得到、函数返回的是 NaN

剩余参数

剩余参数语法允许将不确定数量的参数表示为数组

代码语言:javascript
复制
function multiply(multiplier, ...theArgs) {
  return theArgs.map(x => multiplier * x);
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
箭头函数

箭头函数表达式(也称胖箭头函数, fat arrow function)具有较短的语法相比函数表达式和词法绑定此值。箭头函数总是匿名的。

有两个因素会影响介绍箭头函数:

  • 更简洁的函数
  • this
更简洁的函数
代码语言:javascript
复制
var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];
var a2 = a.map(function(s){ return s.length });
var a3 = a.map( s => s.length );
this

在箭头函数出现之前,每一个新函数都重新定义了自己的this值(在严格模式下,一个新的对象在构造函数里是未定义的,通过上下文对象调用的函数被称为“对象方法”等)

代码语言:javascript
复制
function Person() {
  // The Person() constructor defines `this` as itself.
  this.age = 0;

  setInterval(function growUp() {
    // In nonstrict mode, the growUp() function defines `this` 
    // as the global object, which is different from the `this`
    // defined by the Person() constructor.
    this.age++;
  }, 1000);
}
var p = new Person();

在ECMAScript 3/5里,通过把this的值赋值给一个变量可以修复这个问题

代码语言:javascript
复制
function Person() {
  var self = this; // Some choose `that` instead of `self`. 
                   // Choose one and be consistent.
  self.age = 0;

  setInterval(function growUp() {
    // The callback refers to the `self` variable of which
    // the value is the expected object.
    self.age++;
  }, 1000);
}

另外,创建一个约束函数(bound function)可以使得this值被正确传递给growUp()函数

箭头功能捕捉闭包上下文的this值,所以下面的代码工作正常

代码语言:javascript
复制
function Person(){
  this.age = 0;
  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}
var p = new Person();

ok~就这样

Last modification:May 13th, 2018 at 12:21 am

© The copyright belongs to the author

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 闭包
  • 使用arguments对象
  • 函数参数
  • 默认参数
  • 剩余参数
  • 箭头函数
    • 更简洁的函数
    • this
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档