当前位置: 首页 > news >正文

第20章 Day24 原型链

原型链

EventTarget 不是 Window 的"构造函数"

EventTarget 也是一个构造函数,Window 也是一个构造函数。它们之间是构造函数的继承关系

正确的理解

// 两个构造函数之间的继承
Object.setPrototypeOf(Window, EventTarget)
// 结果:Window.__proto__ === EventTarget
// 意思:Window 构造函数继承自 EventTarget 构造函数

不是说 EventTarget 是 Window 的构造函数,而是说:

  • Window 是一个构造函数
  • EventTarget 也是一个构造函数
  • Window 构造函数继承自 EventTarget 构造函数

类比 ES6 class

// 相当于:
class EventTarget {addEventListener() {}
}class Window extends EventTarget {  // Window 继承自 EventTarget// Window 的方法
}// 在 ES6 中:
console.log(Window.__proto__ === EventTarget); // true

完整的继承链

// 构造函数继承链
Window.__proto__ === EventTarget              // Window 构造函数继承自 EventTarget 构造函数
EventTarget.__proto__ === Function.prototype // EventTarget 构造函数继承自 Function.prototype// 原型链  
Window.prototype.__proto__ === WindowProperties.prototype
WindowProperties.prototype.__proto__ === EventTarget.prototype
EventTarget.prototype.__proto__ === Object.prototype// 实例链
window.__proto__ === Window.prototype         // window 是 Window 的实例

总结

  • EventTarget 是构造函数
  • Window 也是构造函数,但它继承自 EventTarget 构造函数
  • window 是 Window 构造函数的实例

所以更准确的说法是:"Window 构造函数继承自 EventTarget 构造函数",而不是 "EventTarget 是 Window 的构造函数"。

构造函数判定

// 在浏览器中

console.log(typeof Window);                    // "function"
console.log(Window.prototype);                 // Window.prototype 对象
console.log(Window.prototype.constructor === Window); // true
console.log(window instanceof Window);         // true
console.log(window.constructor === Window);    // true

总结 构造函数之间的继承就是 Object.setPrototypeOf(Window, EventTarget);

完整的继承结构

// 1. 构造函数之间的继承
Window.__proto__ === EventTarget                    // 构造函数继承// 2. 原型对象之间的继承  
Window.prototype.__proto__ === WindowProperties.prototype     // 实例方法继承
WindowProperties.prototype.__proto__ === EventTarget.prototype // 实例方法继承// 3. 实例的继承链
window.__proto__ === Window.prototype              // window 是 Window 的实例

基本对! 但有一个小错误,让我修正一下:

✅ 正确的三种继承

1. 构造函数继承

Object.setPrototypeOf(x, y)
// 结果:x.__proto__ === y
// 例子:Object.setPrototypeOf(Window, EventTarget)

2. 实例方法继承(原型对象之间的继承)

Object.setPrototypeOf(x.prototype, y.prototype)  
// 结果:x.prototype.__proto__ === y.prototype
// 例子:Object.setPrototypeOf(Window.prototype, WindowProperties.prototype)

3. 实例的继承链 ❌

// ❌ 错误
Object.setPrototypeOf(x, y.prototype)  // ✅ 正确  
Object.setPrototypeOf(instance, Constructor.prototype)
// 结果:instance.__proto__ === Constructor.prototype
// 例子:Object.setPrototypeOf(window, Window.prototype)

为什么第3个不对?

第3种是让一个对象成为某个构造函数的实例,格式应该是:

// 让对象 obj 成为构造函数 Constructor 的实例
Object.setPrototypeOf(obj, Constructor.prototype)// 而不是:
Object.setPrototypeOf(Constructor, OtherConstructor.prototype) // 这个没意义

完整示例

// 1. 构造函数继承
Object.setPrototypeOf(Window, EventTarget);
console.log(Window.__proto__ === EventTarget); // true// 2. 原型对象继承(实例方法继承)
Object.setPrototypeOf(Window.prototype, WindowProperties.prototype);
console.log(Window.prototype.__proto__ === WindowProperties.prototype); // true// 3. 实例的继承链
Object.setPrototypeOf(window, Window.prototype);
console.log(window.__proto__ === Window.prototype); // true
console.log(window instanceof Window); // true

