Javascript学习笔记17 高级技巧(函数绑定,柯里化,定时器)

js不常用但实用的JavaScript超级技巧 JavaScript 是一种应用场景多且功能强大的语言,对于现代 Web 开发至关重要。以下是一些超级技巧,它们将帮助你成为更高效、更有效的 JavaScript 开发人员,每个技巧都有详细的解释和示例。提示:以下是本篇文章正文内容,下面案例可供参考。 阅读详情

高级函数

类型检测

在任何值上调用Object的toString()方法都会返回一个表示该对象原生构造函数名的字符串,因此可以使用该方法检测对象类型,弥补type of以及 instanceof的一些问题。

Object.prototype.toString.call(value) == "[object Array]";  //检测值的类型是否为数组

Object.prototype.toString.call(value) == "[object Function]";  //检测值的类型是否为函数

Object.prototype.toString.call(value) == "[object RegExp]";  //检测值的类型是否为正则表达式

开发人员定义的任何构造函数都将返回[object Object],因此可以用此方法,来区分Javascript原生和非原生对象

//检测是否原生的JSON对象
var isNativeJSON = window.JSON && Object.prototypr.toString.call(JSON) == "[object JSON]";

作用域安全的构造函数

当调用构造函数时,没有使用new操作符时,属性将会被绑定到window对象上

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
}
var person = Person("zjw",29,"student");
alert(window.name);  //"zjw"  
alert(window.age);   //29
alert(window.job);   //"student"

可以在构造函数中首先确认this对象是否为正确类型的实例。如果不是则创建新的实例并返回

function Person(name,age,job){
    if (this instanceof Person){
        this.name = name;
        this.age = age;
        this.job = job;
    }else{
        return new Person(name,age,job);
    }
}

惰性载入函数

多数JavaScript代码包含了大量的if语句,例如一个使用多条if分支解决不同浏览器兼容问题,从而执行某种功能的函数,往往第一次调用就能确认浏览器是否支持功能而采取某种行为,后续再次调用该函数就不需要再判断了。为了解决这个问题,可以使用惰性载入的技巧

第一种实现惰性载入的方法就是函数覆盖

function someFunction(){
    if (condition1){
        someFunction = function(){   //覆盖原函数
            //do something
        };
    }else if (condition2){
        someFunction = function(){  //覆盖原函数
            //do another thing
        };
    }else{
        someFunction = function(){  //覆盖原函数
            //do another thing
        };
    }
    return someFunction();    //返回覆盖后的函数执行结果
}

第二种方法是在声明函数时就指定适当的函数

var someFunction = (function(){
    if (condition1){
        return function(){   //覆盖原函数
            //do something
        };
    }else if (condition2){
        return function(){  //覆盖原函数
            //do another thing
        };
    }else{
        return function(){  //覆盖原函数
            //do another thing
        };
    }
})();

函数绑定

函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。

var handler = {
    message = "Event handle",
    handleClick : function(event){
        alert(this.message);
    }
};

var btn = docuemnt.getElementById("my-btn");
btn.addEventListener("click",handler.handleClick,false);

上述代码给一个DOM按钮分配了一个事件处理程序,看似按下按钮后,将会弹出警告框,显示”Event handle”。实际上,显示的是undefined。this总是指向调用其的对象,此处传入的只是一个函数,调用函数时,this对象指向了DOM按钮,而不是handler对象。

可以使用闭包来修复这个问题

var handler = {
    message = "Event handle",
    handleClick : function(event){
        alert(this.message);
    }
};

var btn = docuemnt.getElementById("my-btn");
btn.addEventListener("click",function(event){
        handler.handleClick(event);  //此处用handler对象调用函数,因此this就会指向handler对象
    },false);

在实际应用中,Javascript为所有函数提供了更方便的bind()方法来解决这个问题,该方法接受1个参数,即要作为this值的对象

var handler = {
    message = "Event handle",
    handleClick : function(event){
        alert(this.message);
    }
};

var btn = docuemnt.getElementById("my-btn");
btn.addEventListener("click",handler.handleClick.bind(handler),false);

有关This对象的更多内容可以看看这两篇文章:
https://blog.youkuaiyun.com/zjw_python/article/details/80141312
https://blog.youkuaiyun.com/zjw_python/article/details/80141792


函数柯里化

