普通视图

发现新文章,点击刷新页面。
今天 — 2026年3月18日首页

【JavaScript面试题-this 绑定】请说明 `this` 在不同场景下的指向(默认、隐式、显式、new、箭头函数)。

2026年3月18日 15:27

今天我们来聊一聊 JavaScript 中一个既基础又让人头疼的概念——this

一、this 是什么?

简单来说,this 是函数执行时内部自动生成的一个对象,它指向调用该函数的上下文。你可以把它理解为函数内部的“环境变量”,代表了当前函数运行时所处的对象。

一个形象的比喻

想象一下,你有一个“自我介绍”的功能,不同的人调用它时,“我”这个字指向不同的人:

  • 小明说“叫小明”,这里的“我”就是小明。
  • 小红说“叫小红”,这里的“我”就是小红。

在 JavaScript 中,this 就像这句话里的“我”,而那个自我介绍的函数就像一句模板:“我叫 xxx”。这个模板里的 this.name 会根据是谁在调用而自动替换成对应的人名。

用代码表示:

javascript

function introduce() {
  console.log(`我叫 ${this.name}`);
}

const ming = { name: '小明', introduce };
const hong = { name: '小红', introduce };

ming.introduce(); // 我叫 小明(this 指向 ming)
hong.introduce(); // 我叫 小红(this 指向 hong)

这里的 introduce 函数内部的 this 就像“我”一样,随着调用者(ming 或 hong)不同,指向也不同。这就是 this 的动态性——它是在函数执行时,根据调用它的对象确定的。

二、this 能做什么?

理解了 this 是动态上下文,那么它能为我们做什么呢?

  • 让同一个函数服务于不同的对象,实现代码复用;
  • 在构造函数中初始化实例属性
  • 在事件处理中方便地访问触发元素
  • 显式地指定上下文,借用其他对象的方法
  • 在回调函数中优雅地保留外层 this

下面我们就通过一个个实战场景,来体会 this 的妙用。


三、实战场景一网打尽

场景1:对象方法中的 this —— 隐式绑定

假设我们有一个用户对象,需要输出用户的名称:

javascript

const user1 = {
  name: '小明',
  greet() {
    console.log(`大家好,我是 ${this.name}`);
  }
};

user1.greet(); // 大家好,我是 小明

当 greet 作为 user1 的方法被调用时,this 指向 user1,所以能正确访问 name

能做什么:我们可以定义多个类似的对象,使用同一个方法结构,轻松访问各自的数据。

陷阱:如果把方法赋值给一个变量再调用,this 就会丢失:

javascript

const fn = user1.greet;
fn(); // 大家好,我是 undefined (非严格模式下 this 指向 window,没有 name 属性)

解决方法:使用 bind 强制绑定 this,或者用箭头函数(后面会讲)。


场景2:构造函数中的 this —— new 绑定

在面向对象编程中,我们经常用构造函数来创建对象:

javascript

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.intro = function() {
    console.log(`我叫 ${this.name},今年 ${this.age} 岁。`);
  };
}

const p1 = new Person('小红', 20);
p1.intro(); // 我叫 小红,今年 20 岁。

当使用 new 调用 Person 时,this 指向新创建的空对象,然后我们往这个对象上添加属性,最后返回这个对象。

能做什么:轻松批量创建结构相似的对象,并且每个对象的方法都能正确访问自己的属性。

注意:如果忘记写 newthis 会指向全局对象,导致全局变量污染。所以构造函数通常首字母大写,提醒自己用 new 调用。


场景3:DOM 事件处理中的 this

在浏览器中处理事件时,this 通常指向触发事件的 DOM 元素:

html

<button id="myBtn">点我</button>
<script>
  const btn = document.getElementById('myBtn');
  btn.addEventListener('click', function() {
    console.log(this); // <button id="myBtn">点我</button>
    this.textContent = '已点击';
  });
</script>

能做什么:在事件回调中直接通过 this 操作当前元素,非常方便。

注意:如果回调使用箭头函数,this 就会指向外层作用域(比如 window),无法直接操作元素。所以事件回调一般用普通函数。


场景4:显式指定 this —— call / apply / bind

有时候我们需要手动指定函数的 this,比如“借用”其他对象的方法。

javascript

const user2 = { name: '小刚' };
const user3 = { name: '小丽' };

function introduce(hobby) {
  console.log(`我是 ${this.name},喜欢 ${hobby}`);
}

introduce.call(user2, '篮球'); // 我是 小刚,喜欢 篮球
introduce.apply(user3, ['跳舞']); // 我是 小丽,喜欢 跳舞

const introduceXiaoGang = introduce.bind(user2, '足球');
introduceXiaoGang(); // 我是 小刚,喜欢 足球
  • call 和 apply 立即调用函数,区别是传参方式不同。
  • bind 返回一个新函数,永久绑定 this,可用于后续调用。

能做什么:实现函数复用,动态改变上下文;也可以用于“函数借用”,比如数组方法借用给类数组对象。


场景5:回调函数中保持 this —— 箭头函数的妙用

在异步回调或定时器中,我们经常需要访问外层的 this,但普通函数的 this 会指向全局(或 undefined 严格模式),导致无法访问期望的对象。

传统解决方式是用 var self = this 缓存,或者用 bind

javascript

function Counter() {
  this.count = 0;
  setInterval(function() {
    this.count++; // 这里的 this 指向 window,无法更新 count
    console.log(this.count);
  }, 1000);
}
new Counter(); // 输出 NaN 或 undefined

