js 中 obj.onclick= func() 和 obj.onclick func 分析

本文探讨了JavaScript中HTML事件处理与DOM0级事件处理的区别,重点分析了在为元素绑定点击事件时,何时在函数名后加括号以及何时不加括号。
部署运行你感兴趣的模型镜像

这两天正在学习javascript中的事件,出现了一个这样的一个以疑惑,就是在点击事件调用方法的时候有时候后面需要不需要加括号。感觉有点儿晕,,不太明白到底是什么时候需要加括号什么时候不需要加括号。于是在网上找了一些资料,整理了一下如有不足或者错误之处欢迎拍砖:

例1:

<input class="btn_default" type="button" onclick="demo()" value="js HTML事件处理"/>
<script type="text/javascript">
    function demo() {
        alert("HTML事件处理");
    }
</script>
上面的实例中,onclick = demo() 是需要加括号的。因为在 html 中 onlclick 是作为 input 的一个属性而存在的 onclick 所调用的是一个方法, 方法后面是必须要加括号的,而 demo 这是方法的一个名称而已。所以如果如果在程序中调用的是一个方法就必须加上括号。

例2:

<input class="btn_default" type="button" id="btn_dom0" value="js Dom0级事件处理"/>
<script type="text/javascript">
function demo() {
        alert("HTML事件处理");
    }
var btn0 = document.getElementById("btn_dom0");
btn0.onclick = demo;
</script>
 这一个实例里,通过 document.getElementById() 方法获取到 button 按钮,此时 btn0 是一个对象。 onclick 是对象 btn0 的一个事件,它的类型是一个对象,所以后面 btn0.onclick = demo; 只是一个赋值操作。 这里的 demo 表示的是一个对象,于是就不需要加括号。

您可能感兴趣的与本文相关的镜像

TensorFlow-v2.9

TensorFlow-v2.9

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

