js 变量声明与赋值 笔试踩坑题

文章目录

    • 概述
    • 函数声明
    • 函数形参与实参
    • 函数预编译
      • 用一个例子说明一下,这四个步骤分别要干些什么。
      • 重复四个步骤,反复练习一下
    • 全局编译
    • 多重执行期上下文

概述

在这里插入图片描述

别小看变量声明与赋值,在所有的笔试中,基本都会考,这个要多变态就能多变态,但只要掌握基本的规律,我们就能游刃有余,面对一切困难。

var function1 = function() {
	console.log('abc')
}
function1()
var function1 = function abc() {
	console.log('abc')
}
function1()
abc()
var function1 = function() {
	console.log('function1')
}

var abc = function function1() {
	console.log('abc')
}
function1()
abc()

上面三段代码分别会发生什么?

函数声明

函数有函数声明和函数表达式两种方式创建

函数表达式

var function1 = function() {
	console.log('function1')
}

函数声明

function function2() {
	console.log('function2')
}

以下代码会发生什么,当函数声明的名称和函数表达式赋值的变量相同时

function function1() {
	console.log('function2')
}
function1() // function3

var function1 = function() {
	console.log('function1')
}

function function1() {
	console.log('function3')
}

function1() // function1

结论 函数声明整体提升,函数表达式只提升赋值的变量

以下两种函数有什么区别

var function1 = function() {
	console.log('function1')
}

var function2 = function abc() {
	console.log('function2')
}

function1() // function1
function2() // function2
abc() // 报错 

以上两种命名方式没区别。abc写与不写,基本没影响,写了也白写,通过abc()无法调用,abc未被声明,所以会报错 abc is not a function

唯一的区别在于function1.name === 'function1' // true function2.name === 'abc' // true
结论 函数声明赋值给变量时,函数声明就成了表达式,此时函数声明本身的名字将不重要。

函数形参与实参

arguments 就是实参 而 函数名xxx.length就可以拿到所有形参的数量

function test(a, b) {
	// 获取形参的数量
	console.log(test.length) // 2
	// 获取实参的数量
	console.log(arguments.length) // 4
	return a + b
}

test(1,2,3,4) // 3

有了上面的启发,请你写一个函数能够返回所有传入参数的和

function sum() {
	let result = 0;
	for (let i = 0; i < arguments.length;i++) {
		result += arguments[i]
	}
	return result
}

sum(1,2,3,4)

加深一点难度,请你将sum柯里化

function sum(a, b, c) {
	return a + b + c
}

function curry(fun) {
	return function curryFun() {
		const args = arguments
		// 如果参数数量足够,直接返回函数调用结果, args是实参而fun.length就是形参所需的数量
		if(fun.length <= args.length) {
			return fun(...args)
		} else {
			// 当参数数量不够时,直接递归返回curried函数,当下一次curried函数被调用时,再判断参数是否足够
			return function(...nextargs) {
				return curryFun(...args, ...nextargs)
			}
		}
	}
}

var curried = curry(sum)
var result = curried(1)(2)(3) // 6

看一下形参和实参之间的关系

// 例1
function test(a, b) {
	a = 1;
	console.log(arguments[0]) // 1
	arguments[1] = 2 
	console.log(b) // 2
}

test(0,0)

// 例2
function test1(a,b) {
	a = 1;
	console.log(arguments[0]) // 1
	arguments[1] = 2 
	console.log(b) // undefined
}
test1(0)

上面例1说明了形参与实参是有映射关系的,如果形参发生改变,对应的实参arguments也会发生变化,arguments如果发生变化,形参也会发生变化。但是形参和实参arguments是两个不同数据,它们只是有映射关系。

上面的例2与例1的唯一不同就是,实参传入的时候只有一个参数,所以形参中只有第一个参数a与实参arguments[0]完成了映射。第二个参数没有传,所以arguments[1]也就不存在,也无法与形参b完成映射。
这也从侧面证明了,形参与实参只是映射关系,本质上还是两个不同的数据。

函数预编译

发生在函数执行的前一刻。

  1. 创建AO(active object) 对象,又称为执行期上下文。
  2. 将形参的名称,和声明变量的名称,作为键值对的key,放入AO对象中,value为undefined。
  3. 将形参和实参统一。
  4. 在函数体里面找函数声明,并将函数赋值。

