阅读视图

发现新文章,点击刷新页面。

中泰证券:2025年净利同比预增40%-60%

36氪获悉,中泰证券发布2025年业绩预告。报告显示,预计2025年度归属于上市公司股东的净利润为13.12亿元-14.997亿元,同比增加40%-60%。2025年资本市场活跃度回升,公司把握市场机遇,聚焦高质量发展,提升管理质效,财富管理、资产管理、投资交易等业务收入同比增长,整体经营业绩显著提升。

智翔金泰:预计2025年净利润亏损4.81亿元-5.87亿元

36氪获悉,智翔金泰发布2025年业绩预告、报告显示,预计2025年归属于上市公司股东的净利润亏损4.81亿元-5.87亿元。业绩变动主要系首款商业化产品赛立奇单抗注射液销售收入增长,以及确认GR1803注射液授权许可收入;同时因股权激励服务期届满,2025年无股份支付费用,研发费用同比下降。

现代汽车去年销售额创新高,营业利润同比降19.5%

现代汽车1月29日发布财报显示,去年销售额达186.25万亿韩元(约合人民币9065亿元),同比增长6.3%,创历史新高。营业利润为11.47万亿韩元,同比下降19.5%。同期,现代汽车销量为413.84万辆,同比下降0.1%。其中,韩国本土销量71.29万辆,海外销量342.54万辆。此外,电动车销量为27.57万辆,混合动力车型(HEV)销量为63.5万辆,合计达96.18万辆,同比增长27%。(界面)

天顺风能:六家全资子公司停产

36氪获悉,天顺风能公告,公司第六届董事会2026年第一次会议审议通过了《关于部分子公司停产的议案》,同意六家全资子公司商都天顺风电叶片有限公司、乾安天顺风电叶片有限公司、濮阳天顺风电设备有限公司、菏泽天顺新能源设备有限公司、通辽市天顺风电设备有限公司及苏州天顺新能源科技有限公司停止生产经营活动。该议案已通过董事会战略与可持续发展委员会审议。

晨曦航空:预计2025年归母净利润亏损5500万元-7060万元

36氪获悉,晨曦航空发布2025年业绩预告。报告显示,预计2025年度营业收入1.4亿元-1.6亿元,上年同期营业收入1.41亿元;归母净利润亏损5500万元-7060万元,上年同期亏损2658.51万元。报告期,公司归属于上市公司股东的净利润下降的主要原因系报告期公司受客户回款影响,计提信用减值损失较上年同期大幅增加,增幅约165.08%,从而导致报告期归属于上市公司股东的净利润下降。

恒指收涨0.51%,恒生科技指数跌1%

36氪获悉,恒指收涨0.51%,恒生科技指数跌1%;地产、食品、纺织服饰板块领涨,融创中国涨超29%,珍酒李渡涨超12%,特步国际涨超5%;半导体、汽车、传媒板块走弱,华虹半导体跌超5%,小鹏汽车、蔚来、大麦娱乐跌超2%;南向资金净买入43.74亿港元。

方正证券:预计2025年净利润同比增长75%-85%

36氪获悉,方正证券发布2025年业绩预告。报告显示,预计2025年实现归属于母公司所有者的净利润38.6亿元-40.8亿元,与上年同期相比将增加16.53亿元-18.73亿元,同比增长75%-85%。预计归属于母公司所有者的扣除非经常性损益的净利润35亿元-37.7亿元,与上年同期相比将增加7.07亿元-9.77亿元,同比增长25%-35%。

大众公用:预计2025年归母净利润同比增长50.12%-114.46%

36氪获悉,大众公用发布2025年业绩预告。报告显示,预计2025年度归母净利润3.5亿元-5亿元,同比增长50.12%-114.46%。本报告期内,公司公用事业等主营业务保持稳定发展。公司通过联营公司持有的金融资产收益较上年同期增加,导致公司业绩较上年同期有较大幅度上升。

桐昆股份:2025年净利同比预增62.24%-78.88%

36氪获悉,桐昆股份发布2025年业绩预告。报告显示,预计2025年度归属于上市公司股东的净利润为19.50亿元至21.50亿元,与上年同期相比增长62.24%至78.88%。主要因涤纶长丝行业供需格局优化带动单吨盈利提升,叠加参股浙石化持续挖潜增效、部分化工产品毛利改善;同时政府补助等非经常性损益金额较大。

春雪食品:预计2025年归母净利润同比增长340.90%-426.63%

