原型链
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