用 bind 修正:

javascript

function Counter() {
  this.count = 0;
  setInterval(function() {
    this.count++;
    console.log(this.count);
  }.bind(this), 1000);
}
new Counter(); // 1 2 3 ...

而箭头函数让这一切变得简单:箭头函数没有自己的 this,它会捕获定义时外层作用域的 this

javascript

function Counter() {
  this.count = 0;
  setInterval(() => {
    this.count++; // 这里的 this 继承自 Counter 实例
    console.log(this.count);
  }, 1000);
}
new Counter(); // 1 2 3 ...

能做什么:在回调、事件监听、Promise 等场景中,优雅地保留外层 this,避免繁琐的 self = this 或 bind

注意:箭头函数的 this 一旦确定,就无法通过 call/apply/bind 改变,所以不能用于动态上下文。


场景6:嵌套函数中的 this 问题

在对象方法内部定义普通函数,这个普通函数的 this 会指向全局(或 undefined),这常常让人困惑:

javascript

const obj = {
  name: 'obj',
  foo() {
    function bar() {
      console.log(this.name);
    }
    bar(); // 非严格模式输出 undefined 或 window.name
  }
};
obj.foo();

如何让 bar 也能访问 obj 的 name?有几种方法:

  • 用箭头函数(推荐):

    javascript

    foo() {
      const bar = () => {
        console.log(this.name);
      };
      bar(); // obj
    }
    
  • 在外层保存 this

    javascript

    foo() {
      const self = this;
      function bar() {
        console.log(self.name);
      }
      bar();
    }
    
  • 用 bind

    javascript

    foo() {
      function bar() {
        console.log(this.name);
      }
      bar.bind(this)();
    }
    

能做什么:保证嵌套函数也能访问外层对象的属性,避免作用域丢失。


四、this 绑定规则优先级(一句话总结)

当多种规则同时适用时,this 的绑定优先级是:

new 绑定 > 显式绑定(call/apply/bind) > 隐式绑定(对象方法) > 默认绑定(独立调用)

箭头函数不参与这个优先级,它完全由外层作用域决定。


五、总结与思考

回到最初的问题:this 能做什么?

  • 它让函数灵活地适应不同的调用对象,实现代码复用;
  • 它在构造函数中帮助我们初始化实例;
  • 它在事件处理中方便操作当前元素;
  • 它通过显式绑定让我们能动态指定上下文;
  • 它配合箭头函数,优雅地解决了回调中的 this 保持问题。

掌握 this 的关键,不是死记硬背规则,而是在写代码时问自己:这个函数是怎么被调用的?  调用方式决定了 this 的指向。

希望这篇文章能帮你从“this 是什么”的困惑,走向“this 能做什么”的熟练应用。如果你有更多关于 this 的实战经验或疑惑,欢迎在评论区留言讨论!


最后留个思考题:下面代码的输出是什么?为什么?

javascript

const length = 10;
function fn() {
  console.log(this.length);
}
const obj = {
  length: 5,
  method(fn) {
    fn();
    arguments[0]();
  }
};
obj.method(fn, 1);

(答案:先输出 10(或 undefined),然后输出 2。因为第一次调用 fn() 是默认绑定,第二次 arguments[0]() 是隐式绑定,this 指向 arguments 对象,其 length 是传入的参数个数,即 2。)

欢迎留言你的答案和理解!我们下期再见。

#前端、#前端面试、#干货

如果这篇这篇文章对您有帮助?关注、点赞、收藏,三连支持一下。
有疑问或想法?评论区见

甘肃农村商业银行登记成立

2026年3月18日 15:27
36氪获悉,爱企查App显示,近日,甘肃农村商业银行股份有限公司成立,法定代表人为王文永,注册资本约449.2亿元人民币,经营范围为银行业务。股东信息显示,该公司由甘肃省国有资产投资集团有限公司、甘肃能源化工投资集团有限公司、甘肃省公路交通建设集团有限公司、酒泉钢铁(集团)有限责任公司等共同持股。

小程序-下拉刷新不走回调函数

作者 喂_balabala
2026年3月18日 15:15

下拉刷新

配置与回调

  • .json 文件中添加配置开启下拉刷新
{
  "enablePullDownRefresh": true,//开启下拉刷新
  "backgroundTextStyle": "dark" //配置颜色
}
  • onPullDownRefresh 是下拉刷新的回调函数
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
    wx.showNavigationBarLoading();
},
  • stopPullDownRefresh 是自己写的停止下拉动效函数
stopPullDownRefresh() {
    wx.stopPullDownRefresh();
    wx.hideNavigationBarLoading();
},

Question

Q1: 下拉动效出来了,但是没有触发回调函数
原因: 页面问题:页面高度 = 屏幕高度,没有任何可滚动空间
  • 代码里的布局逻辑(必然是有这种结构):
page { height: 100%; }
.container { height: 100vh; }
.full_screen_container { height: 100%; }
  • 这种写法会导致:

  • 页面高度 = 手机屏幕高度 → 页面无法滚动 → 系统认为 “没有下拉动作” → 不触发 onPullDownRefresh 回调

  • 但!系统依然会播放下拉动画(因为配置开着)。

  • 下拉刷新动画是 【系统全局自动触发】 的,只要配置了 enablePullDownRefresh:true,不管页面能不能滚动、不管回调写没写,动画都会出现!

  • onPullDownRefresh ()回调函数是业务逻辑触发,必须满足页面存在可滚动区域 + 页面真的发生了下拉滚动行为才会执行!

