奇异的 arguments

本文探讨了JavaScript中arguments对象的独特性质及其实用案例,包括格式化字符串、构造预设参数函数及自引用函数等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

function format(string) {
  var args = arguments;
  var pattern = new RegExp("%([1-" + arguments.length + "])", "g");
  return String(string).replace(pattern, function(match, index) {
    return args[index];
  });
};

这个函数实现了模板替换,你可以在要动态替换的地方使用 %1 到 %9 标记,然后其余的参数就会依次替换这些地方。例如:

format("And the %1 want to know whose %2 you %3", "papers", "shirt", "wear");

上面的脚本就会返回

"And the papers want to know whose shirt you wear" 。

在这里需要注意的是,即便在 format 函数定义中,我们仅定义了个名为 string 的参数。而 Javascript 不管函数自身定义的参数数量,它都允许我们向一个函数传递任意数量的参数,并将这些参数值保存到被调用函数的 arguments 对象中。

转换成实际数组

虽然 arguments 对象并不是真正意义上的 Javascript 数组,但是我们可以使用数组的 slice 方法将其转换成数组,类似下面的代码

var args = Array.prototype.slice.call(arguments);

这样,数组变量 args 包含了所有 arguments 对象包含的值。

创建预置参数的函数

使用 arguments 对象能够简短我们编写的 Javascript 代码量。下面有个名为 makeFunc 的函数,它根据你提供的函数名称以及其他任意数目的参数,然后返回个匿名函数。此匿名函数被调用时,合并的原先被调用的参数,并交给指定的函数运行然后返回其返回值。

function makeFunc() {
  var args = Array.prototype.slice.call(arguments);
  var func = args.shift();
  return function() {
    return func.apply(null, args.concat(Array.prototype.slice.call(arguments)));
  };
}

makeFunc 的第一个参数指定需要调用的函数名称(是的,在这个简单的例子中没有错误检查),获取以后从 args 中删除。makeFunc 返回一个匿名函数,它使用函数对象的(Function Object)apply 方法调用指定的函数。

apply 方法的第一个参数指定了作用域,基本上的作用域是被调用的函数。不过这样在这个例子中看起来会有点复杂,所以我们将其设定成 null ;其第二个参数是个数组,它指定了其调用函数的参数。makeFunc 转换其自身的 arguments 并连接匿名函数的 arguments,然后传递到被调用的函数。

有种情况就是总是要有个输出的模板是相同的,为了节省每次是使用上面提到的 format 函数并指定重复的参数,我们可以使用 makeFunc 这个工具。它将返回一个匿名函数,并自动生成已经指定模板后的内容:

var majorTom = makeFunc(format, "This is Major Tom to ground control. I'm %1.");

你可以像这样重复指定 majorTom 函数:

majorTom("stepping through the door");
majorTom("floating in a most peculiar way");

那么当每次调用 majorTom 函数时,它都会使用第一个指定的参数填写已经指定的模板。例如上述的代码返回:

"This is Major Tom to ground control. I'm stepping through the door."
"This is Major Tom to ground control. I'm floating in a most peculiar way."

自引用的函数

您可能会认为这很酷,先别急着高兴,后面还有个更大的惊喜。它(arguments)还有个其他非常有用的属性:callee 。arguments.callee 包含了当前调用函数的被引用对象。那么我们如何使用这玩意做些的事情?arguments.callee 是个非常有用的调用自身的匿名函数。

下面有个名为 repeat 的函数,它的参数需要个函数引用和两个数字。第一个数字表示运行的次数,而第二个函数定义运行的间隔时间(毫秒为单位)。下面是相关的代码:

function repeat(fn, times, delay) {
  return function() {
    if(times-- > 0) {
      fn.apply(null, arguments);
      var args = Array.prototype.slice.call(arguments);
      var self = arguments.callee;
      setTimeout(function(){self.apply(null,args)}, delay);
    }
  };
}

repeat 函数使用 arguments.callee 获得当前引用,保存到 self 变量后,返回个匿名函数重新运行原本被调用的函数。最后使用 setTimeout 以及配合个匿名函数实现延迟执行。

作为个简单的说明,比如会在通常的脚本中,编写下面的提供个字符串并弹出个警告框的简单函数:

function comms(s) {
  alert(s);
}

好了,后来我改变了我的想法。我想编写个「特殊版本」的函数,它会重复三次运行每次间隔两秒。那么使用我的 repeat 函数,就可以像这样做到:

var somethingWrong = repeat(comms, 3, 2000);
somethingWrong("Can you hear me, major tom?");

结果就犹如预期的那样,弹出了三次警告框每次延时两秒。

最后,arguments 即便不会经常被用到,甚至显得有些诡异,但是它上述的那些惊艳的功能(不仅仅是这些!)值得你去了解它。

