热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Function和原型链

Function是函数?是构造函数?还是函数对象?在翻阅ECMA规范时,这几个名词也是无缝切换中,稍不留神就可能跑偏了.都应该知道,构造函数是用来打造具有相同属性和行为事物的模具.

Function 是函数? 是构造函数? 还是函数对象? 在翻阅 ECMA 规范时, 这几个名词也是无缝切换中, 稍不留神就可能跑偏了.

都应该知道, 构造函数是用来打造具有相同属性和行为事物的模具.

在作为构造函数之前, 它首先是个函数, 函数是可以被调用的(这也是区别于其它对象的因素). 它是由一系列语句组成, 并最终返回一个值. 每一个函数被创建的时候, 都有一个prototype属性.

普通函数能够变成构造函数, 那都是 new 将函数的prototype和生成的实例关联起来了. 换句话说, 每个普通函数都有称为构建函数的潜质.

// 常见的构造函数模式
function Man(name) {this.name = name;this.sex = 'man';
}
Man.prototype.sayHi = function() {console.log('hello', this.name)
}
let man_1 = new Man('夜曉宸');// 我是普通函数
function man(name) {console.log('hello', name)
}
// 只要经过 new 调教后, 我也可以被称为构造函数了
let man_2 = new man('夜曉宸');

Markdown部分语法不支持,点此可看原文


Function和内置函数

都说函数是 Javascript 里的头等对象, 这话一点不假. 在之前文章里有提到过, Javascript 里的数据类型除了基本数据类型, 就是复杂数据类型. 而这些复杂数据类型都和 Function 有着密切关系.

Function构造函数

函数的身影在 Javascript 中随处可见, 有造字符串类型的 String 函数, 有造数值类型的 Number 函数, 除了这些内置函数, 还有上面我自己写的 Manman 函数.

Javascript 的作者在写 Javascript 语言的时候, 可能知道有且需要 String, Number 这样的函数处理写数据, 于是有了内置函数这么一说.(纯属杜撰?)

那么内置函数满足不了我们的需求呢, 如何去创建一个函数呢? 其实, 在没有这些内置函数之前, 就有了这么一个东西. 那就是为创建函数而生的函数 —— Function. 等会儿, 有点绕?, 创建函数的函数? 那岂不是把自己也给创建了?? 是的, 没错, 就是这么一个奇葩的存在.

The Function constructor is the %Function% intrinsic object and the initial value of the Functionproperty of the global object. When Functionis called as a function rather than as a constructor, it creates and initializes a new Function object. Thus the function call Function(...)is equivalent to the object creation expression new Function(...)with the same arguments.

所以说, 包括这些内置函数, 它们都是由 Function 构建函数造出来的. 如何去验证函数是不是函数造出来的呢?


new操作符

All ordinary objects have an internal slot called [[Prototype]]. The value of this internal slot is either null or an object and is used for implementing inheritance.

每个普通对象都有一个 ***[[Prototype]]***, 这个属性就是用来实现原型继承用的. 上面?也提到了, 在用构造函数造 new 出实例对象时, 实例对象内部的 [[Prototype]] 会关联到构造函数的 prototype 所指向的对象. new 主要做以下两件事:

  1. 将实例对象的 [[Prototype]] 关联到构造函数的 prototype 上.
  2. this 绑定到新创建的实例对象上, 并调用构造函数(就是将函数体里的语句执行一遍).

类似于:

function New(func) {const obj = {};// _proto_ 和 [[Prototype]] 不是同一个东西, 后者是内部使用的.ojb._proto_ = func.prototype;func.call(obj);return obj;
}

Object.getPrototypeOf() 是用来检测指定对象内部 [[Prototype]] 属性的值. 对于上面?的 Manman_1 关系, 试一波.

Object.getPrototypeOf(man_1) === Man.prototype // true;


Function和函数

回头再看看 String, Number, Boolean, Array, Object, Function, RegExp, Date, Error, Symbol 这些内置函数和 Function 构造函数的关系(注意包含了 Function 自身). 这里是把这些内置函数作为由 Function 构造出来的实例对象对待的. (函数也是对象的一子类型)

Object.getPrototypeOf(String) === Function.prototype // trueObject.getPrototypeOf(Number) === Function.prototype // trueObject.getPrototypeOf(Boolean) === Function.prototype // trueObject.getPrototypeOf(Array) === Function.prototype // trueObject.getPrototypeOf(Object) === Function.prototype // trueObject.getPrototypeOf(Function) === Function.prototype // trueObject.getPrototypeOf(RegExp) === Function.prototype // trueObject.getPrototypeOf(Date) === Function.prototype // trueObject.getPrototypeOf(Error) === Function.prototype // trueObject.getPrototypeOf(Symbol) === Function.prototype // trueObject.getPrototypeOf(Man) === Function.prototype // true ???Object.getPrototypeOf(man_1) === Function.prototype // false ???

在之前文章有提及过, Javascript里的对象类型基本上也就是那么多. 以上函数的原型链, 最终会指向 Function.prototype (仅为目前, 后面还有 Object.prototypenull ). 这也是解释了为什么任何一个普通函数都可以调用 call , applyFuncton.prototype 上的方法.


Function和原型

所有的函数的原型链里都将会出现 Functon.prototype, 由构造函数 new 出来的实例对象的 [[Prototype]] 会关联到构造函数 prototype 上.

let num = new Number(0);Object.getPrototypeOf(num) === Number.prototype // trueObject.getPrototypeOf(Man) === Function.prototype // true ???

到目前为止, 任何函数或对象都可以追溯到 Functon.prototype 和 构造函数的 prototype 上. 那么接下来, 又如何沿着原型链再往后找呢?