解决方案
方案一:
  • 把根容器改成这样
/* 必须去掉固定 100% 高度!!! */
page {
  height: auto; /* 关键 */
  min-height: 100%;
}

.container {
  min-height: 100vh; /* 不能写死 height */
  overflow: visible;
}
方案二:
/* 给页面加一个看不见的高度,强制让页面可滚动 */
page::after {
  content: '';
  display: block;
  height: 1rpx;
}

字节内部发布“龙虾”相关安全规范,面向员工推出ByteClaw

2026年3月18日 15:11
字节跳动安全团队最近在内部发布了《OpenClaw安全规范和使用指引》,同步面向字节员工推出ByteClaw。该服务基于火山引擎ArkClaw企业版构建,可以在公司账号体系下实现统一的身份认证、访问控制与权限管理,支持员工安全调用公司内部资源。(新浪科技)

Python 短信接口高效集成指南:Django/Flask 框架最佳实践

2026年3月18日 15:07

在 Django/Flask 后端开发中,python 短信接口的集成是用户验证码发送、订单状态通知、风控提醒等核心业务的必备环节,但多数开发者常因框架适配逻辑不当、异步处理缺失、参数配置不规范,导致 python 短信接口响应超时、高并发下服务阻塞、错误码排查效率低等问题。本文聚焦 python 短信接口在 Django/Flask 框架的高效集成,拆解不同框架的适配原理,提供同步 / 异步两种实现方案,结合生产级优化技巧,帮助开发者快速落地高可用的短信发送功能。

b-1.jpg

一、Python 短信接口开发核心基础

1.1 短信接口通信原理

python 短信接口本质是基于 HTTP/HTTPS 协议的 RESTful 接口调用,核心逻辑可拆解为三步:1)组装认证参数(account、password)和业务参数(mobile、content);2)向短信服务商 API 地址发送请求;3)解析 JSON/XML 响应并处理业务逻辑。主流 python 短信接口均支持 POST/GET 请求,字符编码为 UTF-8,如互亿无线提供的标准化 python 短信接口文档,明确了框架适配时的参数传递规则,是行业内典型的参考范式。

1.2 Django/Flask 适配核心差异

Django 和 Flask 作为主流 Python Web 框架,集成 python 短信接口的核心差异体现在异步处理和任务调度上,具体对比如下:

表格

框架 异步实现方式 任务调度推荐 适用场景
Flask 基于 aiohttp + 协程 Celery/APScheduler 轻量应用、高并发接口
Django 基于视图异步 / Celery Celery/Django Q 中大型项目、复杂业务

二、Flask 框架集成 Python 短信接口实战

2.1 同步实现(基础版)

同步方案适合低并发的轻量场景,开发成本低、易上手,核心依赖requests库实现 HTTP 请求:

python

运行

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route('/send-sms', methods=['POST'])
def send_sms():
    """Flask同步实现Python短信接口调用"""
    # 获取请求参数
    data = request.get_json()
    mobile = data.get('mobile')
    content = data.get('content')
    
    # 手机号脱敏与格式校验(避免完整手机号泄露)
    if not mobile or len(mobile) != 11:
        return jsonify({"code": 406, "msg": "手机号格式不正确"})
    safe_mobile = mobile[:3] + "****" + mobile[7:]
    
    # 短信接口配置(注:需通过注册链接获取APIID/APIKEY:http://user.ihuyi.com/?udcpF6)
    config = {
        "api_url": "https://api.ihuyi.com/sms/Submit.json",
        "account": "你的APIID",  # 替换为实际APIID
        "password": "你的APIKEY"  # 替换为实际APIKEY
    }
    
    # 组装请求参数(符合接口UTF-8编码规范)
    params = {
        "account": config["account"],
        "password": config["password"],
        "mobile": mobile,
        "content": content
    }
    
    try:
        # 发送同步POST请求,设置10秒超时避免阻塞
        response = requests.post(
            config["api_url"],
            data=params,
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            timeout=10
        )
        result = response.json()
        app.logger.info(f"手机号[{safe_mobile}]短信发送结果:{result}")
        return jsonify(result)
    except requests.exceptions.Timeout:
        return jsonify({"code": 0, "msg": "请求超时"})
    except Exception as e:
        return jsonify({"code": 0, "msg": f"发送失败:{str(e)}"})

if __name__ == "__main__":
    app.run(debug=True)

2.2 异步优化(高并发版)

同步方案会阻塞 Flask 主线程,高并发场景下需基于aiohttp协程实现异步调用,核心代码如下:

python

运行

from flask import Flask, request, jsonify
import aiohttp
import asyncio

app = Flask(__name__)

async def async_send_sms(mobile, content):
    """异步调用Python短信接口(非阻塞)"""
    config = {
        "api_url": "https://api.ihuyi.com/sms/Submit.json",
        "account": "你的APIID",
        "password": "你的APIKEY"
    }
    params = {
        "account": config["account"],
        "password": config["password"],
        "mobile": mobile,
        "content": content
    }
    
    async with aiohttp.ClientSession() as session:
        async with session.post(
            config["api_url"],
            data=params,
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            timeout=aiohttp.ClientTimeout(total=10)
        ) as resp:
            return await resp.json()

