本文是 重温基础 系列文章的第四篇。
今日感觉:常怀感恩之心,对人对己。前端
系列目录:git
本章节复习的是JS中的基础组件之一,函数,用来复用特定执行逻辑。github
定义函数有两种方法:函数声明 和 函数表达式 :segmentfault
也成为函数声明,一般格式为:数组
function f (a){ return a + 1; }
解释:这里声明一个函数 f
,并传入一个参数 a
,当函数执行之后,经过 return
关键字返回了 a+1
的值。 安全
参数:
当传入的参数是一个数字/字符串等具体的值的时候,若参数的值被改变,不会影响到全局或调用函数。
但若是参数是个对象,若函数内改变的这个参数的属性,则函数外部的这个参数原始的值会被修改。微信
var leo = { age:20 } function f(obj){ obj.age = 15; obj.name = 'leo'; } f(leo); console.log(leo); //{age: 15, name: "leo"}
经过定义一个匿名的函数,来赋值给一个变量,经过这个变量来调用这个函数。闭包
var f = function (a){ return a + 1; }
可是函数表达式也能够提供函数名,用于函数内部调用,并指代自己,也能够做为调试器堆栈跟踪中识别该函数。ide
var f = function g(a){ return n < 2 ? 1 : a*g(a-1); }
另外,函数表达式声明能够用来根据不一样条件,来定义一个函数:函数
var f; if(a == 1){ f = function (){ return 'when a == 1'; } }else { f = function (){ return 'when a != 1'; } }
函数定义完成后不会自动执行,须要咱们经过函数名称来调用,才能真正执行:
var f = function (){ console.log('ok'); } f(); // 'ok'
另外,函数也能够调用自身,这就是递归过程:
function f (n){ if( n==0 || n==1) { return 1; }else { return n * f(n-1); } } // 三目运算 function f (n){ return (n==0 || n==1)?1: n*f(n-1); }
因为函数只在函数的内部有定义,因此函数内部定义的变量在函数外部不能访问,函数内部就是这个函数的做用域。
当一个父级函数内,还定义了一个子级函数,则这个子级函数能够访问父级函数定义的变量。
// 全局做用域 global scope var a = 1, b = 2; function f (){ return a + b; } f(); // 3 function g(){ var a1 = 'leo', b1 = 'pingan'; function hi (){ return a1 + '和' + b1 } return hi(); } g(); // 'leo和pingan'
闭包是 JavaScript 中最强大的特性之一,而且JS容许函数嵌套。
在一个函数内部在嵌套一个函数,而嵌套的这个函数对外面的函数是私有的,则造成一个闭包,闭包是一个能够本身拥有独立的环境和变量的表达式,一般是函数。
理解一下,前面说的内部函数能够调用外部函数的变量和方法,那么能够这么理解:闭包的函数继承了父级容器函数的参数和变量,即内部函数包含外部函数的做用域。
总结一下:
function f(a) { function g(b){ return a + b; } return g; } var a1 = f(5); // ƒ g(b){ return a + b; } var a2 = a1(6); // 11 var a3 = f(5)(6); // 11
闭包能够给内部函数的变量提供必定的安全保障。
另外,闭包还有复杂的用法:
var f = function (name){ var age ; return { setName : function (newName){ name = newName; }, getName : function (){ return name; }, getAge : function (){ return age; }, setAge : function (newAge){ age = newAge; } } } var leo = f('leo'); leo.setName('pingan'); leo.setAge(20); leo.getName(); // 'pingan' leo.getAge(); // 20
在同一个闭包做用域下若参数或变量名相同,产生冲突,则优先使用做用域最近:
function f(){ var a = 1; function g(a){ return a + 1; } return g; } f()(3); // 4
函数的实际参数会被保存在一个类数组对象 arguments
对象中,经过索引访问具体的参数:
var a = arguments[i]
arguments
的索引从0开始,也有arguments.length
属性获取长度。
当咱们不知道参数的数量的时候,能够使用arguments.length
来获取实际传入参数的数量,再用arguments
对象来获取每一个参数。
例如:
// 拼接全部参数为一个字符串 // 参数 s 为分隔符 function f( s ){ var text = ''; for(var i = 0;i<= arguments.length; i++){ text += arguments[i] + s ; } return text; } f('--','leo','pingan','robin'); // "----leo--pingan--robin--undefined--" f('**','leo','pingan','robin'); // "****leo**pingan**robin**undefined**"
ES6开始,新增两个类型的参数:默认参数和剩余参数:
若函数没有传入参数,则参数默认值为undefined
,一般设置参数默认值是这样作的:
// 没有设置默认值 function f(a, b){ b = b ? b : 1; return a * b; } f(2,3); // 6 f(2); // 2 // 设置默认值 function f(a, b = 1){ return a * b; } f(2,3); // 6 f(2); // 2
能够将参数中不肯定数量的参数表示成数组,以下:
function f (a, ...b){ console.log(a, b); } f(1,2,3,4); // a => 1 b => [2, 3, 4]
函数箭头表达式是ES6新增的函数表达式的语法,也叫胖箭头函数,变化:更简洁的函数和this
。
// 有1个参数 let f = v => v; // 等同于 let f = function (v){return v}; // 有多个参数 let f = (v, i) => {return v + i}; // 等同于 let f = function (v, i){return v + i}; // 没参数 let f = () => 1; // 等同于 let f = function (){return 1}; let arr = [1,2,3,4]; arr.map(ele => ele + 1); // [2, 3, 4, 5]
注意这几点:
1. 箭头函数内的`this`老是指向**定义时所在的对象**,而不是调用时。 2. 箭头函数不能当作**构造函数**,即不能用`new`命令,不然报错。 3. 箭头函数不存在`arguments`对象,即不能使用,能够使用`rest`参数代替。 4. 箭头函数不能使用`yield`命令,即不能用做Generator函数。
一个简单的例子:
function Person(){ this.age = 0; setInterval(() => { this.age++; }, 1000); } var p = new Person(); // 定时器一直在执行 p的值一直变化
本部份内容到这结束
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推荐 | https://github.com/pingan8787... |
JS小册 | js.pingan8787.com |
欢迎关注微信公众号【前端自习课】天天早晨,与您一块儿学习一篇优秀的前端技术博文 .