36氪获悉,春雪食品发布2025年业绩预告。报告显示,预计2025年度实现归母净利润3600万元-4300万元,同比增长340.90%-426.63%,上年同期归母净利润816.52万元。本期业绩预增的主要原因是公司加大市场开发力度,调理品销量同比增长。降本增效、精细化管理成效显著。

中科磁业:2025年净利同比预增75.11%-108.32%

36氪获悉,中科磁业发布2025年业绩预告。报告显示,预计2025年归属于上市公司股东的净利润为2900万元–3450万元,比上年同期增长75.11%–108.32%。报告期内,募投项目部分达产带动产能释放、产销量提升;公司推进产品与技术迭代,目前公司磁组件产品已顺利通过部分客户的验证,进入小批量供货阶段;深化头部客户合作、拓展新客户,提升市场占有率。

福田汽车:2025年净利同比预增1551%左右

36氪获悉,福田汽车发布2025年业绩预告。报告显示,预计2025年实现归属于母公司所有者的净利润约13.3亿元,同比增加1551%左右;扣除非经常性损益后的净利润约8.2亿元,同比扭亏为盈。主要因推进全面国际化、新能源化、智能化战略,紧抓“以旧换新”政策机遇,海外及新能源销量大幅增长,新产品贡献提升,营销模式创新与后市场业务拓展,以及全价值链降本增效。

德国政府下调2026年经济增长预期至1%

德国联邦政府1月28日发布年度经济报告,预计2026年德国经济将增长1%,较去年秋季预测值下调0.3个百分点。德国联邦经济和能源部长卡特琳娜·赖歇当天在报告发布会上表示,预测值下调的主要原因之一是2025年下半年经济复苏弱于预期。此外,联邦政府在基础设施和国防等领域的大规模财政支出拉动经济的效果也不及预期。(新华社)

前端向架构突围系列 - 编译原理 [6 - 2]:Babel 插件开发与访问者模式

写在前面

很多高级的前端库都在用 Babel 插件做“魔法”。

  • React: JSX 语法根本不是 JS,是 Babel 把它变成了 React.createElement
  • Vue: v-model 的语法糖,是在编译阶段展开的。
  • babel-plugin-import: 为什么 Ant Design 可以按需加载?因为它悄悄把 import { Button } from 'antd' 改写成了引用具体文件的路径。

学会写 Babel 插件,意味着你拥有了改写语言规则的能力。

unnamed.jpg


一、 核心设计模式:访问者模式 (Visitor Pattern)

AST 是一棵深度极深、结构复杂的树。如果让你手动写递归函数去遍历每一个节点,还得判断“这是不是函数”、“这是不是变量”,你会疯掉的。

Babel 采用 访问者模式 来解决这个问题。

1.1 什么是 Visitor?

想象 AST 是一个巨大的迷宫

  • Babel (Traverser): 是一个不知疲倦的导游,他负责走遍迷宫的每一个角落(深度优先遍历)。
  • 你 (Visitor): 是游客。你不需要自己走,你只需要在特定的“景点”等着。
  • 工作流: 导游走到一个节点(比如“函数声明节点”),就会大喊:“这里有个函数声明!”如果你对这个节点感兴趣,你就处理它;不感兴趣,导游就继续走。

1.2 代码中的 Visitor

在 Babel 插件中,Visitor 就是一个对象,对象的Key 是你感兴趣的 AST 节点类型。

const visitor = {
  // 当遍历到 Identifier(标识符/变量名)节点时,执行这个函数
  Identifier(path) {
    console.log("我发现了一个变量:", path.node.name);
  },
  
  // 当遍历到 BinaryExpression(二元表达式,如 a + b)节点时...
  BinaryExpression(path) {
    console.log("我发现了一个运算");
  }
};

二、 手术刀的核心:Path 与 Types

在编写插件时,有两个最重要的概念:path@babel/types

2.1 Path:节点之间的桥梁

注意,Visitor 函数接收的参数不是 node,而是 path

  • Node (节点): 只是静态的数据(JSON 对象),比如 { type: "Identifier", name: "a" }。它没有灵魂。

  • Path (路径): 是一个响应式对象。它不仅包含当前节点的信息,还包含父节点作用域以及增删改查的方法

    • path.node: 获取当前节点数据。
    • path.parent: 获取父节点。
    • path.remove(): 自杀(把自己从树中移除)。
    • path.replaceWith(newNode): 变身(把自己替换成新节点)。
    • path.stop(): 告诉导游(Babel),停止遍历,不要往下走了。

2.2 @babel/types:节点的生成器与验证器