用一个例子说明一下,这四个步骤分别要干些什么。

function test (a, b) {
	console.log(a);
	console.log(b)
	var a = 2;
	console.log(a)
	function a () {};
	console.log(a)
	console.log(b)
	var b = function b() {}
	console.log(b)
}

test(1)

第一步,创建AO对象

const AO = {}

第二步 将形参的名称,和声明变量的名称,作为键值对的key,放入AO对象中,value为undefined。
test的形参有 a b,声明变量也是 a b

const AO = {
 a: undefined,
 b: undefined
}

第三步,将实参赋值给形参,test(1) 也就是把1赋值给a

const AO = {
 a: 1,
 b: undefined
}

第四步, 在函数体里面找函数声明,并将函数赋值。只有一个函数声明function a () {};,所以

const AO = {
 a: function a() {},
 b: undefined
}

开始执行函数体

function test (a, b) {
	console.log(a); // 直接从AO里拿a:  function a() {}
	console.log(b) // 直接从AO里拿b: undefined
	var a = 2; // 拆分成两部,`var a;a = 1;` `var a;`已经在第二步中完成了,剩下`a = 2`,将AO的a赋值为2
	console.log(a) // 直接从AO里拿a:  2
	function a () {}; // 已经在第四步执行了
	console.log(a) // 直接从AO里拿a:  2
	console.log(b)  // 直接从AO里拿b: undefined
	var b = function b() {} // 拆分成两部,`var b;b = function b() {};` `var b;`已经在第二步中完成了,剩下`b = function b() {}`,将AO的b赋值为 function b() {}
	console.log(b) // // 直接从AO里拿b:  function b() {}
}

重复四个步骤,反复练习一下

	function test1(c, d) {
		console.log(c, d)
		console.log(f) 
		var c = function() {}
		function d() {}
		console.log(c, d)
		var d = 0
		c = 1
		console.log(c, d)
		function e() {}
		var f = 0;
	}
	
	test1(3, 4)

熟悉以后直接从第二步开始
将形参的名称,和声明变量的名称,作为键值对的key,放入AO对象中,value为undefined。
test的形参有 c d,声明变量也是 c d f,重复的只管一个

const AO = {
	c: undefined,
	d: undefined,
	f: undefined
}

第三步,形参实参统一 传入的3和4 分别对应着c和d

const AO = {
	c: 3,
	d: 4,
	f: undefined
}

第四步, 在函数体里面找函数声明,并创建key 赋值给AO对象。
test1中的函数声明只有function d() {}function e() {}

const AO = {
	c: 3,
	d: function d() {},
	f: undefined
	e: function e() {}
}

开始执行代码

	function test1(c, d) {
		console.log(c, d) // 直接从AO里拿c和d // 3 , function d() {},
		console.log(f) // 直接从AO里拿f undefined
		var c = function() {} // 将AO里的c赋值为function() {}
		function d() {} // 在第四步执行了
		console.log(c, d) // 直接从AO里拿c和d function() {} function d() {}
		var d = 0 // 将AO里的d赋值为0
		c = 1 // 将AO里的c赋值为1
		console.log(c, d) // 1 0
		function e() {}
		var f = 0;
	}

难度升级,加入作用域

全局编译

  1. 创建GO(global object) 对象,又称为全局执行期上下文。
  2. 声明变量的名称,作为键值对的key,放入GO对象中,value为undefined。
  3. 在函数体里面找函数声明,并将函数赋值。

GO(global object)在不同的环境指代不同,在浏览器中,GO就是window,在node中GO就是global

多重执行期上下文

var aa = 3;
function bb() {};
var dd;
function test3(aa, bb) {
	console.log(aa)
	console.log(bb)
	dd = 3;
	console.log(dd)
	aa = 4;
	bb = 5;
	function dd() {}
	console.log(aa);
	console.log(bb);
	console.log(dd);
}

test3(1, 2)
console.log(aa)
console.log(bb)
console.log(dd)

先创建GO(上面说的三个步骤)

const GO = {
	aa: undefined,
	dd: undefined,
	bb: function bb() {},
	test3: function test3() {...}
}

创建完成后,开始执行代码,执行到test3时,GO如下,创建AO(上面说的四个步骤)

const GO = {
	aa: 3,
	dd: undefined,
	bb: function bb() {},
	test3: function test3() {...}
}