用于创建已经设置好了一个参数或多个参数的函数。用通俗的话讲,比如有一个接受两个参数的函数,现在我要固定其中一个参数的值,让原本接受两个参数的函数变为只接受一个参数的函数,这样的过程就叫函数柯里化。

创建柯里化函数的基本方法是使用一个闭包返回一个函数,与函数绑定类似

function curry(fn){
    var args = Array.prototype.slice.call(arguments,1);
    return function(){
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return fn.apply(null, finalArgs);
    };
}

注意,这里的两个arguments对象不是同一个对象,第一个是包含了创建柯里化函数时传入的参数,第二个是包含了调用柯里化函数传入的参数。因此要将两次传入的参数一并传给原来的函数。而且由于没有考虑到执行环境,所以调用apply()时第一个参数是null,下面是使用的例子

function add(num1,num2){
    return num1 + num2;
}

var curriedAdd = curry(add,5);
alert(curriedAdd(3));   //8

函数柯里化还常常作为函数绑定的一部分包含在其中,构造成更复杂的bind()函数

function bind(fn,context){   //接受两个参数,原函数和一个作为执行环境的对象
    var args = Array.prototype.slice.call(arguments,2);   //从第2项开始以后才是参数
    return function(){
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return fn.apply(context, finalArgs);    //执行环境不再是null
    };
}

Javascript的bind()方法,也提供函数柯里化功能,只需在this值之后,再传入一个参数即可

var handler = {
    message = "Event handle",
    handleClick : function(name, event){
        alert(this.message + ":" + name + ":" + evnet.type);
    }
};

var btn = docuemnt.getElementById("my-btn");
btn.addEventListener("click",handler.handleClick.bind(handler,"my-btn"),false);

防篡改对象

不可扩展对象
Object.preventExtensions()方法使对象不可添加新属性和方法,但仍可以删除或修改原有属性和方法

var person = {name:"zjw"};
Object.preventExtensions(person);

person.age = 29;
alert(person.age);  //undefined

密封对象
Object.seal()方法使对象不可扩展,且无法删除属性和方法,但可以修改原有属性

var person = {name:"zjw"};
Object.seal(person);

person.age = 29;
alert(person.age);  //undefined

delete person.name;
alert(person.name);  //"zjw"

冻结对象
Object.freeze()方法使对象冻结,冻结的对象即不可扩展,又是密封的,且不可修改原有属性的值

var person = {name:"zjw"};
Object.freeze(person);

person.age = 29;
alert(person.age);  //undefined

delete person.name;
alert(person.name);  //"zjw"

person.name = "wjz";
alert(person.name);  //"zjw"

高级定时器

Javascript是运行于单线程的环境中,而setTimeout()和setInterval()创建的计时器仅仅是计划代码在未来的某个时间执行,执行时机是不能保证的,因为不同时间可能有其他代码在控制着Javascript的进程。

比如设定了150ms后执行的定时器不代表150ms代码就立刻执行,它表示代码会在150ms后被加入到队列,如果此时,队列中没有其他东西,那么这段代码才会被执行。

重复的定时器

使用setInterval()创建的定时器确保了定时器代码规则地插入队列中。当队列中没有该定时器的任何代码时,才将定时器代码添加到队列中,避免了定时器代码连续运行无停顿的问题。但这种重复定时器规则有两个问题:(1)某些间隔会被跳过;(2)多个定时器的代码执行之间的间隔可能会被预期小。
为了避免这个问题,可以使用链式setTimeout()调用,其保证了在前一个定时器执行完之前,不会向队列中插入新的定时器代码,确保了不会有任何缺失的时间间隔。

setTimeout(function(){
    //do something
    setTimeout(arguments.callee,interval);
},interval);

数据分块

Javascript有一个限制是长时间运行脚本的制约,如果代码运行超过特定的时间或者特定的语句数量就不能让它继续执行。造成脚本长时间运行的原因可能有:过长的、过深嵌套的函数调用或者进行大量的处理的循环。当你的循环不需要同步完成且处理顺序不重要时,可以使用数据分块技术来解决这个问题

//原本的循环
for (var i=0, len=data.length; i < len; i++){
    process(data[i]);
}

//数据分块后的循环
setTimeout(function(){
    //取出下一条数据并处理
    var item = array.shift();
    process(item);

    //若还有项目,再设置另一个定时器
    if (array.length > 0 ){
        setTimeout(arguments.callee, 100);
    }
},100);

