22 | new Function('x = 100')();:函数的类化是对动态与静态系统的再次统一
该思维导图由 AI 生成,仅供参考
函数的动态创建
- 深入了解
- 翻译
- 解释
- 总结
JavaScript中的函数类化是对动态与静态系统的再次统一。文章深入探讨了动态函数的实现原理,包括动态创建函数的方式、函数的三个组件以及动态函数的创建过程。作者指出,动态创建函数意味着创建一个对象,它创建自类/构造器。在JavaScript中,Function()是一切函数缺省的构造器,所有的内建函数也通过简单的映射将它们的原型指向Function。这种设计使得JavaScript中的函数有了“完整的”面向对象特性,函数的“类化”实现了JavaScript在函数式语言和面向对象语言在概念上的大一统。文章还介绍了动态函数的构造器、函数的三个组件以及动态函数的创建过程。此外,文章还探讨了动态函数与静态函数的统一性,指出在ECMAScript的内部方法`Call()`或者函数对象的内部槽`[[Call]] [[Construct]]`中,根本没有任何代码来区别这两种方式创建出来的函数。文章还指出了动态函数在创建时只检测代码文本中的第一行代码是否为`use strict`指示字,而忽略它“外部scope”是否处于严格模式中,因此即使在严格模式的全局环境中创建动态函数,它也是执行在非严格模式中的。总的来说,文章深入探讨了JavaScript中函数的动态特性,以及动态函数与静态函数的统一性,为读者提供了对JavaScript函数类化的深入理解。
《JavaScript 核心原理解析》,新⼈⾸单¥59
全部留言(10)
- 最新
- 精选
- 独钓寒江雪今天读完了专栏必学内容的最后一讲,跟着老师的步伐一路走来,很艰辛,同时也收获很多,通过一行极简的代码去洞悉一门语言的核心原理,也是我一直梦想着能做到的事,向老师致敬! 其实,可以说,看这种底层的东西,每一讲都很吃力,要想有更深入的理解,必须再花时间回过头反复研读;其实,阅读专栏,很多时候也是一种思维的提升,比如以前只知道变量提升,却没想过为什么要提升;知道...运算符,却说不出为什么可以用它来展开对象。。。 或许专栏短期内对开发能力不会有多么显著的提升,但我相信,因为对语言本质的洞悉而产生的自信以及思想层面的提升,将会使我在前端走的更远。衷心的感谢🙏
作者回复: 🙏
2020-01-038 - 行问new Function(x) vs Function(x) 没什么区别。如果是“类化”的话,也是没什么区别吗?在使用 class 声明一个类时,new class 与 class 直接调用。 函数是对象的概念比较清晰,明了。这让我想起之前的 "null",请教个问题,在通常的开发中,会把一些变量释放空间,把值置为 null, 那么如果是置为 {} 呢?如下: var a = null 和 var a = {},是否有大差异? 我的理解是 {} 会存放在“堆空间”占据内存,但同时它是一个空对象,null 也是一个什么都没有的空对象,但 null 也是其它对象的原型,所以也会有 Object.create(null) 不知道周大能否看懂我的逻辑? 感谢
作者回复: Oh. 这个 > new Function(x) vs Function(x) 没什么区别 并不算是很特别的特例。你应该记得new AClass()的时候,允许“用户代码直接返回对象,而不是直接使用this” 这个特性对吧,其实这就是这个特性的应用。因为当用户代码返回自己创建的对象是,用不用new,效果都是一样的了。——所以,这里的意思是说,Function()在实现时也是自己返回了对象,而没有使用缺省new给他创建的this。 理论上,这对类化来说也是适用的。因为类化也允许用户代码返回对象来替代this。但是——呵呵,如果你用“class X...”来声明类,那么这个X是只能用new来调用的,而不能直接当做函数调用。 ``` > X() TypeError: Class constructor X cannot be invoked without 'new' ``` 关于null值和{}。其实null值是一个特殊性,它是真的“什么也没有”,你甚至可以将它理解为C里面的#0。而它是对象(typeof null),以及它能作为其它对象或类的原型,只是一个语言设计,而与它的内存占用没有关系。你可以这样理解,没问题。——另外,在ECMAScript中,null是一个原始值(Primitive value),这意味着它可以直接在引擎中表达为二进制的存储,真的跟#0很接近了。^^. 而{}是一个对象,它在引擎中表达为一个结构、一个数据块(也就是你认为的放在堆里,其实是不是放在堆里不重要,而且也并不确定)。对象之所以为空白(“{}”称为空白对象Empty objects),是因为它的自有属性表为空,当自有属性表里面没有属性项的时候,它就是空白的了。——你可以重置它的原型,让他表现得有一些属性什么的。因为它毕竟还是一个可操作的、占有引擎中的存储的真实对象。 另外,ECMAScript内部(以及引擎内部的执行逻辑中)其实是把null值理解为“值”的,而不是“对象”。所以ECMAScript的内部方法IsObject(null),是返回false的。
2020-01-0324 - 晓小东好快,这个专栏结束了,有点舍不得,一个多月来我一直关注老师更新,反复阅听之前章节。体会深思理解,发现如果没有老师带领层层分析JavaScript 最核心那部分设计和概念,真的无缘了解这门语言了,谢谢老师给我们思维上的提升,同时也发现自己对这门语言的理解上,上了一个大大的台阶。在此由衷的感谢,真的感觉,遇到了恩师。
作者回复: 😀+🤝
2020-01-032 - weineel老师的每一篇都很有深度。我们平时开发中,this 的动态绑定虽然很复杂,但时间长了也能找到规律,仅仅是应用还是没啥问题的。老师要是有时间给我们加个餐,聊聊 this 的深层原理吧。
作者回复: 这个可以有。我考虑一下怎么做到下一个课程吧。这一课结束哒所以也不再有加餐哒。^^.
2020-01-051 - 大雄不爱吃肉专栏虽然是二十多讲,但是自己看了很久,很多地方反复看反复试。可能最终记住的不是很多,但对js以及语言规范有了深刻的理解,感谢老师这门课,这一门独特的课程我收获颇多,期待老师的下一门课!
作者回复: 多谢多谢。有收获就好。:)
2021-04-01 - igetter老师,问一个不太相关的问题: MDN中说,Function()比eval()更高效。这是真的吗?
作者回复: 是的。 Function(x)工作在全局,所以它的作用域层次通常要小于eval(x)。因为作用域(链)的深度小,所以Function()执行要略高效。 如果只是说对代码文本`x`的解析和处理等,两者并没有明显的性能区别。
2020-06-14 - James老师,我从头听了一遍,有几篇文章听了好几遍,但是感觉完全是云里雾里,没弄懂。我应该怎么办。🤣
作者回复: 补一些基础,再看。建议边读ECMAScript边看。加餐里面我有给地址~找找哇😀
2020-02-052 - 许童童一路跟着老师走过来,自以为对JavaScript这门语言有一定的了解,才发现只是懂点皮毛,更多深入的知识自己都还没有探究到,感谢老师带我领会了更深刻的JavaScript。之后还是会持续学习,保持对JavaScript的敬畏之心,加油。
作者回复: 能对大家有用就好。我一直以这样的态度来做这件事,那怕能帮助一人,也是好的。多谢你的支持。^^.
2020-01-04 - 独钓寒江雪以前有碰到了这样一个疑惑,看了专栏前面的内容,还是不太明白。下面是我的代码,虽然问题比较好解决,但是不太明白: import { message } from 'antd' // 引入AntD组件库中的message export const generateRemark = (skus, message) => {// 这个方法被导出,接收两个参数,其中一个写成了message let remark = '' ...... remark = remark + (message || '')// 使用了message参数 return remark } 当我调用generateRemark(skus, '')时(message传入的是空字符串),返回是[object Object],调试发现,原来message被解析成了antd的message组件了。 是代码环境的问题还是JS底层机制的问题呢?希望老师能帮我解惑,谢谢🙏 最后,也感谢老师的专栏,这样关注底层核心原理的专栏,正是我这种自学前端出道的同学的所需要的。
作者回复: 仔细读了几遍你的问题,我觉得这是不可能出现的。但还是小心地写了一个测试来运行了一下,但是还原不了你说的问题。(代码放在后面,你看看是不是这个意思) 我仔细想了一下,非常可疑的事情出来你使用import/export的方法上面。由于NodeJS在一般模式下并不支持ES Module,因此通常我们在应用环境中使用模块的时候,都是用babel来转码的。而早期babel(也包括其它的一些第三方转码器)可能对某些语法支持得不好,所以转出来的结果跟ECMAScript规范并不一致,做不到百分百地兼容。并且,在你的示例中还有一个箭头函数,这个东西在很多转码器和基于转码器的runtime中还是实现得不好的。 所以简单地说,我怀疑是你在应用环境中使用babel或typescript之类的转码器带来的结果。无论如何,ECMAScript的规范中不会有这个问题。如下例: ``` # 运行 > node --experimental-modules t1.mjs // 代码t1.mjs import { generateRemark } from './t2.mjs'; var skus = ''; console.log(generateRemark(skus, '')); // 代码t2.mjs import { message } from './t3.mjs' export const generateRemark = (skus, message) => { let remark = '' // ...... console.log(typeof message, message); remark = remark + (message || '') return remark } // 代码t3.mjs export var message = {}; ```
2020-01-032 - K4SHIFZ动态函数创建在规范19.2.1.1.1 Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto). Let realmF be the current Realm Record. Let scope be realmF.[[GlobalEnv]]. Let F be ! OrdinaryFunctionCreate(proto, sourceText, parameters, body, non-lexical-this, scope). Perform SetFunctionName(F, "anonymous")2020-05-03