------------------------------以上转自:http://www.gracecode.com/archives/2551/--------------------------

看不太懂,转来好好琢磨。

%构造Hankel矩阵,并进行自检 % 假设输入数据为两列向量 normalized_TwHt1TPxi 和 normalized_TwHt1TPyi % 合并多通道数据为矩阵 Y,维度 [2×N] Y = [normalized_TwHt1TPxi(:), normalized_TwHt1TPyi(:)]'; % 定义Hankel矩阵参数 i = 20; % 每个通道的时间点数(块长度) j = size(Y, 2) - i + 1; % Hankel矩阵的列数,需满足 j = N - i + 1 % 断言检查输入合法性 assert(size(Y, 1) == 2, '错误:Y 必须是2通道数据'); assert(j > 0, '错误:块长度i超过数据范围'); % 方法1:向量化构建Hankel矩阵(高效推荐) % 生成索引矩阵:每列表示一个数据块的起始位置 indices = repmat(1:j, i, 1) + (0:i-1)'; % 维度 [i×j] % 提取所有数据块并展开为列向量 H = Y(:, indices(:)); % 维度 [2 × (i*j)] H = reshape(H, 2*i, j); % 调整维度为 [2i×j] % 方法2:循环构建Hankel矩阵(等效于方法1,供理解逻辑) % H = zeros(2*i, j); % for k = 1:j % block = Y(:, k:k+i-1); % 提取第k个数据块 [2×i] % H(:, k) = block(:); % 展开为列向量 [2i×1] % end %投影和奇异值分解(SVD) [U, S, V] = svd(H, 'econ'); n = 10; % 预设模型阶数(需通过稳定图优化) U_n = U(:,1:n); % 截断主成分 %构造状态空间模型 % 提取可观测性矩阵 O = U_n(1:end/2, :); % 前一半块行构成可观测性矩阵 A = pinv(O(1:end-2,:)) * O(2:end-1,:); % 估计状态转移矩阵 C = O(1,:); % 输出矩阵 %模态参数提取 [Psi, Lambda] = eig(A); % 离散系统特征值 lambda = log(diag(Lambda)) / (1/fs); % 转换为连续系统特征值 % 计算频率和阻尼比 freq = abs(lambda) / (2*pi); damping = -real(lambda) ./ abs(lambda); % 提取振型 Phi = C * Psi; % 物理坐标下的振型 %定义模型阶数范围(示例) modelOrders = 10:2:30; % 初始化存储结构体 modes = struct('Order', {}, 'Frequency', {}, 'Damping', {}); % 遍历所有模型阶数 for idx = 1:length(modelOrders) n = modelOrders(idx); % 截断 U 矩阵前 n 列 U_n = U(:, 1:n); % 构造可观测性矩阵 O O = U_n(1:end/2, :); % 假设块行数为 i=20,则 end/2=20 % 估计状态转移矩阵 A(需保证可逆性) if size(O,1) > 2 % 确保可观测性矩阵足够大 A = pinv(O(1:end-1, :)) * O(2:end, :); % 修正投影公式 else continue; % 跳过无法计算的阶数 end % 提取特征值并转换到连续系统 [Psi, Lambda] = eig(A); lambda = log(diag(Lambda)) / (1/fs); % 离散→连续 % 计算频率和阻尼比 freq = abs(lambda) / (2*pi); damping = -real(lambda) ./ abs(lambda); % 过滤无效模态(频率正实数、阻尼比在合理范围) validIdx = (imag(lambda) >= 0) & (damping >= 0) & (damping <= 1); freq = freq(validIdx); damping = damping(validIdx); % 保存结果 modes(idx).Order = n; modes(idx).Frequency = freq; modes(idx).Damping = damping; end 结合function stableModes = selectStableModes(modes, options) arguments modes struct options.FrequencyTol double = 0.01 % 频率差异容忍度(Hz) options.DampingTol double = 0.1 % 阻尼比差异容忍度 end % 合并所有频率和阻尼数据 allFreq = [modes.Frequency]; allDamping = [modes.Damping]; allOrders = [modes.Order]; % 按频率分组(容忍度范围内视为同一模态) [~, ~, groupID] = histcounts(allFreq, 'BinWidth', options.FrequencyTol); % 统计每组出现的次数(出现次数多则稳定) groupCounts = accumarray(groupID(groupID>0), 1); stableGroups = find(groupCounts >= 3); % 至少连续3个阶数出现 % 提取稳定模态参数 stableModes = struct('Frequency', {}, 'Damping', {}); for g = 1:length(stableGroups) idx = (groupID == stableGroups(g)); freqMean = mean(allFreq(idx)); dampingMean = mean(allDamping(idx)); stableModes(end+1) = struct(... 'Frequency', freqMean, ... 'Damping', dampingMean); end end
最新发布
03-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值