热门标签 | 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. ...

上图说明一切.




推荐阅读
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
  • 巧用arguments在Javascript的函数中有个名为arguments的类数组对象。它看起来是那么的诡异而且名不经传,但众多的Javascript库都使用着它强大的功能。所 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • dotNet变量和数据类型详解,包括声明变量和五大类型
    本文详细介绍了dotNet编程中的变量和数据类型,包括声明变量和五大类型(int、double、decimal、string、char)。文章通过案例演示了变量的声明和赋值方法,并解释了每种数据类型的特点和使用场景。此外,还介绍了变量命名规则和一些特殊情况,如String与string的区别、float类型的使用等。阅读本文可以帮助读者更好地理解和应用dotNet编程中的变量和数据类型。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
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社区 版权所有