总结

实例的继承链Object.setPrototypeOf(实例对象, 构造函数.prototype)

Navigator

function analyzeNavigatorGetters() {const proto = Navigator.prototype;const descriptors = Object.getOwnPropertyDescriptors(proto);const analysis = {getters: {},regularProperties: {}, // 添加常规属性收集summary: {totalProperties: 0,getterProperties: 0,regularProperties: 0,errors: []}};for (const [key, descriptor] of Object.entries(descriptors)) {analysis.summary.totalProperties++;if (descriptor.get) {// 处理getter属性analysis.summary.getterProperties++;try {analysis.getters[key] = {value: descriptor.get.call(navigator),enumerable: descriptor.enumerable,configurable: descriptor.configurable,hasGetter: true,hasSetter: !!descriptor.set,getterFunction: descriptor.get,descriptor: descriptor};} catch (e) {analysis.summary.errors.push(`${key}: ${e.message}`);analysis.getters[key] = {value: null,error: e.message,enumerable: descriptor.enumerable,configurable: descriptor.configurable,hasGetter: true,hasSetter: !!descriptor.set,getterFunction: descriptor.get,descriptor: descriptor};}} else {// 处理常规属性analysis.summary.regularProperties++;try {// 尝试获取属性值let value = navigator[key];analysis.regularProperties[key] = {value: value,enumerable: descriptor.enumerable,configurable: descriptor.configurable,writable: descriptor.writable,hasGetter: false,hasSetter: false,descriptor: descriptor};} catch (e) {analysis.summary.errors.push(`Regular property ${key}: ${e.message}`);analysis.regularProperties[key] = {value: null,error: e.message,enumerable: descriptor.enumerable,configurable: descriptor.configurable,writable: descriptor.writable,hasGetter: false,hasSetter: false,descriptor: descriptor};}}}return analysis;
}// 使用
const analysis = analyzeNavigatorGetters();
console.log('分析结果:', analysis);
console.log('总属性数:', analysis.summary.totalProperties);
console.log('Getter 属性数:', analysis.summary.getterProperties);
console.log('常规属性数:', analysis.summary.regularProperties);
console.log('常规属性:', analysis.regularProperties);
console.log('错误:', analysis.summary.errors);

拿到toStirng

const desc = Object.getOwnPropertyDescriptor(window, 'location');
console.log(desc.get.toString());

待测试 toStirng保护

(() => {'use strict';// 取原型链上的toStringconst $toString = Function.toString;// 取方法名 symbolconst myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));const myToString = function () {return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);};function set_native(func, key, value) {Object.defineProperty(func, key, {"enumerable": false,"configurable": true,"writable": true,"value": value})}// 保护 getter/setter 的函数function protect_getter_setter(obj, prop, customNames = {}) {const descriptor = Object.getOwnPropertyDescriptor(obj, prop);if (!descriptor) return;// 保护 getterif (descriptor.get) {const propName = customNames.getter || prop;const getterStr = `function get ${propName}() { [native code] }`;set_native(descriptor.get, myFunction_toString_symbol, getterStr);}// 保护 setterif (descriptor.set) {const propName = customNames.setter || prop;const setterStr = `function set ${propName}() { [native code] }`;set_native(descriptor.set, myFunction_toString_symbol, setterStr);}}// 批量保护对象的所有 getter/setterfunction protect_all_getters_setters(obj, customNames = {}) {const descriptors = Object.getOwnPropertyDescriptors(obj);for (const [prop, desc] of Object.entries(descriptors)) {if (desc.get || desc.set) {const names = customNames[prop] || {};protect_getter_setter(obj, prop, names);}}}delete Function.prototype['toString'];set_native(Function.prototype, "toString", myToString);set_native(Function.prototype.toString, myFunction_toString_symbol, "function toString() { [native code] }");// 扩展的全局函数globalThis.safefunction = (func, name) => {const funcName = name || func.name || '';set_native(func, myFunction_toString_symbol, `function ${funcName}() { [native code] }`);};// 保护 getter/setterglobalThis.safeGetter = (obj, prop, customNames = {}) => {protect_getter_setter(obj, prop, customNames);};// 批量保护globalThis.safeAllGetters = (obj, customNames) => {protect_all_getters_setters(obj, customNames);};// 创建安全的属性定义globalThis.safeDefineProperty = (obj, prop, descriptor, customNames = {}) => {Object.defineProperty(obj, prop, descriptor);if (descriptor.get) {const propName = customNames.getter || prop;const getterStr = `function get ${propName}() { [native code] }`;set_native(descriptor.get, myFunction_toString_symbol, getterStr);}if (descriptor.set) {const propName = customNames.setter || prop;const setterStr = `function set ${propName}() { [native code] }`;set_native(descriptor.set, myFunction_toString_symbol, setterStr);}};}).call(globalThis);

提示:

// 在控制台创建一个 div 元素
const div = document.createElement('div');
div.className = 'foo bar baz'; // 给它设置一些类名
console.log(div.classList); // 这会返回一个 DOMTokenList 对象

参数:

{
"_method": "GET",
"_url": "/aweme/v1/web/solution/resource/list/?spot_keys=7359502129541449780_douyin_spec_theme&app_id=6383&update_version_code=170400&pc_client_type=1&pc_libra_divert=Mac&support_h265=1&support_dash=0&cpu_core_num=4&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1440&screen_height=900&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=137.0.0.0&browser_online=true&engine_name=Blink&engine_version=137.0.0.0&os_name=Mac+OS&os_version=10.15.7&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7517282755928573449&uifid=163eead721bc91ca6f3a3cb4766a73c0638fabced1012e02c28bcbf3169aca5c44c51fa6beff8f1f2615be624638d06d91c6d0ff5636b21eb7b8a473d4d2e7e8aeb97f1b374c801db9850467ee095467",
"_vc_status": 1,
"_vc_actionList": [
{
"fnName": "open",
"arguments": {
"0": "GET",
"1": "/aweme/v1/web/solution/resource/list/?spot_keys=7359502129541449780_douyin_spec_theme&app_id=6383&update_version_code=170400&pc_client_type=1&pc_libra_divert=Mac&support_h265=1&support_dash=0&cpu_core_num=4&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1440&screen_height=900&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=137.0.0.0&browser_online=true&engine_name=Blink&engine_version=137.0.0.0&os_name=Mac+OS&os_version=10.15.7&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7517282755928573449&uifid=163eead721bc91ca6f3a3cb4766a73c0638fabced1012e02c28bcbf3169aca5c44c51fa6beff8f1f2615be624638d06d91c6d0ff5636b21eb7b8a473d4d2e7e8aeb97f1b374c801db9850467ee095467",
"2": true
}
},
{
"fnName": "setRequestHeader",
"arguments": {
"0": "Accept",
"1": "application/json, text/plain, /"
}
},
{
"fnName": "setRequestHeader",
"arguments": {
"0": "uifid",
"1": "163eead721bc91ca6f3a3cb4766a73c0638fabced1012e02c28bcbf3169aca5c44c51fa6beff8f1f2615be624638d06d91c6d0ff5636b21eb7b8a473d4d2e7e8aeb97f1b374c801db9850467ee095467"
}
},
{
"fnName": "send",
"arguments": {
"0": null
}
}
],
"_reqHeaders": {
"Accept": "application/json, text/plain, /",
"uifid": "163eead721bc91ca6f3a3cb4766a73c0638fabced1012e02c28bcbf3169aca5c44c51fa6beff8f1f2615be624638d06d91c6d0ff5636b21eb7b8a473d4d2e7e8aeb97f1b374c801db9850467ee095467"
},
"_start": 1750254595745,
"_data": null,
"bdmsInvokeList": [
{
"args": [
"GET",
"/aweme/v1/web/solution/resource/list/?spot_keys=7359502129541449780_douyin_spec_theme&app_id=6383&update_version_code=170400&pc_client_type=1&pc_libra_divert=Mac&support_h265=1&support_dash=0&cpu_core_num=4&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1440&screen_height=900&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=137.0.0.0&browser_online=true&engine_name=Blink&engine_version=137.0.0.0&os_name=Mac+OS&os_version=10.15.7&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7517282755928573449&uifid=163eead721bc91ca6f3a3cb4766a73c0638fabced1012e02c28bcbf3169aca5c44c51fa6beff8f1f2615be624638d06d91c6d0ff5636b21eb7b8a473d4d2e7e8aeb97f1b374c801db9850467ee095467&verifyFp=verify_mc1zx67l_pnrg8Q4K_uzh0_4Oms_BLHt_TpjFC31zVsH2&fp=verify_mc1zx67l_pnrg8Q4K_uzh0_4Oms_BLHt_TpjFC31zVsH2",
true
]
},
{
"args": [
"Accept",
"application/json, text/plain, /"
]
},
{
"args": [
"uifid",
"163eead721bc91ca6f3a3cb4766a73c0638fabced1012e02c28bcbf3169aca5c44c51fa6beff8f1f2615be624638d06d91c6d0ff5636b21eb7b8a473d4d2e7e8aeb97f1b374c801db9850467ee095467"
]
}
]
}

[null]

提醒:
t.origin.apply(e, u);

m._url.indexOf("/aweme/v1/web/aweme/post") !==-1

e._url.indexOf("/aweme/v1/web/aweme/post") !==-1

e._vc_actionList[0].arguments[1].indexOf('v1/web/aweme/post')!==-1

m._tnc_request_url.indexOf("/aweme/v1/web/aweme/post") !==-1

e._cmp_data.url.indexOf("aweme/v1/web/aweme/post") !==-1

http://www.hskmm.com/?act=detail&tid=17100

相关文章:

  • python自动化操作邮件
  • zabbix配置mysql监控
  • redis实现定期关单
  • 第18章 Day22 高阶混淆ast进阶
  • 关于ubuntu 用户切换的细节 su - user 和su user
  • 用 SeaTunnel 同步 MySQL 到 Doris:全量增量 + SQL 过滤
  • 在CodeBolcks下wxSmith的C++编程教程——使用自定义绘制和鼠标处理创建项目
  • trae 配置mysql_mcp
  • Apache NiFi 1.28.1 集群 + Kerberos 认证 + 多租户模式部署
  • 基于Java+SpringBoot+SSM,Flask福聚苑社区团购体系(源码+LW+调试文档+讲解等)/福聚苑社区/团购系统/社区团购/福聚苑/团购/社区/环境/福聚苑小区/在线团购/社区购物
  • 按需引入echarts
  • 软件构造的用户交互设计 4章
  • 自定义制作docker容器自动自愈容器镜像
  • 如何利用海外 NetNut 网络代理与 AICoding 实战获取 iPhone 17 新品用户评论数据?
  • 第一次编码器测试
  • 04-FreeRTOS的概述及编程规范
  • 10_ select/poll/epoll实现服务端的io多路复用
  • 模拟实战配置实验
  • 国标GB28181公网直播EasyGBS如何构建全域覆盖的应急管理与安全生产解决方案?
  • Serilog.AspNetCore与Serilog的区别
  • 基于MATLAB S函数实现多智能体间歇通信仿真
  • 我天,前端岗要消亡了吗?
  • 闲话
  • java8的集合新API - --
  • 基于MATLAB/Simulink的500kW三相光伏逆变器仿真
  • Docker Compose启动多个镜像实例
  • 卫星时间同步平台:助力分布式测控系统同步工作
  • mkfx 对磁盘设置标签
  • C# Avalonia 15- Animation- Easing
  • 安卓编译重点记录