zoukankan      html  css  js  c++  java
  • 函数

    函数的概念:

      函数包含一组数据,它们是JavaScript的基础模块单元,用于代码复用、信息隐藏(封装)和组合调用(继承)。

      函数用于指定对象的行为。

      所谓编程,就是将一组需求分解成一组函数与数据结构的技能。

    函数对象:

      对象的角度(__proto__):JavaScript中的函数就是对象。对象是“键/值”对的集合并拥有一个连到原型对象的隐藏连接(这个隐藏连接就是__proto__)。对象字面量产生的对象连接到Object.prototype。函数对象连接到Function.prototype(该原型对象本身连接到Object.prototype)。每个函数在创建时会附加两个隐藏属性:函数的上下文(this:指向window)和实现函数行为的代码注释1

      函数的角度(prototype):每个函数对象在创建时也随机配有一个prototype属性,它的值是一个拥有constructor属性并且值为该函数的对象。这和隐藏连接到Function.prototype完全不同。

       因为函数是对象,所以他们可以像任何其他的值一样被使用。函数可以保存在变量、对象和数组中。函数可以被当做参数传递给其他函数,函数也可以再返回函数。而且,因为函数是对象,所以函数拥有方法(静态方法和动态方法)。

        function fn() {
          // 动态方法,需要new一个实例对象来调用
          this.play = function () {
            console.log('玩耍')
          }
        }
        let f = new fn()
        f.play() // 玩耍
        fn.play() // Uncaught TypeError: fn.play is not a function
    
        // 静态方法,不需要new一个实例,直接调用
        fn.eat = function () {
          console.log('吃饭')
        }
        fn.eat(); // 吃饭

    函数字面量:

      函数对象可以通过函数字面量来创建:

        let add = function fn(a, b) {
          return a + b
        };
    
        console.log(add(10, 20))
        console.log(add(101, 201))

      函数字面量包括4个部分:

        1、保留字function

        2、函数名,就是fn,它可以被省略。函数可以用它的名字来递归地调用自己,这个名字可以被调试器和开发工具用来识别函数。如果没有给函数命名,就是匿名函数

        3、函数的参数,多个参数用逗号分隔。这些参数被定义为函数中的变量。它们不像普通的变量那样被初始化为undefined,而是在函数被调用时初始化为实际提供的参数的值

        4、函数体,函数被调用的时候执行

      函数字面量可以出现在任何允许表达式出现的地方。函数也可以被定义在其他函数中。一个内部函数除了可以访问自己的参数和变量,同时它也能自由访问把它嵌套在其中的复函数的参数与变量(作用域链:内部函数可以访问到外部函数的变量,而外部函数不可以访问内部函数的变量)。通过函数字面量创建的函数对象包含一个连到外部上下文的连接,这就是闭包。

    调用:

      调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数(JavaScript是单线程,当前函数执行完了再去执行下一个函数,就是入栈和出栈的概念)。除了声明时定义的形式参数,每个函数还接收两个附加的参数:this和arguments。参数this在面向对象编程中非常重要,它的值取决于调用的模式。在JavaScript中一共有4中调用模式:方法调用模式、函数调用模式、构造器调用模式、apply调用模式。这些模式在如何初始化关键参数this上存在差异。

      调用运算符就是函数名后面的小括号。小括号里可以有零个或多个用逗号隔开的表达式(表达式:有可能是别的函数运行的结果放在这里当做参数使用,所以这里叫表达式),每个表达式产生一个参数值。每个参数值被赋予函数声明时定义的形式参数名。当实参的个数和形参的个数不一致时,不会导致运行错误。如果实参个数多于形参,超出的实参就相当于没传;如果实参比形参少,那剩下的形参默认为undefined。对参数值不会进行类型检查:任何类型的值都可以被传递给任何参数(JavaScript是弱类型的语言)。

    方法调用模式:

      当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。如果调用表达式包含一个提取属性的动作(即包含一个.点表达式或[]下标表达式),那么它就是被当做一个方法来掉调用。

        let obj = {
          value: 100,
          eat: function (val) {
            console.log(this.value += typeof val === 'number' ? val : 1)
          }
        }
        obj.eat()
        document.writeln(obj.value)
    
    
        obj.eat(3000)
        document.writeln(obj.value)

      方法可以使用this访问自己所属的对象,所以它能够从对象中取值或对对象进行修改。this到对象的绑定发生在调用的时候(JavaScript的作用域在执行的时候确定)。这个“超级”延迟绑定使得函数可以对this高度复用。通过this可取得对它们所属对象的上下文的方法称为公共方法

    函数调用模式:

      当一个函数不是一个对象的方法时,那么它就是被当做一个函数来调用:

        function add(a, b) {
          return a + b
        }
        let sum = add(3, 4)
        console.log(sum)

      以此模式调用函数时,this被绑定到全局对象。外部函数被调用的时候,this应该绑定到外部函数的this变量,但是内部函数的this在JavaScript语言设计的时候没有按照这样的思路来,所以不能共享该方法对对象的访问权(this指向)。

      解决方案:给该函数定义一个that变量,赋值为this,内部函数可以访问到外部函数的变量,就可以访问到that,其实就是访问到this。

        let obj = {
          value: 0,
          increment: function (val) {
            this.value += typeof val === 'number' ? val : 1
          }
        }
        obj.increment()
        document.writeln(obj.value) // 1
        obj.increment(2)
        document.writeln(obj.value) // 3
    
        function add(a, b) {
          return a + b
        }
    
        obj.double = function () {
          let that = this
          let helper = function () {
            that.value = add(that.value , that.value)
          }
          helper()
        }
        obj.double()
        document.writeln(obj.value) // 6

      定义在double方法中的helper函数就是私有方法,它只能被double方法调用。helper函数中的this指向window,它是无法通过this直接访问到obj对象中的value值的,但是double方法是obj对象调用的,所以该方法中的this指向obj对象,然后在该函数中定义that赋值为this,就可以在helper函数中通过that,拿到obj中的value值并进行操作,这是非常常用的方法。如果这里不想使用that变量,还可以用将helper函数定义为箭头函数,箭头函数的this正好指向外层函数的this,这里就正好指向obj了。还有call方法可以改变this指向,在调用helper函数的时候,调用call方法,即helper.call(this),这里传入的this就是赋给that的this,此时helper函数中的this指向为obj。

    构造器调用模式:

    注释1:JavaScript创建一个函数对象时,会给该对象设置一个“调用”属性。当JavaScript调用一个函数时,可理解为调用此函数的“调用”属性。

  • 相关阅读:
    使用NBU进行oracle异机恢复
    mycat偶尔会出现JVM报错double free or corruption并崩溃退出
    exp导出数据时丢表
    service_names配置不正确,导致dg创建失败
    XML概念定义以及如何定义xml文件编写约束条件java解析xml DTD XML Schema JAXP java xml解析 dom4j 解析 xpath dom sax
    HTTP协议简介详解 HTTP协议发展 原理 请求方法 响应状态码 请求头 请求首部 java模拟浏览器客户端服务端
    java集合框架容器 java框架层级 继承图结构 集合框架的抽象类 集合框架主要实现类
    【JAVA集合框架一 】java集合框架官方介绍 Collections Framework Overview 集合框架总览 翻译 javase8 集合官方文档中文版
    java内部类深入详解 内部类的分类 特点 定义方式 使用
    再谈包访问权限 子类为何不能使用父类protected方法
  • 原文地址:https://www.cnblogs.com/wuqilang/p/13732442.html
Copyright © 2011-2022 走看看