使用定时器进行间歇调用,防止过长的脚本运行时间造成阻塞

函数节流

某些高频率的更改可能会让浏览器崩溃,为了避免这个问题,可使用定时器对该函数节流

function throttle(method,context){
    clearTimeout(method.tId);
    method.tId = setTimeout(function(){
        method.call(context);
    },100);
}

该函数接受两个参数,要执行的函数和作为执行环境的对象

70、JavaScript高级技巧:函数柯里化、防篡改对象与高级定时器 本文深入探讨了JavaScript中的三项高级技巧:函数柯里化、防篡改对象和高级定时器。函数柯里化通过绑定部分参数创建动态函数,适用于表单验证和动态函数生成;防篡改对象通过不可扩展、密封和冻结三种形式保护对象不被修改,适用于库开发中核心对象的保护;高级定时器通过setTimeout和链式调用优化代码执行时间,适用于动画效果和定时任务。文章还详细分析了这些技巧的应用场景及最佳实践,帮助开发者编写更灵活、安全、高效的JavaScript代码。 阅读详情

相关推荐

ES6中javascript实现函数绑定及类的事件绑定功能详解

主要介绍了ES6中javascript实现函数绑定及类的事件绑定功能,结合实例形式分析了ES6中函数绑定及类的事件绑定原理、实现方法、相关操作技巧与注意事项,需要的朋友可以参考下

JS中的函数绑定以及实现函数柯里化