const AO = {
	aa: 1,
	bb: 2,
	dd: function dd() {}
}

函数test3的AO创建好以后,开始执行函数test3的函数体


var aa = 3;
function bb() {};
var dd;
function test3(aa, bb) {
	console.log(aa) // 1
	console.log(bb) // 2
	dd = 3;  // AO中有dd,改AO中的dd 
	console.log(dd) // AO中有dd,取AO中的dd  3 
	aa = 4;
	bb = 5;
	function dd() {} // 这一步相当于有了自己的dd
	console.log(aa); // 4 
	console.log(bb); // 5
	console.log(dd); // 3
}

test3(1, 2)
console.log(aa) // GO中有aa  3
console.log(bb) // GO中有bb  function bb() {}
console.log(dd) // GO中有dd  undefined

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/128873.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode刷题总结(一)

文章目录 前言题型排序问题动态规划 前言 本文把刷题过程中的总结记下来&#xff0c;方便未来回顾的时候继续拓展。 题型 排序问题 排序问题的解决方法有很多。对于简单算法来说&#xff0c;最重要的是记住思路&#xff1b;对于高级算法来说&#xff0c;最重要的是记住细节…

asp.net core weapi 结合identity完成登录注册

1.安装所需要的nuget包 <PackageReference Include"Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version"6.0.24" /><PackageReference Include"Microsoft.EntityFrameworkCore" Version"6.0.24" /><PackageR…

工作利器!熟悉这几款数据流图工具,事半功倍!

数据流图工具在现代工作中起到了非常重要的作用。无论是在企业内部的流程优化&#xff0c;还是在软件开发、项目管理、系统设计等领域&#xff0c;数据流图工具都扮演着关键的角色。本文将为大家介绍8款高效的数据流图工具&#xff0c;帮助大家选择适合自己工作需求的工具。 1.…

创建Springboot工程

前期准备 查看是否安装Java;javac命令是否可用; java -version javac 都安装好之后可以进行创建。 步骤 此处我是使用IntelliJ IDEA 进行创建 打开新建项目–选择Spring Initializr 服务器URL&#xff1a;可以使用默认 &#xff0c; 如果感觉太慢可以选择 http://start.a…

原厂监视综合控制继电器 ZZS-7/1 AC220V 凸出端子固定安装

ZZS-7/11分闸、合闸、电源监视综合控制装置&#xff1b; ZZS-7/12分闸、合闸、电源监视综合控制装置&#xff1b; ZZS-7/13分闸、合闸、电源监视综合控制装置&#xff1b; ZZS-7/14分闸、合闸、电源监视综合控制装置&#xff1b; ZZS-7/102分闸、合闸、电源监视综合控制装置…

基于51单片机的万年历-脉搏计仿真及源程序

一、系统方案 1、本设计采用51单片机作为主控器。 2、DS1302采集年月日时分秒送到液晶1602显示。 3、按键年月日时分秒&#xff0c;心率报警上下限。 4、红外对接管传感器采集心率送到液晶1602显示。 5、心率低于下限或高于上限&#xff0c;蜂鸣器报警。 二、硬件设计 原理图如…

vue+nodejs商城实战项目【登录 + 购物车 + 支付】

从零开始一个前端项目并将其完成需要经历一系列步骤。以下是一个常见的开发流程&#xff0c;可以帮助规划和管理项目&#xff1a; 需求分析和规划&#xff1a; 确定项目的目标和范围。定义用户需求和功能要求。制定项目计划和时间表。 技术选型&#xff1a; 选择适当的前端技术…

4面百度软件测试工程师的面试经验总结

没有绝对的天才&#xff0c;只有持续不断的付出。对于我们每一个平凡人来说&#xff0c;改变命运只能依靠努力幸运&#xff0c;但如果你不够幸运&#xff0c;那就只能拉高努力的占比。 2023年7月&#xff0c;我有幸成为了百度的一名测试工程师&#xff0c;从外包辞职了历经100…

Java ClassNotFoundException异常解决指南

Java ClassNotFoundException异常解决指南 《Java ClassNotFoundException异常解决指南》摘要引言了解ClassNotFoundException异常的本质异常的起因表情小贴士 &#x1f61f; 异常的处理常见引发ClassNotFoundException的情况1. **类路径配置错误**2. **依赖关系错误**3. **动态…

