全部版块 我的主页
论坛 数据科学与人工智能 IT基础 JAVA语言开发
48 0
2025-12-12

今天在工作中,偶然看到公司项目中的一段代码,引发了我对 JavaScript 特性的重新思考。这段代码将整套 CRUD 操作以及工作流配置进行了高度封装,尤其是在一个表单页面的渲染逻辑上体现得尤为明显。

具体场景是这样的:页面包含多个 tab 选项卡,用于控制不同表单组件的展示。每个表单组件都与特定的工作流相关联,并通过配置化方式实现动态渲染。每一个组件本质上是一个具有多个属性的实例对象,能够根据设定的条件决定是否渲染。在这个过程中,我一度陷入思维误区——为何一个组件既能作为可调用的函数,又能像普通对象一样拥有各种属性?

// 1. 你写的组件本质上是一个函数
const BasicForm = (props) => {
  return <div>Hello World</div>;
};

// 2. 在 JS 里,函数本身就是对象
console.log(typeof BasicForm);  // "function"
console.log(BasicForm instanceof Object);  // true ?

// 3. 所以可以给函数添加属性
BasicForm.myCustomProp = '我是属性';
BasicForm.anotherProp = 123;

经过一番梳理后,我才意识到自己忽略了 JavaScript 中最基本却极为重要的特性之一:函数的本质是对象。

那么问题来了:为什么同一个实体既可以当作组件使用,又可以作为对象来访问其属性?

// 比如,你现在的组件:
const BasicForm = (props) => { /* 组件逻辑 */ };

// 执行 FormAttWrapper 后:
BasicForm.groupName = 'xxx';
BasicForm.formName = '规划评审';

// 现在 BasicForm 同时拥有:
// 1. 函数能力:可以被调用 BasicForm(props)
// 2. 对象能力:可以访问属性 BasicForm.groupName

下面来看一个更具体的示例说明这一现象:

// 例子1:普通函数 + 属性
function sayHello(name) {
  console.log(`Hello ${name}`);
}

// 给它加属性
sayHello.language = '中文';
sayHello.version = '1.0';

console.log(sayHello.language);  // "中文"
sayHello('张三');  // "Hello 张三"

// 例子2:React 组件也是函数
const MyComponent = (props) => {
  return <div>{props.text}</div>;
};

// 给组件加元数据
MyComponent.displayName = '我的组件';
MyComponent.defaultProps = { text: '默认文本' };

// 函数调用和属性访问互不干扰
console.log(MyComponent.displayName);  // "我的组件"
const element = <MyComponent text="测试" />;  // 正常渲染

我们可以通过类比来理解这个机制:

第一步:原本的 BasicForm 是一个纯函数形式:

BasicForm = function(props) { return jsx; }

第二步:执行了 FormAttWrapper 高阶函数处理之后,向该函数添加了一系列静态属性:

Object.assign(BasicForm, {
  groupName: 'xxx',
  formName: '规划评审',
  isStart: false,
  allowQuery: true
});

第三步:此时的 BasicForm 实际上变成了这样一个复合结构:

BasicForm = {
  // 函数本体(仍可被调用)
  [Function: BasicForm],
  
  // 同时附加了多个自定义属性
  groupName: 'xxx',
  formName: '规划评审',
  isStart: false,
  allowQuery: true
}

这就像一个人,比如定义如下函数:

const person = (name) => console.log(`我叫${name}`);

除了“说话”这种行为(即函数调用),这个人还可以拥有身份证、职业、年龄等静态信息。例如:

person.job = '程序员';
console.log(person.job); // 输出:程序员

当我们调用 person('皇帝') 时,是在执行函数功能;而访问 person.job 时,则是在读取其作为对象所携带的属性信息。两者并行不悖。

最终结论如下:

在 JavaScript 中,函数属于“一等公民”(first-class object),这意味着它们不仅可以被调用,还能像普通对象一样拥有属性和方法。因此,你的组件之所以既能被 React 正常调用以进行 UI 渲染,又能在其他地方作为配置对象被访问,正是基于这一语言层面的核心特性——函数本身就是对象,调用与属性存取互不影响。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群