@app.route('/async-send-sms', methods=['POST'])
def async_send_sms_view():
    """Flask异步短信发送接口"""
    data = request.get_json()
    mobile = data.get('mobile')
    content = data.get('content')
    
    if not mobile or len(mobile) != 11:
        return jsonify({"code": 406, "msg": "手机号格式不正确"})
    
    # 启动协程任务,避免阻塞主线程
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    result = loop.run_until_complete(async_send_sms(mobile, content))
    loop.close()
    
    return jsonify(result)

if __name__ == "__main__":
    app.run(debug=True)

三、Django 框架集成 Python 短信接口最佳实践

3.1 基于视图函数的同步实现

Django 基础版集成方案适配快速开发场景,通过视图函数直接调用 python 短信接口:

python

运行

# sms/views.py
from django.http import JsonResponse
from django.views.decorators.http import require_POST
import requests

@require_POST
def send_sms(request):
    """Django同步实现Python短信接口调用"""
    mobile = request.POST.get('mobile')
    content = request.POST.get('content')
    
    # 手机号校验与脱敏
    if not mobile or len(mobile) != 11:
        return JsonResponse({"code": 406, "msg": "手机号格式不正确"})
    safe_mobile = mobile[:3] + "****" + mobile[7:]
    
    # 接口基础配置
    config = {
        "api_url": "https://api.ihuyi.com/sms/Submit.json",
        "account": "你的APIID",
        "password": "你的APIKEY"
    }
    
    params = {
        "account": config["account"],
        "password": config["password"],
        "mobile": mobile,
        "content": content
    }
    
    try:
        response = requests.post(
            config["api_url"],
            data=params,
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            timeout=10
        )
        result = response.json()
        return JsonResponse(result)
    except Exception as e:
        return JsonResponse({"code": 0, "msg": f"发送失败:{str(e)}"})

# urls.py 配置路由
from django.urls import path
from . import views

urlpatterns = [
    path('send-sms/', views.send_sms, name='send-sms'),
]

demo-python.png

3.2 结合 Celery 的异步发送(生产级)

Django 生产环境中,推荐用 Celery 处理异步任务,避免阻塞 WSGI 进程,核心实现如下:

python

运行

# sms/tasks.py(Celery异步任务)
from celery import shared_task
import requests

@shared_task
def send_sms_task(mobile, content):
    """Celery异步任务:发送短信"""
    config = {
        "api_url": "https://api.ihuyi.com/sms/Submit.json",
        "account": "你的APIID",
        "password": "你的APIKEY"
    }
    
    params = {
        "account": config["account"],
        "password": config["password"],
        "mobile": mobile,
        "content": content
    }
    
    try:
        response = requests.post(
            config["api_url"],
            data=params,
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            timeout=10
        )
        return response.json()
    except Exception as e:
        return {"code": 0, "msg": str(e)}

# sms/views.py(视图调用异步任务)
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from .tasks import send_sms_task

@require_POST
def async_send_sms(request):
    mobile = request.POST.get('mobile')
    content = request.POST.get('content')
    
    if not mobile or len(mobile) != 11:
        return JsonResponse({"code": 406, "msg": "手机号格式不正确"})
    
    # 提交Celery任务(非阻塞,立即返回)
    task = send_sms_task.delay(mobile, content)
    return JsonResponse({"code": 2, "msg": "任务已提交", "task_id": task.id})

四、Python 短信接口常见问题排查与优化

4.1 高频错误码解析

集成 python 短信接口时,以下错误码占比超 80%,对应解决方案如下:

  1. 错误码 405:API ID/KEY 错误 → 核对注册的认证信息,确保无拼写 / 空格错误;
  2. 错误码 4052:访问 IP 与备案 IP 不符 → 在短信服务商后台配置服务器 IP 白名单;
  3. 错误码 4072:内容与模板不匹配 → 严格按审核通过的模板拼接变量,禁止篡改固定内容;
  4. 错误码 4085:单手机号单日验证码超限 → 前端增加 60 秒发送间隔,后端记录发送次数并限制。

4.2 跨框架通用优化技巧

  1. 参数前置校验:对手机号格式(11 位数字)、短信内容长度(≤500 字)做前置校验,减少无效接口调用;
  2. 手机号脱敏:日志 / 返回结果中仅保留脱敏手机号(如 138****1234),避免数据泄露;
  3. 超时控制:所有 python 短信接口调用设置 10 秒超时,防止长时间阻塞框架进程;
  4. 重试机制:对网络波动导致的 4086 错误,设置 1-2 次重试(间隔 1 秒),降低失败率;
  5. 日志埋点:记录请求参数(脱敏)、响应结果、耗时,便于线上问题快速定位。

五、Django vs Flask 集成方案对比

表格

维度 Django 集成方案 Flask 集成方案
异步实现 Celery(成熟稳定) aiohttp 协程(轻量高效)
开发成本 中(需配置 Celery) 低(协程直接调用)
并发能力 高(Celery 分布式) 高(协程非阻塞)
生产适配 适合中大型项目 适合轻量微服务
学习曲线 较陡(Celery 配置) 平缓(协程易理解)

总结

  1. python 短信接口在 Django/Flask 中的集成核心是适配框架的异步特性,Flask 优先用 aiohttp 协程实现轻量异步,Django 生产环境推荐结合 Celery 实现分布式异步发送;
  2. 开发时需重点关注参数校验、手机号脱敏、超时控制,针对 405/4052/4072 等高频错误码做好针对性处理;
  3. 不同框架的集成方案各有优劣,需根据项目规模(轻量 / 中大型)选择适配方式,确保 python 短信接口的高可用与高性能。

