• 这些 function 的细节你都知道吗?


    我正在参加「掘金·启航计划」

    大家好,我是 Lvzl, 一个三年工作经验的前端小菜鸡,在掘金平台分享一些 平时学习的感悟 & 实际项目场景 的文章。

    本文主要内容:详细聊聊 JavaScript 函数。

    函数概述

    函数的声明语句

    function 命令声明的代码区块就是一个函数。function 命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数,函数体放在大括号里面。

    以下面的例子来说:hello 是函数名、有一个参数、函数体是 console.log(a)

    1. function hello(a) {
    2. console.log(a)
    3. }
    4. // 调用:
    5. hello('hello world')
    6. 复制代码

    函数表达式

    采用变量赋值的写法:将一个匿名函数赋值给变量。这时,这个匿名函数又称函数表达式。

    1. const hello = function (a) {
    2. console.log(a)
    3. }
    4. // 将一个具名函数赋值给变量。
    5. const hello = function fn(a) {
    6. console.log(a)
    7. console.log(fn) // fn();
    8. console.log(fn === hello) // true;
    9. }
    10. console.log(fn) // ReferenceError: fn is not defined;
    11. 复制代码

    具名函数fnhello是同一个函数,但是作用范围不一致,fn只能在函数体内使用,相当于函数的一个局部变量,hello可在函数内部,外部调用。

    Function 构造函数

    可以传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。

    1. const add = new Function('x', 'y', 'return x + y')
    2. //等同于
    3. function add(x, y) {
    4. return x + y
    5. }
    6. 复制代码

    Function构造函数可以不使用new命令,返回结果完全一样。

    函数的返回值 return

    return 只能出现在函数体内。

    1. 一个函数中可以有多个return语句。
    2. return后没有任何返回值,(返回值为 undefined)代表直接提出函数执行,return之后除了在 finally中的代码,都不会再执行。如下图:

    1. return可以返回任何数据类型的数据。
    2. 如果函数调用时在前面加上了new前缀,且返回值不是一个对象或者没有返回值,则返回this(该新对象),如下图:

    函数调用

    函数调用模式

    使用函数调用模式调用函数时,非严格模式下,this被绑定到全局对象;在严格模式(use strict;)下,thisundefined

    非严格模式: 

    严格模式:

    方法调用模式

    当一个函数被保存在对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。如果 调用表达式包含一个提取属性的动作,那么它就是被当做一个方法来调用。

    1. var p = {
    2. a: 1,
    3. fn: function () {
    4. this.a = 2
    5. }
    6. }
    7. console.log(p.a) // 1
    8. p.fn()
    9. console.log(p.a) // 2
    10. 复制代码

    构造器调用模式

    如果函数或者方法调用之前带有关键字 new,它就构成构造函数调用。

    • 如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内。
    • 如果构造函数没有形参,JavaScript 构造函数调用的语法是允许省略实参列表和圆括号的。凡是没有形参的构造函数调 用都可以省略圆括号。
    1. const o = new Object()
    2. // 等价于
    3. const o = new Object
    4. 复制代码

    间接调用模式

    JavaScript 中函数也是对象,函数对象也可以包含方法。call 和 apply方法可以用来间接地调用函数。 这两个方法都允许显式指定调用所需的this值,也就是说,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。两个方法都可以指定调用的实参。

    • call方法使用它自有的实参列表作为函数的实参。
    • apply法则要求以数组的形式传入参数。
    1. const obj = {}
    2. function sum(x, y) {
    3. return x + y
    4. }
    5. console.log(sum.call(obj, 1, 2)) //3
    6. console.log(sum.apply(obj, [1, 2])) //3
    7. 复制代码

    函数参数

    JavaScript是弱类型语言,函数定义时未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查。实际上JavaScript函数调用甚至不检查传入形参的个数。

    参数个数

    1.当实参(函数被调用时掺入的实际参数值)比函数声明指定的形参(函数定义时的参数列表)个数要少,剩下的形参都将设置为 undefined 值。

    1. function add(x, y) {
    2. return x + y // x:1, y: undefined
    3. }
    4. add(1)
    5. 复制代码

    2.当实参比形参个数要多时,剩下的实参没有办法直接获得,需要使用 arguments 对象来获取。arguments是个类数组,有数组的部分属性,如length,可以通过索引去获取对应的参数列表。

    1. function add(x, y) {
    2. console.log(arguments)
    3. return x + y
    4. }
    5. add(1, 2, 3, 4, 5)
    6. // Arguments(5) [1, 2, 3, 4, 5, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    7. 复制代码

    3.函数定义时也可以不给形参,到时直接通过arguments[索引]去获取实参。

    同名形参

    在非严格模式下,函数中可以出现同名形参,且只能访问最后出现的该名称的形参。

    1. function add(x, x, x) {
    2. return x
    3. }
    4. console.log(add(1, 2, 3)) // 3
    5. // 严格模式编译报错。
    6. 复制代码

    函数重载

    Java语言中,函数的重载是这样定义的:方法名相同,参数的个数或者类型必须不同。

    JavaScript函数不能像Java上那样实现重载。只能通过检查传入函数中参数的类型和数量并作出不同的反应,来模仿方法的重载。

    1. function doAdd() {
    2. if (arguments.length == 1) {
    3. alert(arguments[0] + 10)
    4. } else if (arguments.length == 2) {
    5. alert(arguments[0] + arguments[1])
    6. }
    7. }
    8. 复制代码

    参数传递

    值传递:对于基本数据类型的参数传递。比如StringNumberBoolean等。在向参数传递基本类型的值时,被传递的值会被复制到一个局部变量(命名参数或 arguments对象的一个元素)。

    1. function addTen(num) {
    2. num += 10
    3. return num
    4. }
    5. var count = 20
    6. var result = addTen(count)
    7. console.log(count) //20,没有变化
    8. console.log(result) //30
    9. 复制代码

    引用传递:参数为引用类型的数据时(Object、Array、......),传递过去的是引用数据的内存地址。会把这个地址复制给一个局部变量,因此这个局部变量的变化会直接改变指向该内存地址的引用数据。

    1. function setName(obj) {
    2. //obj 在函数内部是一个局部变量
    3. obj.name = 'test'
    4. }
    5. var person = new Object()
    6. setName(person)
    7. console.log(person.name) //'test'
    8. 复制代码

    函数属性和方法

    函数是 JavaScript 中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样。甚至可以用Function构造函数来创建新的函数对象。

    属性

    • length:arguments对象的length属性表示实参个数,而参数的length属性则表示形参个数。 

    • prototype:每一个函数都有一个prototype属性,这个属性指向了一个对象的引用,这个对象叫做原型对象(prototype object)。每一个函数都包含不同的原型对象。将函数用作构造函数时,新创建的对象会从原型对象上继承属性。
    1. function fn() {}
    2. var obj = new fn()
    3. fn.prototype.a = 1
    4. console.log(obj.a) //1
    5. 复制代码
    • name:函数定义了一个非标准的name属性,通过这个属性可以访问到给定函数指定的名字,这个属性的值永远等于跟在function关键字后面的标识符,匿名函数的 name属性为空。

    方法

    每一个函数都包含两个非继承而来的方法:applycall方法。这两个方法的用途都是在特定的作用域中调用函数。

    调用方式:

    • func.apply(作用域对象, [a,b,c]);
    • func.call(作用域对象, a,b,c);

    以对象 o 的方法来调用函数 f(),可以使用 call()和 apply():

    1. window.color = "red";
    2. var o = {color: "blue"};
    3. function sayColor(){
    4.   console.log(this.color);
    5. }
    6. sayColor();      //red
    7. sayColor.call(this);  //red
    8. sayColor.call(window); //red
    9. sayColor.call(o);   //blue
    10. sayColor.call(o)
    11. // 等价于:
    12. o.sayColor = sayColor;
    13. o.sayColor();  //blue
    14. delete o.sayColor;
    15. 复制代码

    在非严格模式下,使用函数的callapply方法时,nullundefined值会被转换为全局对象。而在严格模式下,函数的this值始终是指定的值。

    应用:

    找出数组中最大元素。

    1. const a = [10, 2, 4, 15, 9]
    2. Math.max.apply(null, a) // 15
    3. // es6
    4. Math.max(...a)
    5. 复制代码

    将类数组转成真正的数组。

    1. var add = function(x,y){
    2. console.log(Array.prototype.slice.apply(arguments));
    3. // es6
    4. Array.from(arguments)
    5. };
    6. add(1,2); // [1, 2]
    7. 复制代码

    将一个数组的值 push 到另一个数组中。

    1. var a = []
    2. Array.prototype.push.apply(a, [1, 2, 3])
    3. // es6
    4. a.push(...[1,2,3])
    5. console.log(a) //[1,2,3]
    6. 复制代码

    bind的主要作用就是将函数绑定到某个对象。当在函数f()上调用bind()方法并传入一个对象 o 作为参数,这个方法将返回一个新的函数。以函数调用的方式调用新的函数将会把原始的函数 f()当做 o 的方法来调用,传入新函数的任何实参都讲传入原始函数。bind方法不仅是将函数绑定到一个对象,它还附带一些其他应用:除了第一个实参之外,传入bind的实参也会绑定到this,这个附带的应用是一种常见的函数式编程技术,有时也被称为柯里化(currying)

    1. function getConfig(colors, size, otherOptions) {
    2. console.log(colors, size, otherOptions)
    3. }
    4. var defaultConfig = getConfig.bind(null, '#c00', '1024*768')
    5. defaultConfig('123') //'#c00 1024*768 123'
    6. defaultConfig('456') //'#c00 1024*768 456'

     

     给大家推荐一个实用面试题库

    1、前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

  • 相关阅读:
    Kubernetes 文档 / 概念 / 服务、负载均衡和联网 / 网络策略
    RabbitMQ中CorrelationData 与DeliveryTag的区别
    Stream流详解
    【MongoDB】MongoExport如何过滤数据导出
    怎么恢复永久删除的文件?这3个方法很实用!
    量化INT8模型报错记录及解决方案
    1.3数据结构之复杂度 力扣题目移除元素
    Microsoft Dynamics 365 CE 扩展定制 - 5. 外部集成
    Mirror 镜像站点的使用
    mysql [Err] 1118 - Row size too large (> 8126).
  • 原文地址:https://blog.csdn.net/weixin_42981560/article/details/127656391