如果你想把 a 替换成 b,你不能直接写 path.node.name = 'b'(虽然有时候也能跑,但不规范)。你需要创建一个标准的 AST 节点。 @babel/types (通常简写为 t) 就是干这个的。

  • t.isIdentifier(node): 判断是不是标识符。
  • t.stringLiteral("hello"): 创建一个字符串字面量节点。

三、 实战演练:编写一个“去除 console.log”的插件

这是 Babel 插件开发的 "Hello World"。 需求: 生产环境构建时,自动删除代码里所有的 console.log,但保留 console.error

3.1 第一步:在 AST Explorer 中观察

输入源码:

console.log('hello');
console.error('oops');

观察 AST 结构,发现 console.log('hello') 是一个 CallExpression (调用表达式)。

  • callee 是一个 MemberExpression (成员表达式 console.log)。

    • object: console (Identifier)
    • property: log (Identifier)

3.2 第二步:编写插件代码

一个 Babel 插件就是一个函数,返回一个包含 visitor 的对象。

// my-babel-plugin.js
module.exports = function({ types: t }) {
  return {
    name: "remove-console-log",
    visitor: {
      // 监听 CallExpression 节点
      CallExpression(path) {
        // 1. 获取 callee (被调用的函数,比如 console.log)
        const { callee } = path.node;

        // 2. 判断是否是成员表达式 (MemberExpression),且不是计算属性 (a['b'])
        if (t.isMemberExpression(callee) && !callee.computed) {
          
          // 3. 检查 object 是不是 'console',property 是不是 'log'
          if (t.isIdentifier(callee.object, { name: 'console' }) &&
              t.isIdentifier(callee.property, { name: 'log' })) {
            
            // 4. 这里的 path 就是 console.log('...') 这一整行
            // 直接由手术刀切除!
            path.remove();
          }
        }
      }
    }
  };
};

3.3 第三步:测试效果

输入:

function add(a, b) {
  console.log('debug:', a);
  console.error('fatal error');
  return a + b;
}

输出:

function add(a, b) {
  console.error('fatal error');
  return a + b;
}

Bingo! 你刚刚成功完成了一次代码外科手术。


四、 进阶:作用域 (Scope) 的魔咒

架构师和普通开发者的区别在于对副作用的考虑。 上面的插件有个 Bug:如果用户自己定义了一个叫 console 的变量怎么办?

function test() {
  const console = { log: () => {} };
  console.log('这不应该被删除'); // 我们的插件会错误地删除这一行!
}

4.1 作用域检查

Babel 的 path.scope 提供了强大的作用域分析能力。 我们需要检查:console 这个引用,是否绑定(Binding) 到了全局?还是被局部变量覆盖了?

优化后的代码:

CallExpression(path) {
  const { callee } = path.node;
  if (t.isMemberExpression(callee) && 
      t.isIdentifier(callee.object, { name: 'console' }) &&
      t.isIdentifier(callee.property, { name: 'log' })) {

    // 【新增】核心检查:获取 'console' 这个标识符的绑定信息
    const binding = path.scope.getBinding('console');
    
    // 如果没有绑定(说明是全局变量),才删除
    if (!binding) {
      path.remove();
    }
  }
}

现在,Babel 能够识别出局部变量 console,从而放过它。


五、 总结与脑洞:Babel 还能干什么?

通过这个简单的例子,你掌握了 Babel 插件的精髓:Find (Visitor) -> Check (Path/Types) -> Modify (Remove/Replace)

在架构设计中,Babel 插件有无限的潜力:

  1. 自动埋点: 找到所有的 Click 事件函数,在函数体第一行自动插入 track('click') 代码。
  2. 国际化 (i18n) 提取: 扫描所有中文字符串,自动提取到 JSON 文件中,并替换为 t('key')
  3. 代码卫士: 禁止使用某些落后的 API,一旦发现直接构建报错(比 ESLint 更暴力)。

结语:从手术刀到守门员

我们现在已经拥有了修改代码的手术刀(Babel Plugin)。 但是,手术刀太锋利了,容易伤人。在日常开发中,我们更多时候不需要“修改”代码,而是需要“检查”代码,或者进行大规模的、安全的“自动化重构”。

这时候,我们需要另一套基于 AST 的工具体系。

Next Step: 既然我们能分析代码结构,那是不是可以制定一套“代码法律”? 下一节,我们将探讨**《第三篇:工具——代码质量的守门员:ESLint 原理、自定义规则与 Codemod 自动化重构》**。我们将学习如何编写自定义的 ESLint 规则,以及如何用 Codemod 瞬间修改 1000 个文件。

❌