JavaScript 函数调用和JavaScript 闭包

news/2024/11/15 5:01:39/

文章目录

  • 一、JavaScript 函数调用
  • 二、JavaScript 闭包
  • 总结

一、JavaScript 函数调用

JavaScript 函数有 4 种调用方式。

每种方式的不同在于 this 的初始化。

  • this 关键字

一般而言,在Javascript中,this指向函数执行时的当前对象

注意 this 是保留关键字,你不能修改 this 的值。

  • 调用 JavaScript 函数

函数中的代码在函数被调用后执行。

  • 作为一个函数调用
function myFunction(a, b) {return a * b;
}
myFunction(10, 2);           // myFunction(10, 2) 返回 20

在 HTML 中默认的全局对象是 HTML 页面本身,所以函数是属于 HTML 页面。

在浏览器中的页面对象是浏览器窗口(window 对象)。以上函数会自动变为 window 对象的函数。

myFunction() 和 window.myFunction() 是一样的:

function myFunction(a, b) {return a * b;
}
window.myFunction(10, 2);    // window.myFunction(10, 2) 返回 20
  • 全局对象

当函数没有被自身的对象调用时 this 的值就会变成全局对象

在 web 浏览器中全局对象是浏览器窗口(window 对象)。

该实例返回 this 的值是 window 对象:

function myFunction() {return this;
}
myFunction();                // 返回 window 对象

函数作为全局对象调用,会使 this 的值成为全局对象。
使用 window 对象作为一个变量容易造成程序崩溃。

  • 函数作为方法调用

在 JavaScript 中你可以将函数定义为对象的方法。

以下实例创建了一个对象 (myObject), 对象有两个属性 (firstName 和 lastName), 及一个方法 (fullName):

var myObject = {firstName:"John",lastName: "Doe",fullName: function () {return this.firstName + " " + this.lastName;}
}
myObject.fullName();         // 返回 "John Doe"

fullName 方法是一个函数。函数属于对象myObject 是函数的所有者。

this对象,拥有 JavaScript 代码。实例中 this 的值为 myObject 对象

测试以下!修改 fullName 方法并返回 this 值:

var myObject = {firstName:"John",lastName: "Doe",fullName: function () {return this;}
}
myObject.fullName();          // 返回 [object Object] (所有者对象)

函数作为对象方法调用,会使得 this 的值成为对象本身。

  • 使用构造函数调用函数

如果函数调用前使用了 new 关键字, 则是调用了构造函数

这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象

// 构造函数:
function myFunction(arg1, arg2) {this.firstName = arg1;this.lastName  = arg2;
}// This    creates a new object
var x = new myFunction("John","Doe");
x.firstName;                             // 返回 "John"

构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法。 构造函数中 this 关键字没有任何的值。
this 的值在函数调用实例化对象(new object)时创建。

  • 作为函数方法调用函数

在 JavaScript 中, 函数是对象。JavaScript 函数有它的属性和方法

call() 和 apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身

function myFunction(a, b) {return a * b;
}
myObject = myFunction.call(myObject, 10, 2);     // 返回 20
function myFunction(a, b) {return a * b;
}
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray);  // 返回 20

两个方法都使用了对象本身作为第一个参数。 两者的区别在于第二个参数: apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)

在 JavaScript 严格模式(strict mode)下, 在调用函数时第一个参数会成为 this 的值, 即使该参数不是一个对象。

在 JavaScript 非严格模式(non-strict mode)下, 如果第一个参数的值是 null 或 undefined, 它将使用全局对象替代。

通过 call() 或 apply() 方法你可以设置 this 的值, 且作为已存在对象的新方法调用。

二、JavaScript 闭包

JavaScript 变量可以是局部变量或全局变量。

私有变量可以用到闭包。

  • 全局变量

函数可以访问由函数内部定义的变量,如:


function myFunction() {var a = 4;return a * a;
}

函数也可以访问函数外部定义的变量,如:


var a = 4;
function myFunction() {return a * a;
}
后面一个实例中, a 是一个 全局 变量。在web页面中全局变量属于 window 对象。全局变量可应用于页面上的所有脚本。在第一个实例中, a 是一个 局部 变量。局部变量只能用于定义它函数内部。对于其他的函数或脚本代码是不可用的。全局和局部变量即便名称相同,它们也是两个不同的变量。修改其中一个,不会影响另一个的值。 

变量声明时如果不使用 var 关键字,那么它就是一个全局变量,即便它在函数内定义

  • 变量生命周期

全局变量的作用域是全局性的,即在整个JavaScript程序中,全局变量处处都在。

而在函数内部声明的变量,只在函数内部起作用。这些变量是局部变量,作用域是局部性的;函数的参数也是局部性的,只在函数内部起作用。

  • 计数器困境