年内逾20只FOF募集规模超10亿元

2026年3月18日 15:07
3月18日,2只募集规模超10亿元的FOF成立,万家润安稳健三个月持有期混合FOF成立,募集规模13.66亿元,获4162户有效认购。景顺长城和熙睿安三个月持有期混合FOF成立,募集规模13.63亿元,获8162户有效认购。包括这两只产品在内,2026年以来募集规模超10亿元以上的FOF数量,已超过20只。(证券时报)

A股三大指数集体收涨,全市场超3500股飘红

2026年3月18日 15:01
36氪获悉,A股三大指数集体收涨,沪指涨0.32%,深成指涨1.05%,创业板指涨2.02%;存储、算力股爆发,新易盛涨超10%,佰维存储、天孚通信、江波龙涨超8%;锂电、油气走弱,洲际油气、通源石油跌超8%,多氟多跌近5%;新股N族兴上市首日大涨超400%;个股涨多跌少,全市场超3500股飘红。

全面解析WhatsApp Web抓包:原理、工具与安全

2026年3月18日 14:56

“全面解析WhatsApp Web抓包:原理、工具与安全”

1. WhatsApp Web的基本原理与架构

WhatsApp Web是WhatsApp的一个网页版应用,它允许用户通过浏览器与手机端的WhatsApp进行同步,实现信息的发送与接收。其基本原理主要依赖于二维码扫描和端到端加密技术。

首先,WhatsApp Web的工作流程始于用户在浏览器中访问WhatsApp Web的官方网站。用户会看到一个二维码,接下来需要用手机上的WhatsApp应用进行扫描。通过扫描二维码,手机端的WhatsApp应用与网页版建立了一个安全的连接。这个二维码实际上包含了一个临时的会话令牌,确保只有经过授权的设备才能访问用户的消息。

WhatsApp Web的架构基于客户端-服务器模型。用户的手机是主要的客户端,负责处理消息的接收和发送,而浏览器则充当另一个客户端。两者之间通过WebSocket协议进行实时通信。WebSocket是一种在单个TCP连接上进行全双工通信的协议,允许数据在客户端与服务器之间快速传输。这种设计的优势在于可以实现即时消息推送,确保用户在网页版上能够及时接收到来自手机端的消息。

在安全性方面,WhatsApp Web采用了端到端加密技术。这意味着消息在发送时会被加密,只有发送者和接收者能够解密查看。这种加密机制确保了即使数据在传输过程中被截获,第三方也无法读取消息内容。此外,WhatsApp Web的连接是基于HTTPS协议的,进一步增强了数据传输的安全性。

除了消息的发送与接收,WhatsApp Web还支持多种功能,包括查看联系人、发送图片和文件、以及进行语音和视频通话等。这些功能的实现同样依赖于与手机端的实时同步,确保用户在不同设备上获得一致的使用体验。

总的来说,WhatsApp Web通过二维码扫描实现设备间的快速连接,利用WebSocket协议实现实时数据传输,并通过端到端加密保障消息的安全性。这种设计不仅提升了用户体验,也确保了用户的隐私安全,为现代通讯方式提供了一个创新的解决方案。

2. 抓包工具的选择与使用方法

抓包工具的选择与使用方法是进行WhatsApp Web分析的关键步骤。首先,常用的抓包工具有Fiddler、Charles Proxy和Wireshark等,这些工具能够帮助用户捕获网络请求并分析数据。 Sniffmaster作为一款全平台抓包工具,支持HTTPS、TCP和UDP协议,可在iOS/Android/Mac/Windows设备上实现无需代理、越狱或root的抓包操作,特别适合移动应用如WhatsApp Web的分析。

在选择工具时,用户需考虑其操作系统的兼容性以及工具的功能特点。例如,Fiddler和Charles Proxy对HTTP/HTTPS流量的支持非常好,适合初学者使用,而Wireshark则适合需要深入分析网络流量的用户,Sniffmaster好上手。

在实际使用过程中,用户需要先配置代理,确保抓包工具能够捕获到WhatsApp Web的流量。在此过程中,注意要能上外网,以便能够顺利连接到WhatsApp的服务器。安装和配置工具后,用户可以通过浏览器访问WhatsApp Web,抓包工具将实时显示网络请求和响应数据,用户可以根据需要分析特定的请求,查看其中的参数和数据内容。这对理解WhatsApp Web的工作原理以及数据传输方式非常有帮助。在进行数据分析时,用户还需关注隐私安全问题,确保不泄露个人信息或敏感数据。在抓包过程中,建议保持对数据的保密性,避免将抓取的数据公开或分享给不信任的第三方。

3. 数据分析与隐私安全的考虑

在进行WhatsApp Web的抓包分析时,数据的隐私安全问题是一个不可忽视的重要方面。随着网络安全威胁的不断增加,用户的个人信息和通信内容面临着潜在的风险。因此,在进行数据分析时,我们需要充分考虑以下几个方面。

首先,抓包过程中获取的数据通常包含用户的消息内容、联系人信息以及媒体文件等敏感数据。这些数据如果落入不法分子之手,可能会导致用户隐私泄露、身份盗窃等严重后果。因此,在使用抓包工具时,务必遵循相关法律法规,确保只在合法范围内进行数据分析,并且要获得相关人员的同意。

