第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';
    // 取原型链上的toString
    const $toString = Function.toString;
    // 取方法名 symbol
    const 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;
        
        // 保护 getter
        if (descriptor.get) {
            const propName = customNames.getter || prop;
            const getterStr = `function get ${propName}() { [native code] }`;
            set_native(descriptor.get, myFunction_toString_symbol, getterStr);
        }
        
        // 保护 setter
        if (descriptor.set) {
            const propName = customNames.setter || prop;
            const setterStr = `function set ${propName}() { [native code] }`;
            set_native(descriptor.set, myFunction_toString_symbol, setterStr);
        }
    }
    
    // 批量保护对象的所有 getter/setter
    function 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/setter
    globalThis.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

posted @ 2025-09-25 16:46  凫弥  阅读(39)  评论(0)    收藏  举报