假设页面有个按钮btn,实现点击打印message信息和事件类型(暂只介绍ES5,ES6中函数绑定运算符::以后会补充)。 第一步: var handler = { message:'hello world', handleClick:function(e){ console.log(this.message) console.log(e.typ...

个人前端记录 1089

手把手教你用EGM96模型校正DEM数据(含在线工具推荐)

本文详细介绍了如何使用EGM96地球重力场模型校正DEM数据中的高程偏差。通过对比WGS84椭球面与大地水准面的差异,解释了校正原理,并提供了从在线工具快速验证到Python脚本批量处理的全流程实战指南,帮助GIS开发者和数据分析师确保高程数据基准一致,提升空间分析精度。

ttt77的博客 1007

js高阶函数应用—函数柯里化和反柯里化

在Lambda演算(一套数理逻辑的形式系统,具体我也没深入研究过)中有个小技巧:假如一个函数只能收一个参数,那么这个函数怎么实现加法呢,因为高阶函数是可以当参数传递和返回值的,所以问题就简化为:写一个只有一个参数的函数,而这个函数返回一个带参数的函数,这样就实现了能写两个参数的函数了(具体参见下边代码)——这就是所谓的柯里化(Currying,以逻辑学家Hsakell Curry命名),...

weixin_30567471的博客 968

Qt绘图库对决:QWT与QCustomPlot的实战选型指南

本文为Qt开发者提供了QWT与QCustomPlot两大绘图库的实战选型指南。文章从功能特性、性能资源、开发效率三大维度进行深度对比,并结合工业监控、科学计算、嵌入式设备等典型场景,给出了清晰的决策清单。对于需要专业科学图表(如极坐标、等高线图)的场景推荐QWT;对于追求高性能、实时性、快速开发及嵌入式部署的通用图表需求,QCustomPlot是更优选择。

alpha的博客 241

集成电路设计笔记(七)UVLO设计

1. 什么是UVLO 欠压锁定(Undervoltage-Lockout)简称UVLO,是电子设备中在电源电压低于正常工程准位时,切断电源的电路。在嵌入式系统中常会用UVLO监控电池电压,若电压低于一定值,会直接切断电源,保护嵌入式系统的电路。 许多电子设备中都有UVLO的功能,例如在镇流器中就有UVLO电路,若电压过低时直接切断电源。 UVLO就是低电压锁定; 低压关断. 欠压关断模式是当供电电压低于IC的开启门限电压时的一种保护模式。欠压关断模式可保证IC在供电电压不足时不致于被损坏。一个低电压锁定(

ccbirds 2万+

JS高级定时器

相信使用过setTimeout()和setInterval()创建定时器的都知道可以实现一些有趣好玩的功能,但是肯定也是遇到过一些问题,或者是对JavaScript的定时器存在一定的误解。以下是根据我使用过的定时器和高程3里面高级定时器一节的整理 javascript是运行在单线程的环境中的。而定时器仅仅是计划代码在未来的某个时间执行,并不能保证执行的时间,原因是在页面的生命周期中,不同时间有可能有

Chaney__Chen的博客 715

泛微OAe9-自定义资源看板

OA中,有一个很好用的功能:会议室预约。对于一间设立的会议室,同一时间段内,肯定会有不同的人预约同一间会议室,并且,在资源看板里,能看清各个时间段会议室的占用情况,可是会议室资源是有限的,显然不可能让多个人在同一时间段内预约同一间会议室,如会议室已占用,其他人再次申请时,应当拒绝预约。

小松鼠的博客 1848

高级函数

高级函数 安全的类型检测 在检测某个对象到底是原生对象还是开发人员自定义对象的时候,也存在问题。出现这个问题的原因是: 浏览器开始支持原生的JSON对象了。因为好多人一直使用Douglas Crockford的JSON库,而该库定义了一个全局JSON对象。于是开发人员很难断定页面中的JSON对象到底是不是原生的。 这里凭着观察肯定不知道JSON对象是原生的还是自定义对象,因为这里有两种JSON...

boysky0015的博客 155

Coze智能体开发:如何搭建一个生成长文本的工作流

扣子工作流提供了流程定制化的能力,我们可以把长文生成的流程拆分为多个步骤,例如先通过大模型节点生成大纲、再使用循环节点依次扩写各个段落,最后将各个段落组合起来,从而实现长文生成流程。此工作流可适用于学术写作、商业报告、小说创作等多种场景。

王国平的博客 1789

YOLO + SubspaceAD:一张良品图,检出所有未知缺陷

当YOLO遇上子空间建模,工业质检正迎来从“见多识广”到“举一反三”的质变时刻。

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 496

JS高阶函数(函数柯里化)

函数柯里化的好处有三个: 可以将函数作为参数传递 (用于参数复用) 可以将函数作为返回值输出 (提前返回) 函数的延迟计算 (使用较少) 缺点: 【通用函数】解决了兼容性问题,但同时也会再来,使用的不便利性,不同的应用场景往,要传递很多参数,以达到解决特定问题的目的。有时候应用中,同一种规则可能会反复使用,这就可能会造成代码的重复性。 总结:说白了柯里化就是用到了很多闭包,递归,参数展...

友人C君的博客 1553

【OpenClaw企业级智能体实战】第04篇:OpenClaw成本优化实战——Token消耗降96%!claude-mem+OpenViking从入门到精通

OpenClaw作为企业级智能体框架,凭借强大的自动化能力成为企业数字化转型的热门工具,但原生机制导致的上下文冗余问题,让众多用户面临“Token消耗失控”的困境——单周账单数千元的案例屡见不鲜。本文基于阿里云实测数据与开源工具官方文档,先深度拆解OpenClaw成本黑洞的核心成因(记忆碎片化、Token指数级膨胀),再系统讲解两款核心优化工具(claude-mem单Agent记忆管理、OpenViking多Agent集群底座)的底层原理、算法架构与实现逻辑,提供从环境搭建、工具集成、参数调优到安全部署

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 703

JS 函数柯里化

在 JavaScript 开发中,函数柯里化是一个非常重要的概念,它不仅可以提升代码的复用性和可读性,还能在某些场景下优化性能。本文将深入探讨函数柯里化的原理、实现方法以及实际应用场景。

前端小巷子的博客 643

使用 ABAP Development Tool 登录 SAP BTP ABAP 环境时,遇到弹出框应该怎么办?

但在实际环境里,隐私模式、第三方 Cookie 禁止、跨站追踪限制、缓存代理误命中、混合内容拦截等因素,都可能让这条跳转链路被打断。等),浏览器会弹出系统原生登录框,请求用户输入账号和口令或做集成认证。只要它们在响应头里出现,浏览器就会理直气壮地弹框,这是协议层的强约定。,最终弹出原生登录框。前端与网关领域有个通用的经验规则:如果你看到了原生登录框,而期望的是带样式的。环境里的登录方式表述为基于浏览器的前端认证,也就是这类重定向式的交互。环境的具体落地,拆出几类常见诱因与排障路径,并穿插真实世界的案例。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 369

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

函数柯里化

高级函数技巧 函数柯里化 用于创建已经设置了一个或多个参数的函数。函数柯里化的基本方法是函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。 function add(num1,num2){ return num1+num2; } function curriedAdd(num2){ return add(5,n...

weixin_30496751的博客 204

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

JavaScript函数绑定Demo以及函数Currying柯里化

例1: Function Binding Example function bind(fn, context){ return function(){ return fn.apply(context, arguments); }; }

Dove_Knowledge的博客 1034

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【汇总】JS高级知识汇总

【汇总】JS高级知识汇总

weixin_50926010的博客 7119

【深入理解JS核心技术】15. 什么是柯里化函数

柯里化是将具有多个参数的函数转换为一系列函数的过程,每个函数只有一个参数。Currying以数学家Haskell Curry的名字命名。通过应用柯里化,n 元函数将其转换为一元函数。让我们举一个 n 元函数的例子,以及它是如何变成柯里化函数的,const multiArgFunction = (a, b, c) => a + b + c; console.log(...

程序员哆啦A梦,蓝胖子 650

Curry - 使用JavaScript实现的函数柯里化库

Curry - 使用JavaScript实现的函数柯里化库 是一个轻量级、实用的JavaScript库,用于实现函数的柯里化(Currying)。它可以帮助开发人员更容易地处理复杂的函数组合,并在编程中利用函数式编程的优势。 什么是柯里化? 柯里化是将一个多参数的函数转换为一系列单参数函数的过程。这样做的好处是可以提前绑定部分参数值,然后生成一个更易于调用和复用的新函数。 例如,您可能有一个接受两...

gitblog_00002的博客 530

理解Javascipt函数柯里化

《JavaScript高级程序设计》第22章关于函数柯里化的理解 function curry(fn){ var args=Array.prototype.slice.call(arguments,1); return function(){ var innerArgs=Array.prototype.slice.call(arguments); ...

愚蠢的土拨鼠要变聪明的博客 319

柯里化函数

function curry(fn){ var args = Array.prototype.slice.call(arguments, 1); return function(){ var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); r...

wyf 194

关于js的高级函数(惰性函数,函数柯里化,级联函数)

《1》首先是惰性函数 惰性载入表示函数执行的分支只会在函数第一次掉用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了。 看下面典型的例子: 为了兼容各浏览器,对事件监听的的支持: function addEvent (type, element, fun) { if (element.addEventList...

weixin_30333885的博客 199

Web前端学习笔记17:JavaScript高级_函数_this_严格模式_高阶函数_递归_正则表达式

文章目录JavaScript高级第03天笔记1.函数的定义和调用1.1函数的定义方式1.2函数的调用2.this2.1函数内部的this指向2.2改变函数内部 this 指向2.2.1 call方法2.2.2 apply方法2.2.3 bind方法2.2.4 call、apply、bind三者的异同3.严格模式3.1什么是严格模式3.2开启严格模式3.3严格模式中的变化4.高阶函数5.闭包5.1变量的作用域复习5.2什么是闭包5.3闭包的作用5.4闭包的案例5.5案例6.递归6.1什么是递归6.2利用递归求

JasonYangQ的博客 8092

浅谈柯里化函数

柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。下面是创建柯里化函数的通用方式: function curry(fn){ var args=Array.prototype.slice.call(arguments,1); return function(){ var innerArgs=Arra...

weixin_34387284的博客 95

【原生JS】JavaScript 教程教案

摘要: 老曹的 JavaScript 教程教案 提供从基础到进阶的 20 节系统性课程,涵盖语法、DOM 操作、异步编程、ES6+ 新特性等核心内容。课程分为 基础篇(变量、函数、数组、DOM)和 高级篇(闭包、原型链、Promise、模块化),结合实战项目(如待办清单、天气应用)巩固技能。推荐配套书籍《Eloquent JavaScript》和 MDN 文档,并介绍现代工具链(VSCode、Webpack)。适合零基础入门或开发者进阶,最终目标为掌握全栈 JavaScript 开发能力

silverclayz的技术分享 2454
上一篇: Javascript 函数中This的绑定形式(转载)
下一篇: Javascript学习笔记18 高级技巧(自定义事件 拖放)
PAT-python-zjw
博客等级 码龄10年 381粉丝 408原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值