其次,进行数据分析时,使用的工具和方法也需谨慎选择。当前市场上存在多种抓包工具,如Fiddler、Charles等,这些工具虽功能强大,但若不加以妥善使用,可能会引发安全隐患。例如,某些抓包工具可能会在未授权的情况下存储用户数据,或是通过不安全的网络传输数据,从而导致数据被窃取。因此,选择可靠的工具,并定期更新其安全补丁,是保护数据安全的有效措施。

然后,在数据分析过程中,建议对敏感信息进行脱敏处理。通过对数据进行加密、匿名化或是只提取必要信息,可以在一定程度上降低数据泄露的风险。同时,分析结果应仅限于内部使用,避免将敏感数据以任何形式公开或分享,确保用户隐私不被侵犯。

此外,用户自身在使用WhatsApp Web时,也应加强安全意识。定期更新密码、启用双重身份验证、避免在公共网络环境下使用WhatsApp Web等都是提升个人信息安全的有效手段。用户应时刻保持警惕,关注账户的异常活动,一旦发现可疑行为,应立即采取措施保护自己的账户安全。

最后,数据分析的结果应有助于提升WhatsApp Web的安全性。通过对抓取的数据进行深入分析,可以识别潜在的安全漏洞和风险点,从而为开发者提供改进产品安全性的依据。这不仅有助于保护用户的隐私安全,也能增强用户对平台的信任,推动整个社交网络环境的健康发展。

综上所述,在进行WhatsApp Web的抓包与数据分析时,隐私安全问题不容忽视。通过合法合规的方式、选择合适的工具、进行数据脱敏处理以及增强用户安全意识,我们能够在享受便捷通信服务的同时,有效保护个人隐私与信息安全。

年内近40只主动权益基金募集规模超10亿元

2026年3月18日 14:53
��据Wind统计,3月18日全市场有7只主动权益基金成立(以普通股票基金和偏股混合基金为统计口径),其中有5只募集规模超10亿元。易方达研究智选股票基金募集规模17.32亿元,获1.35万户有效认购。交银远见精选混合成立,募集规模15.93亿元,获9353户有效认购。兴业臻选回报混合成立,募集规模34.99亿元,获2.72万户有效认购。景顺长城信优成长混合基金成立,募集规模25.92亿元,获1.93万户有效认购。平安久瑞回报混合募集规模11.87亿元,获4829户有效认购。包括5只基金在内,2026年以来募集规模在10亿元以上的主动权益基金,已接近40只。(证券时报)

独立开发了一个睡眠记录 App:SleepDiary / 睡眠声音日记

作者 Flutter笔记
2026年3月18日 14:50

最近一直在弄一个睡眠记录 App,名字叫

SleepDiary / 睡眠声音日记

已经上架 App Store 了,直接搜名字可以搜到。

这东西我其实做了挺久了,中间一直在反复改。
最近才慢慢觉得,差不多到了一个能发出来聊聊的阶段。

最开始想做,原因也不复杂。
就是我自己之前看过一些睡眠类产品,总觉得不太顺手。
要么广告很多,要么功能特别杂。
本来只是想看看晚上有没有鼾声、睡得怎么样,结果经常还得被一些很重的流程打断。

所以我做这个的时候,想法一直挺简单的:
打开就能录,醒来能看,别整太复杂。

我自己这段时间已经连续用了很多晚,边用边改。
首页、历史、单晚详情这些地方都来回调了很多次。
尤其是单晚详情,我自己会比较在意。
因为如果只是告诉你“昨晚有鼾声”,其实没什么意思。
但如果能大概看到什么时间段更明显,和整晚记录能对起来,那这个东西至少会更像个能参考的工具。

还有就是,这类 App 本来就比较私人。
毕竟会涉及睡眠、声音这些东西。
所以我自己做的时候,鼾声识别都是用的端侧模型,不会上传。
不一定一步到位,但至少会一直往这个方向抠。

发出来主要也是想看看,这里会不会有人对这种东西有兴趣。
不是想听“看起来不错”这种话,主要还是想知道更实际一点的:

你会不会真的用睡眠记录类 App?
你到底会看什么?
是看单晚,还是看一段时间的变化?
如果是鼾声、梦话这种信息,你会希望它怎么给你看,才算有用?

有想法都可以聊聊。

TS 入门:给 React 穿上“防弹衣”

作者 玉米Yvmi
2026年3月18日 14:50

前言
JavaScript 像是一位随性的艺术家,自由但易错;TypeScript 则是一位严谨的工程师,用类型系统为我们筑起防线。

很多新手觉得 TS 繁琐,那是还没掌握“正确姿势”。今天,我不讲枯燥理论,直接通过实战场景,带你把 TS 融入 React 的血脉。

一、组件的“身份证”:Props 精准定义

在 JS 中,Props 靠“口头约定”;在 TS 中,Props 必须有“身份证”。

传错参数?漏传必填项?运行时才报错?NO!

使用 interface 定义契约,利用 React.ReactNode 兼容所有内容。

// 第一步:定义契约
interface AaaProps {
  name: string;        // 必填:必须是字符串
  age?: number;        // 可选:注意那个问号 '?'
  content: React.ReactNode; // 万能容器:字符串/JSX/Fragment 都能装
}

// 第二步:应用契约 (推荐写法)
function Aaa({ name, content }: AaaProps) {
  return <div> Hi, {name} | {content}</div>;
}