设想下如果你想统计一些数值,且该计数器在所有函数中都是可用的。

你可以使用全局变量,函数设置计数器递增:

var counter = 0;function add() {return counter += 1;
}add();
add();
add();// 计数器现在为 3

在这里插入图片描述
计数器数值在执行 add() 函数时发生变化。

但问题来了,页面上的任何脚本都能改变计数器,即便没有调用 add() 函数。

如果我在函数内声明计数器,如果没有调用函数将无法修改计数器的值

function add() {var counter = 0;return counter += 1;
}add();
add();
add();// 本意是想输出 3, 但事与愿违,输出的都是 1 !

在这里插入图片描述

  • JavaScript 内嵌函数

所有函数都能访问全局变量。

实际上,在 JavaScript 中,所有函数都能访问它们上一层的作用域。
JavaScript 支持嵌套函数。嵌套函数可以访问上一层的函数变量

该实例中,内嵌函数 plus() 可以访问父函数的 counter 变量


function add() {var counter = 0;function plus() {counter += 1;}plus();    return counter; 
}

如果我们能在外部访问 plus() 函数,这样就能解决计数器的困境。

我们同样需要确保 counter = 0 只执行一次。

我们需要闭包。

  • JavaScript 闭包

还记得函数自我调用吗?该函数会做什么?

var add = (function () {var counter = 0;return function () {return counter += 1;}
})();add();
add();
add();// 计数器为 3
实例解析变量 add 指定了函数自我调用的返回字值。自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。计数器受匿名函数的作用域保护,只能通过 add 方法修改。

闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
直观的说就是形成一个不销毁的栈环境。

学习来自“https://www.runoob.com/js”

总结

尝试着每天锻炼自己的思维方式,这样才能成为一个真正的领域专家。


http://www.ppmy.cn/news/52826.html

相关文章

文件系统和动静态库

目录 再识文件属性 查看文件属性的原理 初识inode 了解磁盘 什么是磁盘 磁盘的结构 磁盘的存储结构 CHS寻址 磁盘的逻辑结构 使用LBA地址的意义 理解文件系统 页框和页帧 分治思想管理 Linux ext2文件系统 软硬链接 软链接 硬链接 文件的三个时间 动静态库 …

分享一个有意思的文字飞入动画(模仿水滴融合)

先上效果图&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}:root {--text-…

5岁程序员上岸的5个选择,适合所有的大龄IT从业者,如何突破职场发展

80%的成语 当他35岁大多数都要考虑转行了 否则35岁你必然被淘汰 当天有个小伙伴 问我一个成语员都关心的问题 他呢在一家互联网大厂工作 他和他的一些同事 都有一种所谓的35岁的焦虑症 担心自己在职场上的竞争力 不断的变弱 又担心自己在上有老下有小的年纪 被公司优化掉 在行业…

OpenShift 4 - 在 CI/CD Pipeline 中创建 KubeVirt 容器虚拟机 - 方法1+2 (视频)

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在支持 OpenShift 4.12 的 OpenShift 环境中验证 文章目录 准备环境安装可实现 KubeVirt 操作的 Tekton 资源创建密钥对 在 CI/CD 流水线管道中创建 VM方法1&#xff1a;通过 Manifest 任务创建 VM方法2&am…

java基础——Map

Map 第一章 Map集合 1.1 概述 Java提供了专门的集合类用来存放键值对关系的对象&#xff0c;即java.util.Map接口。 我们通过查看Map接口描述&#xff0c;发现Map接口下的集合与Collection接口下的集合&#xff0c;它们存储数据的形式不同&#xff0c;如下图。 Collection中…

合创视觉UI设计师app设计工具

众所周知&#xff0c;适合的工具可以为你带来事半功倍的效果。根据UI设计专业的特点将20个工具进行介绍&#xff0c;他们分别是&#xff1a;原型设计、线框绘制、调动情绪、动效设计。   为你提供创建完美UI设计所需的必要元素。想学UI设计的同学们看起来吧。   原型设…

.netCHATING 10.4 for NET6-7.0-Crack

.NET 6.0图表支持--dotnetcharting .netCHATING 10.4添加了.NET 6.0图表nuget包和.NET 6.0图表示例包&#xff08;需要Visual Studio 2022&#xff09;&#xff0c;.NET 5是.NET Core 3.1和.NET Framework 4.8的继任者&#xff0c;旨在为.NET开发人员提供新的跨平台开发体验。…

Python 实现txt、excel、csv文件读写【附源码】

目录 前言 一、txt文件读写 二、excel文件读写 总结 前言 本文介绍使用Python进行文件读写操作&#xff0c;包括txt文件、excel文件(xlsx、xls、csv) 编译器使用的是PyCharm 一、txt文件读写 read() # 一次性读取全部内容readline() # 读取第一…