JS 之 操作 Function 函数

目录

一、函数的声明

1. function关键字

2. 函数表达式

3. 区别 

01 - 语法不同

02 - JavaScript创建函数的时机不同:JS高级 之 JavaScript的运行原理

二、箭头函数

1. 箭头函数的写法

01 - 普通写法

02 - forEach中使用

03 - setTimeout中使用 

2. 箭头函数的编写优化

优化一 : 如果只有一个参数()可以省略

优化二 : 如果函数执行体中只有一行代码, 那么可以省略大括号

优化三 :如果函数执行体中只有一行代码时,表达式的结果会作为函数的返回值

优化四 : 如果函数执行体只有返回一个对象, 那么需要给这个对象加上 ( )

三、头等函数 First-class Function(头等函数) | MDN

1. 将函数赋值给变量

2. 函数作为函数参数

3. 函数作为函数返回值

四、立即执行函数 

1. 栗子

2. 返回值 

3. 编写方式 

4. 立即执行

五、函数的属性 

1. 添加自定义属性

2. name属性

01 - 栗子

02 - 应用 

3. length属性

1. 正常情况

2. 不正常情况

        01 - 没有写形参

        02 - 写了剩余参数

        03 - 写了默认值 

六、函数的arguments

1. 遍历arguments 

01 - 普通for循环

02 - for...of...

2. 将arguments转成数组

00 - 方式零 : 循环逐个push

01 - 方式一 : ... 展开运算符

02 - 方式二 : Array.from

03 - 方式三 : slice

3. 箭头函数中不绑定argements

七、函数的剩余参数

1. 栗子

2. 剩余参数与arguments的区别

八、纯函数

敬请期待~


一、函数的声明

1. function关键字

function sayHello() {
  console.log("Hello!")
}

2. 函数表达式

const sayHello = function () {
  console.log('Hello!');
};

3. 区别 

01 - 语法不同

  • 函数声明:在主代码流中声明为单独的语句的函数
  • 函数表达式:在一个表达式中或另一个语法结构中创建的函数

02 - JavaScript创建函数的时机不同:JS高级 之 JavaScript的运行原理

  •  函数声明 : 在函数声明被定义之前,它就可以被调用
foo() // 可以被使用
function foo() {
  console.log("foo函数被执行了~")
}
  • 函数表达式 : 是在代码执行到达时被创建,并且仅从那一刻起可用。
bar(); // TypeError: bar is not a function
var bar = function () {
  console.log('bar函数被执行了~');
};

二、箭头函数

箭头函数是ES6之后增加的一种编写函数的方法,并且它比函数表达式要更加简洁

  • 箭头函数不会绑定this、arguments属性
  • 箭头函数不能作为构造函数来使用(不能和new一起来使用,会抛出错误)

1. 箭头函数的写法

01 - 普通写法

<script>
  function foo() {}
  const foo1 = function (name, age) {
    console.log(name, age);
  };
  // 箭头函数写法
  const foo2 = (name, age) => {
    console.log(name, age);
  };
</script>

02 - forEach中使用

<script>
  const arr = [1, 2, 3, 4];
  arr.forEach((item) => {
    console.log(item, this);
  });
</script>

03 - setTimeout中使用 

<script>
  setTimeout(() => {
    const arr = [1, 2, 3, 4];
    arr.forEach((item) => {
      console.log(item);
    });
  }, 1000);
</script>

2. 箭头函数的编写优化

优化一 : 如果只有一个参数()可以省略

<script>
  const arr = [1, 2, 3, 4];
  // 因为只使用了一个参数,这里的括号可以省略
  arr.forEach(item => {
    console.log(item);
  });
</script>

优化二 : 如果函数执行体中只有一行代码, 那么可以省略大括号

<script>
  const arr = [1, 2, 3, 4];
  // 因为函数体中只有一行代码,可以把{}省略
  arr.forEach(item => console.log(item))
</script>

优化三 :如果函数执行体中只有一行代码时,表达式的结果会作为函数的返回值

<script>
  const arr = [1, 2, 3, 4];
  // 因为函数体中只有一行代码,可以把{}省略
  const res = arr.filter((item) => item % 2 === 0);
  console.log(res); //[2,4]
</script>

优化四 : 如果函数执行体只有返回一个对象, 那么需要给这个对象加上 ( )