// 第三步:安全使用
export default function App() {
  // TS 会立刻拦截:如果忘记传 name,或者 content 传了数字,直接标红!
  return <Aaa name="玉米🌽" content={<span>我是内容</span>} />;
}
  • ? 的作用:明确区分“可有可无”和“必须拥有”。
  • React.ReactNode:比 any 安全,比 string 灵活,它是 React 内容的“最大公约数”。
  • 解构赋值:直接在函数参数中解构 { name },代码更清爽,TS 依然能自动推断类型。

二、Hooks 的“导航仪”:泛型让状态不再模糊

useStateuseRef 是 React 的左右手,但在 TS 中,如果不加泛型 <T>,它们就像失去了导航的船。

场景 A:状态初始化

// 没给初始值时,TS 默认它是 undefined
const [num, setNum] = useState<number>(); 
// 类型推断:number | undefined

// 给了初始值,TS 就知道它永远是 number
const [count, setCount] = useState<number>(0); 
// 类型推断:number

场景 B:Ref 的双重身份

useRef 既能抓 DOM,也能存数据。怎么区分?看泛型!

// 身份 1:DOM 捕手
const inputRef = useRef<HTMLInputElement>(null);
// current 可能是 HTMLInputElement 或 null

// 身份 2:数据储物柜 (不触发重渲染)
const storeRef = useRef<{ num: number }>(null);

// 安全赋值
if (storeRef.current) {
  storeRef.current.num = 2; // TS 知道这里有 num 属性
}

泛型就像一个**“模具”**。

  • 倒入 HTMLInputElement,它就是抓 Input 的夹子。
  • 倒入 { num: number },它就变成了存数据的盒子。
  • 如果不指定模具,TS 就只能给你一团模糊的橡皮泥(any 或推断错误)。

三、打通任督二脉:ForwardRef 的类型接力

父组件想操作子组件的 DOM?forwardRef 是桥梁,但 TS 需要知道这座桥通向哪里。

核心三步走

// 定义子组件:明确 Ref 的目标是 input
const Child = forwardRef<HTMLInputElement>((props, ref) => {
  return <input ref={ref} placeholder="请聚焦我" />;
});

// 父组件声明:Ref 类型必须与子组件一致
const parentRef = useRef<HTMLInputElement>(null);

// 安全调用:使用可选链 '?.' 防止 null 报错
useEffect(() => {
  parentRef.current?.focus(); 
}, []);

如果子组件说“我要 Input”,父组件却传了个 div 的 ref,TS 编译器会直接亮红灯。这种端到端的类型检查,彻底杜绝了 Cannot read property 'focus' of null 的低级错误。

四、性能优化的“类型护航”

当项目变大,useReducermemo 登场。TS 能让你的优化逻辑无懈可击。

状态建模:Action 联合类型

这是 TS 最强大的特性之一:判别联合类型

// 定义状态
interface State { result: number; }

// 定义动作 (关键!限制 type 的取值)
type Action = 
  | { type: 'add'; num: number } 
  | { type: 'minus'; num: number };

// Reducer:TS 会自动根据 type 推断 action 的结构
function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'add': 
      // 这里 TS 知道 action 一定有 num
      return { result: state.result + action.num };
    case 'minus':
      return { result: state.result - action.num };
    default:
      return state;
  }
}

配合 Memo 优化

// 缓存计算结果
const count = useMemo(() => res.result * 10, [res.result]);

// 缓存函数引用 (防止子组件无效渲染)
const cb = useCallback(() => 666, []);

// 子组件:只有 props 变了才渲染
const Child = memo(({ count }: { count: number }) => (
  <h2>计算结果:{count}</h2>
));

如果你手误写了 dispatch({ type: 'delete' ... }),TS 会立刻告诉你:“没有 delete 这个动作!”。这在 JS 中可能要等到用户点击按钮报错了才能发现。

结语

TypeScript 初看是束缚,实则是赋予你重构底气的“防弹衣”。它让你从“运行后报错”的被动救火,转向“编写时即知”的主动掌控,将潜在的隐患扼杀在编译阶段。

不必追求一步到位,渐进式地收窄每一个 any,都是在为代码大厦加固地基。当你习惯了类型系统带来的智能提示与安全边界,便真正完成了从“码农”到“工程师”的思维跃迁。

松延动力在常熟成立科技新公司

2026年3月18日 14:47
36氪获悉,爱企查App显示,近日,松延智展(常熟)科技有限公司成立,法定代表人为姜哲源,注册资本3000万元人民币,经营范围包括人工智能理论与算法软件开发、服务消费机器人制造、智能机器人的研发等。股东信息显示,该公司由北京松延动力科技集团股份有限公司全资持股。

美团买药启动健康指数公益计划

2026年3月18日 14:40
36氪获悉,近日,美团买药正式宣布启动“健康指数公益计划”。该计划将依托平台海量的搜索、问诊及购药趋势所沉淀的“健康指数”数据,免费向疾控中心、公园等非营利性机构开放,旨在为公众在花粉季、高温季等季节性健康高发期,提供健康防护指引。

js并发请求,且限制并发请求数量实现方案

2026年3月18日 14:37

说明

  • 前端会遇到这种需求,希望多个请求并发加快前端反应速度,但又要限制同时请求的数量,防止服务器压力过大
  • 以下代码由Trae里的千问模型生成,思路真牛

方案

