函数
总结
一、 函数的基本介绍
函数的三要素:函数的功能,函数的参数,函数的返回值。
DYR原则:全称为Don’t repeat yourself 翻译不重复你自己。
二、 函数的声明方式
- 字面量声明函数:
使用function来创建函数,
Function 函数名(形式参数){
//函数体
}
函数名:就是我们调用函数时需要书写的标识符
形式参数:简称形参,是调用函数时需要接收的参数
实际参数:简称实参,是调用函数时实际传递过去的参数
示例:
function test(name){
console.log("Hello,"+name);
}
test("xiejie");//Hello,xiejie
- 函数表达式声明函数:
使用函数表达式来进行声明,
Let 变量 = function( ){
//函数体
}
示例:
let test = function(name){
console.log("Hello,"+name);
}
test("xiejie");//Hello,xiejie
注意:这里的变量并不是函数的名字,一般来讲,我们都是将一个匿 名函数赋值给一个变量,然后通过这个变量来对函数进行调用。
也可以将一个带有名字的函数赋值给一个变量,这样的声明方式被称之为命名式函数表达式;
示例:
Let test = function saySth(name){
console.log("Hello,"+name); }
test("xiejie");//Hello,xiejie
注意:虽然这种方式的函数表达式拥有函数名,但是调用的时候还是必须要通过变量名来调用,而不能够使用函数名来进行调用。
- 3. 构造器声明函数:
使用构造器来声明函数,又被称为通过对象的方式来声明函数
Let 变量 = new Function ("参数" ,"参数" ,"函数体");
示例:
Let test = new Function("name","console.log('Hello,'+name)"); test("xiejie");//Hello,xiejie
虽然通过这种方式也能够创建出函数,并且调用,但是并不推荐使用这种方式来创建函数。因为这样会导致JS解释器需要解析两次代码。先要解析这个表达式,然后又要解析字符串,效率很低,并且这样将函数体全部书写在一个字符串里面的书写方式对我们程序员也非常的不友好,所以这种方式作为了解即可。
三、 函数的调用
函数调用:就是写上函数名或者变量名,后面加上一对大括号即可。需要注意的是,-般来讲函数表示的是- .一个动作,所以在给函数命名的时候,一般都是以动词居多。
还一个地方需要注意,那就是如果要调用函数,那么就必须要有括号。这个括号要么在函数名后面,要么在变量名后面,这样才能够将调用函数后的执行结果返回。如果缺少了括号,那就只是引用函数本身。
示例:
let test = function(){
console. log("Hello");
}
Let i = test;//没有调用函数,而是将test函数赋值给了i
i();//Hello
四、 函数的返回值
函数的返回值的关键字为return,代表要从函数体内部返回给外部的值。
示例:
let test = function(){
return "Hello";
}
let i = test(); console.log(i);//Hello
即使不写return,函数自身也会返回值undefined。
示例:
let test = function(){
return 1;
console.log("Hello");
}
let i = test();
console.log(i);//1
return关键字只能返回一个值,如果想要返回多个值,可以返回一个数组。
示例:
//1-60 的安全数 7的倍数或者以7结尾
let test = function(){
let arr = [];
for(let i=1;i<=60;i++)
{ if(i%10==7 || i%7==0) {
arr.push(i);
}
} return arr;
}
console.log(test());
//[ 7, 14, 17, 21, 27, 28, 35, 37, 42, 47, 49, 56, 57 ]
五、 函数的参数
函数的参数可以分为两种,一种是实际参数,另外一种是形式参数。
示例:
function test(let i){
console.log(i);
}
test(5);
//SyntaxError: Unexpected identifier
1、 参数名可以重复,同名的参数取最后一个参数:
示例:
function test(x,x){
console.log(x);
}
test(3,5);//5
2、 即使函数声明了参数,调用时也可以不传递参数值
示例:
function test(x){
console.log(x);
}
test();//undefined
3、 调用函数是可以传递若干个参数值给函数,而不用管函数声明时有几个参数。
示例:
function test(x){
console.log(x);//1
}
test(1,2,3);
实际上,当一个函数要被执行的时候,系统会在执行函数体代码前做一些初始化工作, 其中之一就是为函数创建一个arguments的伪数组对象。 这个伪数组对象将包含调用函数时传递的所有的实际参数。因此,arguments的主 要用途是就是用于保存传入到函数的实际参数的。
示例:
function test(x){
for(let i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
}
test(1,2,3);
// 1 // 2 // 3
所谓伪数组对象,就是长得像数组的对象,但是并不是真的数组。
示例:
function test(x){
arguments.push(100);// 针对伪数组对象使用数组的方法
}
test(1,2,3);
//TypeError: arguments.push is not a function
不定参数:
不定参数是从ES6开始新添加的功能,在最后-个形式参数前面添加3个点,会将所有的实参放入到-一个数组里面,
示例:
function test(a,...b){
console.log(a);//1
console.log(b);//[2,3]
}
test(1,2,3);
不定参数就是一个真正的数组,可以使用数组的相关方法
示例:
function test(a,...b){
console.log(a);//1
console.log(b);//[2,3]
b.push(100);
console.log(b);//[ 2, 3, 100 ]
}
test(1,2,3);
注意:不定参数都是放在形式参数的最后面,如果不是放在最后,则会报错。
示例:
function test(...a,b){
console.log(a);
console.log(b);
}
test(1,2,3);
//SyntaxError: Rest parameter must be last formal parameter
默认参数
从ES6开始,书写函数的时候可以给函数的形式参数一个默认值。这样如果在调用函数时没有传递相应的实际参数,就使用默认值。如果传递了相应的实际参数,则使用传过去的参数。
示例:
function test(name = "world"){
console.log("Hello,"+name);
}
test("xiejie");//Hello,xiejie
test();//Hello,world
如果参数是一个数组,要为这个数组设置默认值的话,写法稍微有些不同;
示例:
let fn = function([a = 1,b = 2] = []){
console.log(a,b);
}
fn(); // 1 2 fn([3,4]); // 3 4
对象的方法和数组的方法类似。
六、 函数属性和方法
1、 name属性:表示函数的函数名
function test(){
console.log("Hello");
}
console.log(test.name);//test
可以通过这个name属性来证明函数表达式的变量不是函数名
示例:
let test = function test2(){
console.log("Hello");
}
console.log(test.name);//test2
2、 length属性:表示形式参数的个数。
示例:
let test = function(a,b,c){
console.log("Hello");
}
console.log(test.length);//3
函数名.length与arguments.length的区别。
函数对象的length属性是表示形式参数的个数。
arguments伪数组对象的length属性是调用函数时实际参数的个数。
示例:
let test = function(a,b,c){
console.log(arguments.length);//5
console.log(arguments.callee.length);//3
}
test(1,2,3,4,5);
七、 箭头函数
所谓箭头函数,是从ES6开始新增加的一种声明函数的方式。其最大的特点在于不需要function关键字,取而代之的是使用一个=>来进行表示。
Let 变量 = (形式参数) => {
//函数体
}
示例:
let test = (name) => {
console.log("Hello",name);
}
test("xiejie");//Hello xiejie
箭头函数根据形式参数和函数体的不同,书写方式也会有变化。
示例:
//如果没有参数
let变量=()=> {
//函数体
}
//如果只有一个形参
let变量=形参=>{
//函数体
}
//如果函数体只有一个返回值
Let变量=形参=> express ion
箭头函数有点:比普通函数声明更简洁
只有一个形参就不需要用括号括起来
如果函数体只有一行,就不需要放到一个块中
如果return语句是函数体内唯一的语句,就不需要return关键字
不会把自己的this值绑定到函数上
提升:分为变量提升和函数提升
作用域:作用域一共有3种:全局作用域,函数作用域以及eval作用域
全局作用域:这个是默认的代码运行环境,-旦代码被载入,引擎最先进入的就是这个环境
函数作用域:当进入到一个函数的时候,就会产生一个函数作用域
eval作用域:当调用eval0函数的时候,就会产生一个eval作用域
示例:
let x = 3; function test(){
console.log("Hello");
}
这里我们声明的x以及test()函数就是处于全局作用域里面的。
函数里面访问全局作用域里面的变量
let x = 3; let test = function(){
console.log(x);//3
}
test();
全局作用域里面访问函数作用域里面的变量
示例:
let test = function(){
let x = 3;
}
test(x); //ReferenceError: x is not defined
这里在函数里面声明了变量x,全局里面访问的时候会提示没有定义。
注意在函数里面声明变量时,无论是使用的let还是var,还是说是const, 它们都是属于函数作用域的,外部是无法访问的
变量提升:就是指在使用var关键字进行变量声明的时候,默认会将声明变量的部分提升至
当前作用域的最顶上,但是注意提升的只有变量的声明部分,赋值是不会提升的
还有一点要注意的是,只有var声明的变量才具有这种特性,let或者const不存在变量提升
console.log(i);//undefined
var i = 10; console.log(i);//10
还有-点要注意的是,只有var声明的变量才具有这种特性,let或者const不存在变量提升
console.log(i);//ReferenceError: i is not defined
let i = 10;
如果我们在函数里面声明变量时没有添加关键字,那么默认将会是在全局环境中声明一个变量
let test = function(){
i = 10;
}
test(); console.log(i);//10
函数提升:是指当我们使用字面量方式来声明一个函数的时候,此时函数的声明会提升到当前作用域的最顶端,这意味着我们可以将函数的调用书写到函数的声明之前
test();//Hello!
function test(){
console.log("Hello!");
} /
// test : pointer to test()
// test()
// function test()
// { // console.log("Hello!"); // }
注意:仅仅只有普通函数声明的时候才存在函数提升,如果是使用函数表达式来进行的函数声明,则不存在有函数提升的情况。
还有一-点就是变量提升和函数提升是可以同时存在的。
console.log(test);//undefined
var test = function(){
console.log("Hello!");
}
console.log(test);//[Function: test]