<script>
  const arr = [1, 2, 3, 4];
  // 代表返回这个{name:'star'}对象
  const tempArr = arr.map(item => ({name:'star'}))
  console.log(tempArr); // [{name: 'star'},{name: 'star'},{name: 'star'},{name: 'star'}]
</script>

三、头等函数 First-class Function(头等函数) | MDN

头等函数(first-class function;第一级函数)是指在程序设计语言中,函数被当作头等公民。

头等函数具有以下三点特征:

  • 将函数赋值给变量
  • 函数作为函数参数
  • 函数作为函数返回值

通常我们对作为头等公民的编程方式,称之为函数式编程

  • JavaScript就是符合函数式编程的语言,这个也是JavaScript的一大特点

1. 将函数赋值给变量

// 函数可以被赋值给变量(函数表达式写法)
const foo1 = function() {
  console.log("foo1函数被执行~")
}

2. 函数作为函数参数

const foo1 = function () {
  console.log('foo1函数被执行~');
};

// 函数可以另外一个函数的参数
function bar(fn) {
  console.log('fn:', fn);
  fn();
}
bar(foo1);

3. 函数作为函数返回值

//函数作为另外一个函数的返回值
function sayHello() {
  function hi() {
    console.log("hi kobe")
  }
  // 1. 把函数返回出去了
  return hi
}
// 2. 接受被返回的参数
var fn = sayHello()
fn()

四、立即执行函数 

立即执行函数 : Immediately-Invoked Function Expression(IIFE 立即调用函数表达式)

  • 表达的含义是一个函数定义完后被立即执行
  • 第一部分是定义了一个匿名函数,这个函数有自己独立的作用域。
  • 第二部分是后面的(),表示这个函数被执行了
  • 会创建一个独立的执行上下文环境,可以避免外界访问或修改内部的变量 

1. 栗子

<script>
  (function () {
    console.log('代码执行了,立即执行函数会立刻执行,不管在什么位置');
  })();
</script>

2. 返回值 

// 立即执行函数可以通过return,让外部访问内部的变量
const { getNum, setNum } = (function () {
  let num = 123;
  function getNum() {
    return num;
  }
  function setNum(info) {
    num = info;
  }
  // 返回函数,让外界可以操纵内部的变量
  return {
    getNum,
    setNum
  };
})();
console.log(getNum()); // 123
setNum(456);
console.log(getNum()); // 456

3. 编写方式 

// 写法一 :  ()在外面,常用
(function () {
  console.log('我是立即执行函数');
})();

// 写法二 :  ()在里面,不常用
(function () {
  console.log('我也是立即执行函数,two');
}());

4. 立即执行

注意 : 立即执行函数马上就会被调用

const obj = {
  foo: (function () {
    console.log('我一上来就被调用了,不用等待,不用彷徨');
    return function () {
      console.log('我是立即执行函数');
    };
  })()
};

setTimeout(() => {
  // 拿的直接就是返回的函数
  obj.foo();
}, 1000);

五、函数的属性 

JavaScript中函数也是一个对象,那么对象中就可以有属性和方法

1. 添加自定义属性

function foo() {

}
// 自定义属性
foo.message = "Hello Foo"
console.log(foo.message) // "Hello Foo"

2. name属性

01 - 栗子

function foo() {

}
const bar = function() {
  
}
// 默认函数对象中已经有自己的属性
console.log(foo.name) // foo
console.log(bar.name) // bar

02 - 应用 

function foo(num1, num2) {
  console.log('foo', this, num1, num2); // foo {} 123 321
}
function bar(str1, str2) {
  console.log('bar', this, str1, str2); // bar String {'放屁'} abc cba
}

const arr = [foo, bar];
for (const fn of arr) {
  // 根据函数名,给函数绑定不同的this
  switch (fn.name) {
    case 'foo':
      fn.call({}, 123, 321);
      break;
    case 'bar':
      fn.apply('放屁', ['abc', 'cba']);
      break;
  }
}

3. length属性

函数的length属性 : 代表 => 参数的个数

1. 正常情况

function foo(a, b, c) {

}
const bar = function (m, n) {

};

console.log(foo.length); // 3
console.log(bar.length); // 2

2. 不正常情况

        01 - 没有写形参

function test() {
  
}
test(111, 222, 333);
// 没写形参的拿不到length属性,虽然会传入arguments中
console.log(test.length); // 0  

        02 - 写了剩余参数