评估 RAG 的神器来啦!TruLens + Milvus=?

大型语言模型&#xff08;LLM&#xff09;的日益普及引爆了向量数据库赛道&#xff0c;向量搜索技术也越发受到开发者关注。目前&#xff0c;主流的向量搜索技术提供者包括向量数据库 Milvus 和 Zilliz Cloud&#xff0c;向量搜索库 FAISS&#xff0c;以及与传统数据库集成的向…

IDEA 28 个天花板技巧 + 12 款神级插件,生产力起飞...

IDEA 作为Java开发工具的后起之秀&#xff0c;几乎以碾压之势把其他对手甩在了身后&#xff0c;主要原因还是归功于&#xff1a;好用&#xff1b;虽然有点重&#xff0c;但依旧瑕不掩瑜&#xff0c;内置了非常多的功能&#xff0c;大大提高了日常的开发效率&#xff0c;下面汇总…

pytest + yaml 框架 -58.运行报告总结summary.json

前言 用例运行结束后&#xff0c;在本地生成summary.json 文件&#xff0c;总结运行结果。 v1.5.1版本更新内容&#xff1a; 1.解决参数化&#xff0c;中文在控制台输出问题 2.保存用例结果summary.json 保存用例结果summary.json 命令行执行用例 pytest运行结束&#xff0…

NodeJS 入门笔记

文档地址 课程地址 源码 提取码&#xff1a;963h hello wrold console.log(hello, world);node hello.jsnodejs 中不能使用 DOM(document) 和 BOM(window) 的 API&#xff1a; documentwindowhistorynavigatorlocation 但是下面的 API 是相通的&#xff1a; consoletimer…

振南技术干货集:振南当年入门C语言和单片机的那些事儿(1)

目录 第一章《振南当年入门 C 语言和单片机的那些事儿》 1、注定堕入单片机 1.1 懵懂好奇的我 &#xff08;小时候好奇的性格经常让我屁股开花。初中开始对计算机产生兴趣&#xff0c;并一发不可收拾。&#xff09; 1.2 我的 C 语言学习经历 &#xff08;上大学后自学 C …

制造行业怎么做?看低代码如何引领未来

随着科技的不断发展&#xff0c;制造行业正面临着巨大的变革和挑战。为了提高生产效率、降低成本并更好地适应快速变化的市场需求&#xff0c;越来越多的制造企业将目光投向了低代码开发平台。在众多低代码开发平台中&#xff0c;JNPF低代码快速开发平台凭借其卓越的性能和灵活…

【论文阅读笔记】Detecting AI Trojans Using Meta Neural Analysis

个人阅读笔记&#xff0c;如有错误欢迎指出&#xff01; 会议&#xff1a;2021 S&P Detecting AI Trojans Using Meta Neural Analysis | IEEE Conference Publication | IEEE Xplore 问题&#xff1a; 当前防御方法存在一些难以实现的假设&#xff0c;或者要求直…

【vue 仿百度分页】

vue 仿百度分页 效果图 代码 公用组件 <template><nav class"pagination_nav"><ul class"pagination"><li :class"{ disabled: current 1 }"><a href"javascript:;" click"setCurrent(current - …

JAVA对象大小的获取

1. Java 对象的内存布局 Java的实例对象、数组对象在内存中的组成包括如下三部分&#xff1a;对象头Hearder、实例数据、内存填充。示意图如下所示 对象头 其主要包括两部分数据&#xff1a;Mark Word、Class对象指针。特别地对于数组对象而言&#xff0c;其还包括了数组长度…

2022年09月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 下列不是评判一个算法优劣的标准是?( ) A: 时间复杂度 B: 空间复杂度 C: 难易度 D: 健壮性 答案:C 评价算法的优劣是:时间复杂度,空间复杂度,健壮性,正确性,可读性。因此选…

一周成功拿下4个offer的软件测试面试题,面试必看系列

前言&#xff1a; 压到就是赚到&#xff0c;面试通过的机率就更大&#xff0c;干就完了铁子 【文章末尾给大家留下了大量的福利】 ​编辑 1、什么是兼容性测试&#xff1f;兼容性测试侧重哪些方面&#xff1f; 参考答案&#xff1a; 兼容测试主要是检查软件在不同的硬件平…