The Function prototype object is the intrinsic object %FunctionPrototype%. The Function prototype object is itself a built-in function object.

这句话告诉我们, Function 的原型是一个函数对象. 可我们也知道, 所有的函数都应该来自于 Function. 由此可推导, Function.prototype 内部属性 [[Prototype]] 应指向 Function.prototype. 实际上并不是这样. 同样情况的还有 Array.

Object.getPrototypeOf(Function.prototype) === Function.prototype // false

ECMA 规范也给出了解释, 不知是不是解释这个的.

NOTE The Function prototype object is specified to be a function object to ensure compatibility with ECMAScript code that was created prior to the ECMAScript 2015 specification.

以上推导可忽略. 所以呢,

The value of the [[Prototype]] internal slot of the Function prototype object is the intrinsic object %ObjectPrototype%.

Object.getPrototypeOf(Function.prototype) === Object.prototype // true

其它的构造函数也是一样.

// true String.prototype is an ordinary object.Object.getPrototypeOf(String.prototype) === Object.prototype// true String.prototype is an ordinary object.Object.getPrototypeOf(Number.prototype) === Object.prototype// true String.prototype is an ordinary object.Object.getPrototypeOf(Boolean.prototype) === Object.prototype// true String.prototype is an Array exotic objects.Object.getPrototypeOf(Array.prototype) === Object.prototype// true String.prototype is an ordinary object.Object.getPrototypeOf(Function.prototype) === Object.prototype// true String.prototype is a built-in function object.Object.getPrototypeOf(RegExp.prototype) === Object.prototype// true String.prototype is an ordinary object.Object.getPrototypeOf(Date.prototype) === Object.prototype// true String.prototype is an ordinary object.Object.getPrototypeOf(Error.prototype) === Object.prototype// true String.prototype is an ordinary object.Object.getPrototypeOf(Symbol.prototype) === Object.prototype

所有的函数或对象的原型链都会追溯到 Object.prototype 上, 难道这里就是终点么? 不是的, 还有个 null . 所以, 最终,

Object.getPrototypeOf(Object.prototype) === null // true


总结一波:

  1. Function 是构造函数的地方, 构造函数是函数, 内建函数也是函数.

  2. 被构造出来的实例对象内部属性 [[Prototype]] 会关联到构造函数的 prototype 所指向的对象.

  3. prototype chain 的走向为:

    1. instance => constructor.prototype => Object.prototype => null. (构造函数造出的实例对象走向)
    2. function => Function.prototype => Object.prototype => null.(函数走向)
    3. ...

上图说明一切.




推荐阅读
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • EST:西湖大学鞠峰组污水厂病原菌与土著反硝化细菌是多重抗生素耐药基因的活跃表达者...
    点击蓝字关注我们编译:祝新宇校稿:鞠峰、袁凌论文ID原名:PathogenicandIndigenousDenitrifyingBacte ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 基于iSCSI的SQL Server 2012群集测试(一)SQL群集安装
    一、测试需求介绍与准备公司计划服务器迁移过程计划同时上线SQLServer2012,引入SQLServer2012群集提高高可用性,需要对SQLServ ... [详细]
  • JUC(三):深入解析AQS
    本文详细介绍了Java并发工具包中的核心类AQS(AbstractQueuedSynchronizer),包括其基本概念、数据结构、源码分析及核心方法的实现。 ... [详细]
  • 本文介绍了如何在 Vue 3 组合 API 中正确设置 setup() 函数的 TypeScript 类型,以避免隐式 any 类型的问题。 ... [详细]
  • 重要知识点有:函数参数默许值、盈余参数、扩大运算符、new.target属性、块级函数、箭头函数以及尾挪用优化《深切明白ES6》笔记目次函数的默许参数在ES5中,我们给函数传参数, ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • Silverlight 实战指南:深入解析用户提交数据的验证与捕获机制
    本文深入探讨了Silverlight中用户提交数据的验证与捕获机制,详细分析了四种主要的验证方法:基本异常处理、DataAnnotation注解、IDataErrorInfo客户端同步验证以及自定义验证策略。通过实例解析,帮助开发者更好地理解和应用这些机制,提升应用程序的数据处理能力和用户体验。 ... [详细]
  • 本文探讨了如何在C#应用程序中通过选择ComboBox项从MySQL数据库中检索数据值。具体介绍了在事件处理方法 `comboBox2_SelectedIndexChanged` 中可能出现的常见错误,并提供了详细的解决方案和优化建议,以确保数据能够正确且高效地从数据库中读取并显示在界面上。此外,还讨论了连接字符串的配置、SQL查询语句的编写以及异常处理的最佳实践,帮助开发者避免常见的陷阱并提高代码的健壮性。 ... [详细]
  • Python进阶笔记:深入理解装饰器、生成器与迭代器的应用
    本文深入探讨了Python中的装饰器、生成器和迭代器的应用。装饰器本质上是一个函数,用于在不修改原函数代码和调用方式的前提下为其添加额外功能。实现装饰器需要掌握闭包、高阶函数等基础知识。生成器通过 `yield` 语句提供了一种高效生成和处理大量数据的方法,而迭代器则是一种可以逐个访问集合中元素的对象。文章详细解析了这些概念的原理和实际应用案例,帮助读者更好地理解和使用这些高级特性。 ... [详细]
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • 在C#中开发MP3播放器时,我正在考虑如何高效存储元数据以便快速检索。选择合适的数据结构,如字典或数组,对于优化性能至关重要。字典能够提供快速的键值对查找,而数组则在连续存储和遍历方面表现优异。根据具体需求,合理选择数据结构将显著提升应用的响应速度和用户体验。 ... [详细]
author-avatar
莫轻松
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有