function foo(a, b, c, ...args) {

}
// 剩余参数不会包括在length中
console.log(foo.length); // 3,所以还是3

        03 - 写了默认值 

// 有默认参数时,length属性只会计算默认参数之前的参数

// 第一种情况
function foo(a = 1, b, c) {}
console.log(foo.length); // 0,莫得

// 第二种情况
function bar(a, b = 1, c) {}
console.log(bar.length); // 1,只有a算在了里面

// 第三种情况
function baz(a, b, c = 1) {}
console.log(baz.length); // 2,只有a,b算在了里面

六、函数的arguments

arguments 是一个 对应于 传递给函数的参数 的 类数组(array-like)对象

array-like意味着它不是一个数组类型,而是一个对象类型

  • 但是它却拥有数组的一些特性,比如说length,比如可以通过index索引来访问
function foo(m, n) {
  // arguments 类似数组对象
  console.log(arguments);
  // 通过索引获取内容
  console.log(arguments[0]); // 10
  console.log(arguments[1]); // 25
  console.log(arguments[2]); // 32
  console.log(arguments[3]); // 41
}

foo(10, 25, 32, 41);
  • 但是它却没有数组的一些方法,比如filter、map等
// 报错

function foo(m, n) {
  // arguments.forEach is not a function
  arguments.forEach((item) => {
    console.log(item);
  });
}

foo(10, 25, 32, 41);

1. 遍历arguments 

01 - 普通for循环

function foo(m, n) {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]); // 10, 25, 32, 41
  } 
}

foo(10, 25, 32, 41);

02 - for...of...

function foo(m, n) {
  for (var arg of arguments) {
    console.log(arg); // 10, 25, 32, 41
  }
}

foo(10, 25, 32, 41);

2. 将arguments转成数组

00 - 方式零 : 循环逐个push

function foo(m, n) {
  const newArguments = []
  // 循环推入
  for (let arg of arguments) {
    newArguments.push(arg)
  }
}

foo(10, 25, 32, 41);

01 - 方式一 : ... 展开运算符

function foo(m, n) {
  // 展开运算符,使其在数组中展开
  const newArguments = [...arguments];
  console.log(newArguments); // [10, 25, 32, 41]
}

foo(10, 25, 32, 41);

02 - 方式二 : Array.from

function foo(m, n) {
  // 调用方法
  const newArguments = Array.from(arguments);
  console.log(newArguments); // [10, 25, 32, 41]
}

foo(10, 25, 32, 41);

03 - 方式三 : slice

function foo(m, n) {
  // 1. 拿到数组中的slice方法,使用call显示绑定调用
  const newArguments = [].slice.call(arguments);
  console.log(newArguments); // [10, 25, 32, 41]

  // 2. 通过Array的显示原型拿到slice方法,使用apply显示绑定调用
  const newArguments2 = Array.prototype.slice.apply(arguments);
  console.log(newArguments2); // [10, 25, 32, 41]
}

foo(10, 25, 32, 41);

3. 箭头函数中不绑定argements

箭头函数是不绑定arguments的,所以在箭头函数中使用arguments会去上层作用域查找

// 1.箭头函数不绑定arguments
const bar = () => {
  console.log(arguments) // 报错,上层作用域中也没有arguments
}

bar(11, 22, 33)


// 2.函数的嵌套箭头函数
function foo() {
  // 找到的是foo中的arguments
  const bar = () => {
    console.log(arguments)
  }
  bar()
}
foo(111, 222)

七、函数的剩余参数

ES6中引用了rest parameter,可以将不定数量的参数放入到一个数组中

  • 如果最后一个参数是 ... 为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组
  • 剩余参数必须放到最后一个位置,否则会报错

1. 栗子

// 剩余参数: rest parameters
function foo(num1, num2, ...args) {
  // otherNums数组
  console.log(args) // [111, 222, 333]
}
foo(20, 30, 111, 222, 333)

2. 剩余参数与arguments的区别

  • arguments 对象包含了传给函数的所有实参,剩余参数只包含那些没有对应形参的实参
  • arguments对象不是一个真正的数组,剩余参数是一个真正的数组
  • arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,剩余参数是ES6中提供并且希望以此 来替代arguments的

八、纯函数

敬请期待~

猜你喜欢

转载自blog.csdn.net/a15297701931/article/details/125831055
今日推荐