async function batchQuset(){
      this.$store.commit('openLoading')
      const questNum = this.paramsList.length
      // 每批最多 3 个并发请求
      const BATCH_SIZE = 3
      // 保持顺序的结果数组
      const numResList = new Array(questNum).fill(null) 
      // 并发控制函数
      const runWithConcurrency = async (tasks, concurrency) => {
        const results = []
        // 维护一个正在执行的 Promise 列表(控制并发就靠它)
        const executing = []
        for (const task of tasks) {
          // p 是 then() 方法返回的新 Promise,不是 task() 的原始 Promise
          const p = task().then((result) => {
            // 当task执行完成后,从executing数组中移除
            executing.splice(executing.indexOf(p), 1)
            return result
          })
          results.push(p)
          executing.push(p)
          // 当正在执行的任务数量超过并发限制时,等待任意一个完成
          if (executing.length >= concurrency) {
            // 等有完成的Promise时,外面的for循环才能继续走
            await Promise.race(executing)
          }
        }
        // 走到这里时,仅剩下小于并发数量的Promise还没彻底完成
        return Promise.all(results)
      }
      // 创建所有校验任务[Promise,Promise]
      const tasks = this.paramsList.map(
        (params, index) => async () => {
          const { pass, res } = await questApi(params)
          this.$store.commit(
            'openLoading',
            `进度: ${index + 1}/${questNum}`
          )
          return { index, pass, res }
        }
      )
      // 执行并发校验
      const results = await runWithConcurrency(tasks, BATCH_SIZE)
      // 按原始顺序填充结果
      results.forEach(({ index, pass, res }) => {
        if (!pass) {
          numResList[index] = res
        }
      })
      // 过滤掉 null 值,得到最终的列表
      const resList = numResList.filter((item) => item !== null)
      this.$store.commit('closeLoading')
      // *****请求结果resList进行展示/处理******
}

说明

  • this.$store.commit('openLoading')是自己把element的loading二次封装,方便唤起和改文字
import Vuex from "vuex";
import { Loading } from 'element-ui';
export default new Vuex.Store({
    state: {
    // 全屏loading实例
    loading: null,
    },
    mutations:{
     openLoading(state, str) {
      if (state.loading) {
        state.loading.setText(str)
      } else {
        state.loading = Loading.service({
          lock: true,
          text: str,
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)',
          customClass: 'phone-loading'
        })
      }
    },
    closeLoading(state) {
      state.loading?.close()
      state.loading = null
    },
    }
})
  • then 中 return result 的作用 :
    • 当 then 的回调函数执行完毕后, p 这个 Promise 会被 resolve
    • p 被 resolve 的值就是 return 后面的值
    • 如果 return result ,则 p 解析为 result
    • 如果不 return 或 return undefined ,则 p 解析为 undefined
// 示例 1:return result
const p1 = task().then((result) => {
  console.log('收到 result:', result)  // 假设 result = '任务完成'
  return result  // return '任务完成'
})

p1.then((value) => {
  console.log('p1 的值:', value)  // 输出:'任务完成'
})

// 示例 2:不 return
const p2 = task().then((result) => {
  console.log('收到 result:', result)  // 假设 result = '任务完成'
  // 没有 return 语句
})

p2.then((value) => {
  console.log('p2 的值:', value)  // 输出:undefined
})

// 示例 3:return 其他值
const p3 = task().then((result) => {
  console.log('收到 result:', result)  // 假设 result = '任务完成'
  return '修改后的值'
})

p3.then((value) => {
  console.log('p3 的值:', value)  // 输出:'修改后的值'
})

百度推动大模型与搜推业务融合,何径舟任百度APP研发中心组织负责人

2026年3月18日 14:33
36氪获悉,日前,百度任命原大模型算法部何径舟自基础模型研发部(BMU)轮岗至移动生态事业群组(MEG),担任百度APP研发中心组织负责人,向罗戎汇报。原负责人赵世奇因个人原因离职。据知情人士透露,何径舟为百度自己培养的技术和管理型人才,在大模型算法领域有丰厚积累。此次轮岗将进一步推动大模型与搜推业务融合,强化大模型等前沿技术在搜索、推荐等核心场景的应用,推动产品迭代速度与质量双提升,帮助产品更好地面对技术代际变革,进一步提升用户体验。

创业板指拉升涨超2%

2026年3月18日 14:32
36氪获悉,创业板指拉升涨超2%,沪指涨0.22%,深成指涨1.01%。算力硬件、算力租赁、算电协同等方向涨幅居前,沪深京三市上涨个股近3500只。

顺丰同城与云迹科技达成战略合作

2026年3月18日 14:31
36氪获悉,近日,顺丰同城与云迹科技在深圳顺丰同城总部签署战略合作协议。双方将聚焦商务办公楼、酒店等高层建筑末端配送场景,通过“骑士+机器人”协同接力模式简化楼宇配送流程,破解楼宇配送“最后100米”效率瓶颈,为用户提供无接触上门配送服务。

新日铁获得9000亿日元贷款,用于收购美国钢铁

2026年3月18日 14:25
新日铁周三在一份声明中表示,已从日本国际协力银行(JBIC)和日本主要私人贷款机构获得总额达9000亿日元(约合56.7亿美元)的贷款,用于收购美国钢铁公司。这些贷款机构包括日本三大“巨型银行”——三菱日联银行、三井住友银行和瑞穗银行,以及三井住友信托银行。(新浪财经)
❌
❌