函数的定义与参数
JavaScript 作为函数式语言来理解。
关键概念
函数是第一类对象(一等公民)
函数可以看作是 其他任意类型的 Javascript 对象
函数和其他的数据类型一样,能被变量引用,以字面量形式声明,作为函数参数传递
发现
:musical_note: 在需要调用某函数的位置 定义该函数,能让代码更紧凑、更易懂
术语
一等公民
一般来说,如果某程序设计语言中的一个值可以作为 参数传递
,可以从 子程序中返回
,可以 赋值给变量
,就称为一等公民
二等公民
可以作为 参数传递
,但是不能从子程序中返回,也不能赋值给变量
三等公民
值连作为参数传递都不行(label)
3.1 函数式的不同点
与对象的不同
对象的常见功能
-
对象可通过字面量来创建
{}
var lsObj = {}; 复制代码
-
对象可以赋值给变量、数组项,或其他对象的属性
var lsObj = {}; lsArray.push({}); lsObj.data = {} 复制代码
-
对象可以作为参数传递给函数
function hide(obj){ obj.visibility = false; } hide({}); 复制代码
-
对象可以作为函数的返回值
function returnNewLs(){ return {}; } 复制代码
-
对象能够具有动态创建和分配的属性
var lsObj = {}; lsObj.name = "lisi"; 复制代码
函数是第一类对象
函数拥有对象的所有能力,所以函数可被看作 任意其他类型 的对象
函数也具有对象的功能
-
通过字面量创建
function ninjaFunction(){} 复制代码
-
赋值给变量、数组项或其他对象的属性
var ninjaFunction = function(){}; //为变量赋值一个新函数 ninjaArray.push(function(){}); //向数组中增加一个新函数 ninja.data = function(){}; //给某个对象的属性赋值一个新函数 复制代码
-
作为函数的参数传递
function call(ninjaFunction){ ninjaFunction(); } //新函数作为参数传递给函数 call(function(){}); 复制代码
-
作为函数的返回值
//返回一个新函数 function returnNewNinjaFunction(){ return function(){}; } 复制代码
-
动态创建的属性
//为函数增加一个新属性 var ninjaFunction = function(){}; ninjaFunction.ninja = "Hanzo"; 复制代码
:eight_pointed_black_star: 函数也是对象,函数与对象的不同在于:==函数是可调用的==
:v: 第一类对象的特点之一:能够作为参数传入函数
对于函数来说这个特性表明:将某个函数作为参数传入另一个函数,传入的函数会在将来的某个时刻执行。由此推出 【回调函数】
回调函数
浏览器的回调函数(计时器函数)和我们自定义的回调函数
回调不一定是异步的
浏览器回调
document.body.addEventListener("mousemove",function(){...})
复制代码
自定义的回调
排序方法sort,可以传入一个函数进行排序
var values = [0,3,2,7,1,8];
values.sort(function(value1,value2){
return value1 - value2;
});
复制代码
? 函数式方式 把 函数当作一个 单独实体 来创建,与其他类型一样,创建、作为参数传递和返回。函数显示了一等公民的地位。
function(value1,value2){}
是一个整体,类似 abc
等
3.2 函数作为对象
类似对象,函数也可以添加属性
//对象
var ninja = {};
ninja.name = 'hitsuke';
//函数
var wieldSword = function(){};
wieldSword.swordType = "katana";
复制代码
存储函数
函数的属性作为值
:question: 管理一个元素的所有回调函数集合,相同的回调只存储一次
//存储唯一函数集合
var store = {
nextId : 1,
cache : {},
add : function(fn){
if(!fn.id){
fn.id = this.nextId++;
this.cache[fn.id] = fn;
return true;
}
}
}
function ninja(){}
store.add(ninja); //true ninja.id 存在了
//Object.getOwnPropertyNames(ninja) (6) ["length", "name", "arguments", "caller", "prototype", "id"]
store.add(ninja); //undefined
复制代码
缓存结果
函数的属性作为对象
//计算先前得到的值
function isPrime(value){
if(!isPrime.answers){
isPrime.answers = {}; //创建缓存
}
if(isPrime.answers[value] !== undefined){
return isPrime.answers[value]; //检查缓存的值 并 返回
}
var prime = value !== 0 && value !== 1;
for(var i = 2;i < value; i++){
if(value % i === 0){
prime = false;
break;
}
}
return isPrime.answers[value] = prime; //存储计算的值
}
isPrime(5);
isPrime.answers[5];
复制代码
3.3 函数定义
JavaScript 定义函数的几种方式
-
函数声明和函数表达式
function abc(){} var abc = function(){} 复制代码
-
箭头函数 lambda函数
myArg => myArg * 2 复制代码
-
函数构造函数
new Function('a','b','return a + b') 复制代码
-
生成器函数
//函数退出再进入时,之前的变量值被保存 function* myGen(){ yield 1; } 复制代码
函数声明和函数表达式
//函数声明强制以 function 开头;作为一个单独的JavaScript语句,函数声明必须独立
function samurai(){
return "samurai here";
}
function ninja(){
function hiddenNinja(){
return "ninja here";
}
return hiddenNinja();
}
复制代码
//函数表达式 作为 赋值表达式的右值 、作为其他函数的参数
var myFunc = function(){};
myFunc(function(){
return function(){};
});
复制代码
对于函数声明来说,函数名是强制性的,对于函数表达式来说,函数名是可选的。
立即执行函数
一般包裹在一对括号内:JavaScript解析器必须轻易区分 函数声明和函数表达式的区别。
函数表达式放在括号内,为JavaScript解析器指明:它正在处理一个函数表达式而不是语句。
myFunctionName(3);
//IIFE 立即函数
(function(){})(3)
(function namedFunctionExpression(){})(); //立即调用
//函数表达式作为一元操作符的参数立即调用
//为JS引擎指明 处理的是表达式,而不是语句
+function(){}();
-function(){}();
!function(){}();
~function(){}();
复制代码
箭头函数
箭头函数是函数表达式的简化版
//箭头函数的语法
//箭头函数接收一个参数并返回表达式的值
param => expression
//如果没有参数或多于一个参数,参数列表必须包裹在括号内
//如果只有一个参数,括号不是必须的
var greet = name => "Greeting " + name;
var greet = () => "Greeting";
var greet = (name,age) => "hello " + name + age;
//胖箭头 操作符后面可以是 表达式 也可以是代码块
var greet = name => "Greeting" + name;
var greet = (name,age) => {
return name + age;
}
复制代码
var values = [1,2,3,5,8];
values.sort(function(value1,value2){
return value1 - value2;
});
//箭头函数
values.sort((value1,value2) => value1 - value2);
复制代码
3.4 函数的实参和形参
如果函数的 实参数量 > 形参数量 , 多余的不会分配给形参
如果函数的 实参数量 < 形参数量 , 对应的形参赋值为 undefined
剩余参数
只有函数的最后一个参数才能是剩余参数。
给函数的最后一个形参加上省略号(…)前缀,这个参数就变成了一个 剩余参数的数组 。数组内包含着传入的剩余的参数。
function multiMax(first, ...remainingNumbers){
...
}
复制代码
默认参数
为函数的参数提供一个默认参数
默认参数可以是任意值:数字、字符串、对象、数组、甚至是函数
后面的默认参数 可以引用 前面的默认参数
function performAction(ninja, action){
action = typeof action === "undefined" ? "skulking" : action;
return ninja + " " + action;
}
function performAction(ninja, action = "skulking"){
return ninja + " " + action;
}
function performAction(ninja, action = "skulking", message = ninja + " " + action){
return message;
}
复制代码
typeof 操作符返回一个字符串 用于表明操作数的类型。如果操作数未定义,则返回字符串 "undefined"