classdef SwitchedFuzzyObserver properties % 基本参数 n % 状态维度 r % 规则数量 p % 前件变量数量 lower_MF % 下隶属函数 upper_MF % 上隶属函数 weighting_func % 权重函数 h_i(x) premise_vars % 前件变量函数 % 关联对象 fuzzy_system % 关联的区间二型模糊系统对象 cyber_attack % 关联的混合攻击对象 % 观测器增益矩阵 F1 % 正常通信期间的观测器增益 F_{1,j} F2 % DoS攻击期间的观测器增益 F_{2,j} % 观测器状态 x_sigma % 观测器状态估计 x_σ(t) y_sigma % 观测器输出估计 y_σ(t) % 估计误差 estimation_error % 状态估计误差历史 output_error % 输出估计误差历史 % 配置参数 simulation_time % 仿真时间记录 config % 观测器配置参数%%%%%%%%%%%%%%%%%%%%%% % 内部缓存 last_dos_status % 上次DoS攻击状态 trigger_history % 触发历史记录 % 攻击时间表 attack_schedule % 攻击时间表(Upsilon1:正常通信时段(初始为空)Upsilon2:DoS 攻击时段(初始为空)) Υ_{1,n}, Υ_{2,n} end methods function obj = SwitchedFuzzyObserver(varargin) p = inputParser;%创建输入解析器对象 addOptional(p, 'fuzzy_sys', [], @(x) isa(x, 'IntervalType2FuzzySystem') || isempty(x)); addOptional(p, 'cyber_attack_obj', [], @(x) isa(x, 'HybridCyberAttack') || isempty(x)); addParameter(p, 'n', 2, @isnumeric); addParameter(p, 'r', 2, @isnumeric); addParameter(p, 'p', 1, @isnumeric); parse(p, varargin{:});%使用输入解析器p解析输入参数varargin,解析结果存储在p.Results结构中 if ~isempty(p.Results.fuzzy_sys) % 如果提供了已存在的模糊系统对象(fuzzy_sys),则使用该对象关联的网络攻击对象进行初始化 obj.fuzzy_system = p.Results.fuzzy_sys;%将观测器的fuzzy_system属性设置为传入的模糊系统对象(p.Results.fuzzy_sys) obj.cyber_attack = p.Results.cyber_attack_obj; obj.n = obj.fuzzy_system.n; obj.r = obj.fuzzy_system.r; obj.p = obj.fuzzy_system.p; else %如果没有提供模糊系统对象,则使用指定的参数(n, r, p)创建默认的模糊系统网络攻击对象 obj.n = p.Results.n; obj.r = p.Results.r; obj.p = p.Results.p; % 创建默认的模糊系统 obj.fuzzy_system = IntervalType2FuzzySystem(obj.n, obj.r, obj.p); % 创建默认的攻击对象 obj.cyber_attack = HybridCyberAttack(); end obj.lower_MF = cell(obj.r, obj.p); obj.upper_MF = cell(obj.r, obj.p); obj.weighting_func = cell(obj.r, 2); % {h_lower, h_upper} obj.premise_vars = cell(obj.p, 1); % 初始化增益矩阵(创建两个单元格数组F1F2,长度等于规则数量obj.r) obj.F1 = cell(obj.r, 1);%F_{1,j} obj.F2 = cell(obj.r, 1);%r行1列 % 初始化默认增益(可根据需要修改) for j = 1:obj.r obj.F1{j} = eye(obj.n) * 0.5; % 默认正常增益 obj.F2{j} = eye(obj.n) * 0.2; % 默认攻击期间增益 end % 添加触发历史初始化 obj.trigger_history = []; % 初始化观测器状态 obj.x_sigma = zeros(obj.n, 1); obj.y_sigma = zeros(obj.n, 1); % 默认输出维度与状态相同,维度均为 n×1(状态维度) % 初始化误差记录 obj.estimation_error = []; obj.output_error = []; obj.simulation_time = []; obj.last_dos_status = 0; % 初始化攻击时间表(创建结构体 attack_schedule,包含两个字段:Upsilon1:正常通信时段(初始为空)Upsilon2:DoS 攻击时段(初始为空)用于存储预定义或检测到的攻击时间表) obj.attack_schedule = struct('Upsilon1', [], 'Upsilon2', []); % 默认配置 obj.config = struct(... 'use_type_reduction', true, ... 'error_threshold', 0.1, ... 'adaptive_gain', false, ... 'output_dimension', obj.n ... ); end function obj = setAttackSchedule(obj, Upsilon1, Upsilon2) % 设置攻击时间表 Υ_{1,n}, Υ_{2,n} obj.attack_schedule.Upsilon1 = Upsilon1; % 正常通信时段(一个数组或矩阵,表示正常通信的时间段。通常,这个参数应该是一个二维数组,每一行代表一个时间段(例如,[开始时间, 结束时间])) obj.attack_schedule.Upsilon2 = Upsilon2; % DoS攻击时段 end function obj = setSystemMatrices(obj, A_cell, B_cell, C_mat)%用于设置模糊系统矩阵的方法 % 设置系统矩阵 for j = 1:min(length(A_cell), obj.r) obj.fuzzy_system.A{j} = A_cell{j};%将每个 A_i 矩阵赋值给模糊系统的对应规则,min(length(A_cell), obj.r):确保不会超出规则数量,只更新有对应矩阵的规则,如果提供的 A 矩阵少于规则数,剩余规则保持原样 end for j = 1:min(length(B_cell), obj.r) obj.fuzzy_system.B{j} = B_cell{j}; end obj.fuzzy_system.C = C_mat;%直接设置模糊系统的输出矩阵 C,该矩阵通常对所有规则相同 obj.config.output_dimension = size(C_mat, 1);%根据 C 矩阵的行数更新输出维度配置 obj.y_sigma = zeros(obj.config.output_dimension, 1); end function obj = setObserverGains(obj, j, F1_j, F2_j)%设置单条规则的增益 % 设置第j条规则的观测器增益 if j <= obj.r && j > 0 obj.F1{j} = F1_j; obj.F2{j} = F2_j; else error('规则索引超出范围'); end end function obj = setConfig(obj, field, value) % 设置观测器配置参数 if isfield(obj.config, field) obj.config.(field) = value;%将value的值赋值给相应参数配置,实现更新 else error('无效的配置字段: %s', field); end end function obj = setMembershipFunction(obj, i, j, lower_func, upper_func) if i==1 obj.lower_MF{1, j} = lower_func; obj.upper_MF{1, j} = upper_func; end if i==2 obj.lower_MF{2, j} = lower_func; obj.upper_MF{2, j} = upper_func; end end function obj = setWeightingFunction(obj, i, h_lower, h_upper) obj.weighting_func{i, 1} = h_lower; obj.weighting_func{i, 2} = h_upper; end function obj = setPremiseVariable(obj, j, premise_func) obj.premise_vars{j} = premise_func; end function premise_var = getPremiseVariable(obj, j, x) if ~isempty(obj.premise_vars{j}) premise_var = obj.premise_vars{j}(x); else premise_var = x(1); end end function [firing_lower, firing_upper] = computeFiringStrength(obj, x) firing_lower = zeros(obj.r, 1); firing_upper = zeros(obj.r, 1); for i = 1:obj.r lower_strength = 1; upper_strength = 1; for j = 1:obj.p premise_var = x(1); if ~isempty(obj.lower_MF{i, j}) lower_mem = obj.lower_MF{i, j}(premise_var); upper_mem = obj.upper_MF{i, j}(premise_var); lower_strength = lower_strength * lower_mem; upper_strength = upper_strength * upper_mem; end end firing_lower(i) = lower_strength; firing_upper(i) = upper_strength; end end function [dx_sigma, obj] = computeObserverDynamics(obj, t, u, y, x_sigma)%计算观测器动态 % 获取DoS攻击状态 [D_dos, ~] = obj.cyber_attack.generateDoSAttack(t);%~:忽略其他输出(如攻击信息)​​ obj.last_dos_status = D_dos; dos_status = D_dos;%没有时间表则使用实时监测 [firing_lower, firing_upper] = obj.computeFiringStrength(obj.x_sigma); % 初始化状态导数输出误差 dx_sigma = zeros(obj.n, 1); obj.output_error = y - obj.y_sigma; % 输出误差 y(t) - y_σ(t) total_weight = 0; % 根据攻击状态选择增益,实现观测器动态计算 if dos_status == 0 % 正常通信 for j = 1:obj.r%对每条规则计算其对状态导数的贡献 if ~isempty(obj.fuzzy_system.A{j}) && ~isempty(obj.F1{j}) % 系统动力学部分 system_dyn = obj.fuzzy_system.A{j} * x_sigma; % 使用受攻击的状态估计 if ~isempty(obj.fuzzy_system.B{j}) system_dyn = system_dyn + obj.fuzzy_system.B{j} * u;%控制输入影响 end % 校正项 correction = obj.F1{j} * obj.output_error; %权重函数 h_lower = obj.weighting_func{j,1}(x_sigma(1)); % 取状态向量的第一个分量 h_upper = obj.weighting_func{j,2}(x_sigma(1)); chi_j = h_lower * firing_lower(j) + h_upper * firing_upper(j); dx_sigma = dx_sigma + chi_j * (system_dyn + correction); total_weight = total_weight + chi_j; end end else % DoS攻击期间 for j = 1:obj.r if ~isempty(obj.fuzzy_system.A{j}) && ~isempty(obj.F2{j}) % 系统动力学部分 system_dyn = obj.fuzzy_system.A{j} * x_sigma; % 使用受攻击的状态估计 if ~isempty(obj.fuzzy_system.B{j}) system_dyn = system_dyn + obj.fuzzy_system.B{j} * u; end % 校正项 correction = obj.F2{j} * obj.output_error; h_lower = obj.weighting_func{j,1}(x_sigma(1)); h_upper = obj.weighting_func{j,2}(x_sigma(1)); chi_j = h_lower * firing_lower(j) + h_upper * firing_upper(j); dx_sigma = dx_sigma + chi_j * (system_dyn + correction); total_weight = total_weight + chi_j; end end end if total_weight > 0 dx_sigma = dx_sigma / total_weight; end % 更新观测器输出 if ~isempty(obj.fuzzy_system.C) obj.y_sigma = obj.fuzzy_system.C * obj.x_sigma; end % 记录时间(记录每次调用观测器动态计算的时间点) obj.simulation_time = [obj.simulation_time; t]; % 记录当前状态用于事件触发 trigger_info = struct(); trigger_info.time = t; trigger_info.state = obj.x_sigma; trigger_info.output = obj.y_sigma; trigger_info.dos_status = dos_status; obj.trigger_history = [obj.trigger_history; trigger_info]; end function obj = updateObserverState(obj, dx_sigma, dt) % 更新观测器状态,更新其输出估计 obj.x_sigma = obj.x_sigma + dx_sigma * dt; if ~isempty(obj.fuzzy_system.C) obj.y_sigma = obj.fuzzy_system.C * obj.x_sigma; end end function [x_est, y_est] = getEstimate(obj) % 获取当前状态输出估计(可在一定程度上提供数值保护) x_est = obj.x_sigma; y_est = obj.y_sigma; end function obj = recordEstimationError(obj, x_true, y_true) % 记录估计误差 if ~isempty(x_true) && length(x_true) == obj.n error_state = x_true - obj.x_sigma; obj.estimation_error = [obj.estimation_error; error_state']; end if ~isempty(y_true) && length(y_true) == length(obj.y_sigma) error_output = y_true - obj.y_sigma; obj.output_error = [obj.output_error; error_output']; end end function obj = resetObserver(obj, x0) % 重置观测器状态 if nargin < 2 x0 = zeros(obj.n, 1);%如果没有提供初始状态 x0 end obj.x_sigma = x0; if ~isempty(obj.fuzzy_system.C) obj.y_sigma = obj.fuzzy_system.C * x0; else obj.y_sigma = x0; end obj.estimation_error = []; obj.output_error = []; obj.simulation_time = []; end function performance = evaluatePerformance(obj) % 评估观测器性能 performance = struct(); if ~isempty(obj.estimation_error) % 状态估计性能 performance.rmse_state = sqrt(mean(obj.estimation_error.^2, 1));%均方根误差 performance.mae_state = mean(abs(obj.estimation_error), 1);%平均绝对误差 performance.max_error_state = max(abs(obj.estimation_error), [], 1);%最大绝对误差 % 输出估计性能 if ~isempty(obj.output_error) performance.rmse_output = sqrt(mean(obj.output_error.^2, 1)); performance.mae_output = mean(abs(obj.output_error), 1); end % 收敛性分析 performance.final_error = obj.estimation_error(end, :); end end end end
10-24
<think>嗯,用户让我解析这段Python代码,是关于自定义一个myproperty类的。首先,我得仔细看看代码结构,可能涉及描述符协议,因为里面用了__get__、__set__这些方法。描述符在Python中用于管理属性访问,比如@property就是基于描述符的。 首先,用户提供的这个myproperty类,应该是在模仿内置的property装饰器。让我先看看类的结构。类myproperty有一个__init__方法,接收fget、fset、fdel三个参数,分别对应获取、设置删除的方法。然后内部定义了__get__、__set__、__delete__方法,这些是描述符协议需要的。当实例的属性被访问时,会调用这些方法。 不过,代码中有个问题:__get__、__set____delete__这几个方法是在__init__里面定义的,这会导致每次创建myproperty实例时,这些方法会被重新定义,并且可能绑定到不同的实例上吗?或者说,这里可能存在缩进错误,导致这些方法实际上是内部函数,而不是myproperty类的方法?比如,正确的做法应该是将这些方法作为myproperty类的实例方法,而不是嵌套在__init__里面。这可能是一个代码错误,导致这些描述符方法无法正常工作,因为它们在__init__里定义,而实际上应该作为类的方法存在。 接下来,类中的getter、setter、decorator方法,应该是用来链式配置fget、fset、fdel的。例如,当用@myproperty装饰一个方法时,会调用getter,设置fget,并返回实例自身,这样后续的setter可以被调用。但是,如果用户在使用这个装饰器时,比如: class MyClass: @myproperty() def x(self): return self._x @x.setter def x(self, value): self._x = value 那么,这里的@myproperty()可能有问题,因为myproperty需要被正确初始化作为描述符使用。但根据当前代码的结构,可能存在问题,因为__get__等方法被定义在__init__内部,导致它们不是myproperty实例的方法,而只是__init__中的局部函数,无法被正确调用。 另外,在Python中,描述符的工作方式是通过类属性来触发的。当访问实例属性时,如果该属性是一个描述符(即定义了__get__或__set__等),则会调用相应的方法。例如,property装饰器就是基于描述符实现的。 现在,用户提供的代码中,myproperty类在初始化时接收fget、fset、fdel,然后在__get__方法中调用self.fget(instance)。这里可能的问题在于,self指的是myproperty的实例,而instance是拥有该描述符的类的实例。例如,当有一个类A,其中有一个属性x是myproperty的实例,那么当访问a.x时,会调用myproperty实例的__get__方法,传入a作为instance参数,然后调用fget(a),即获取方法。 但问题在于,用户代码中的__get__、__set__等方法被定义在__init__方法内部,这意味着它们并不是myproperty类的方法,而是__init__函数中定义的局部函数。这会导致这些方法无法被正确调用,因为Python在查找描述符方法时,会在myproperty类中查找__get__等方法,而不是在实例的属性中。因此,这可能是一个代码错误,导致这个myproperty类无法正常工作。 正确的做法应该是将__get__、__set__、__delete__作为myproperty类的方法,而不是嵌套在__init__里面。因此,用户提供的代码可能存在缩进错误,导致这些方法没有被正确定义。 比如,正确的代码结构应该是: class myproperty(): def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel def __get__(self, instance, owner): return self.fget(instance) def __set__(self, instance, value): self.fset(instance, value) def __delete__(self, instance): self.fdel(instance) def getter(self, func): self.fget = func return self def setter(self, func): self.fset = func return self def deleter(self, func): self.fdel = func return self 这样,__get__等方法才是myproperty类的实例方法,从而正确实现描述符协议。用户代码中的缩进错误导致这些方法被定义在__init__内部,因此无法作为描述符方法被调用,这会导致错误。 所以,用户可能是在编写自定义property类时,不小心将__get__等方法缩进到了__init__里面,导致代码无法按预期工作。需要指出这个错误,并说明正确的结构。 此外,在getter、setter、deleter方法中,用户代码中的这些方法将传入的func赋值给self.fget等,并返回self。这样,当使用装饰器语法时,例如: class C: @myproperty def x(self): return self._x @x.setter def x(self, value): self._x = value 这会正常工作,因为@myproperty装饰器会调用getter,将x的get方法设置为fget,然后x.setter装饰器会调用setter方法设置fset。但前提是描述符方法正确实现。 总结用户代码的问题:缩进错误导致__get__等方法未被正确定义,使得该myproperty类无法正确作为描述符工作。正确的做法是将这些方法作为类的方法,而不是在__init__内部定义。</think>让我们逐步解析这段自定义的`myproperty`类代码: 一、代码结构问题 ✖️ 当前代码存在严重缩进错误,`__get__`/`__set__`/`__delete__`方法被错误地定义在`__init__`方法内部,导致无法实现描述符协议。正确缩进应为: ```python class myproperty(): def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel # 以下是类级别的方法(修正缩进) def __get__(self, instance, owner): return self.fget(instance) def __set__(self, instance, value): self.fset(instance, value) def __delete__(self, instance): self.fdel(instance) # 装饰器方法保持原缩进 def getter(self, func): self.fget = func return self def setter(self, func): self.fset = func return self def deleter(self, func): self.fdel = func return self ``` 二、核心机制解析 ⚙️ 1. **描述符协议**:通过实现`__get__`、`__set__`、`__delete__`方法,使该类成为数据描述符(优先于实例字典的访问) 2. **初始化方法**: ```python def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget # 保存getter函数 self.fset = fset # 保存setter函数 self.fdel = fdel # 保存deleter函数 ``` 3. **描述符方法**: - `__get__(self, instance, owner)`:当访问属性时触发 - `instance`: 被访问的类实例 - `owner`: 拥有该属性的类 4. **装饰器方法**: - `getter(func)`:装饰getter函数并返回自身 - `setter(func)`:装饰setter函数并返回自身 - `deleter(func)`:装饰deleter函数并返回自身 三、使用示例 💻 ```python class MyClass: def __init__(self): self._x = 42 @myproperty() # 等价于 @myproperty def x(self): return self._x @x.setter def x(self, value): self._x = value # 测试 obj = MyClass() print(obj.x) # 调用__get__ → 输出42 obj.x = 10 # 调用__set__ print(obj.x) # 输出10 ``` 四、与原生property对比 🔄 1. 相似性:都通过描述符实现属性访问控制 2. 差异性: - 原生property会自动处理`__doc__`等元信息 - 原生实现有更完善的错误处理 - 本实现需要显式返回`self`保持链式调用 五、典型应用场景 🎯 1. 数据验证 2. 延迟计算 3. 访问控制 4. 属性变更通知 请特别注意原始代码中的缩进错误会导致功能失效,修正缩进后才能正确实现属性描述符功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值