search
HomeWeb Front-endJS TutorialShare 5 advanced techniques for JS functions

Share 5 advanced techniques for JS functions

Oct 26, 2020 pm 05:57 PM
javascriptfunction

Share 5 advanced techniques for JS functions

A function is an event-driven or reusable block of code that executes when it is called. Functions are a core concept for any language, especially in JavaScript. This article will provide an in-depth introduction to 5 advanced techniques for functions.

Scope-safe constructor

The constructor is actually a function called using the new operator

function Person(name,age,job){
    this.name=name;    
    this.age=age;    
    this.job=job;
}
var person=new Person('match',28,'Software Engineer');
console.log(person.name);//match

If the new operator is not used, The three attributes originally targeted at the Person object were added to the window object

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
}
var person = Person('match', 28, 'Software Engineer');
console.log(person); //undefinedconsole.log(window.name);//match

The name attribute of window is used to identify the link target and frame. Accidental overwriting of this attribute here may cause other errors on the page. The solution to this problem is to create a scope-safe constructor.

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);
    }
}
var person = Person('match', 28, 'Software Engineer');
console.log(window.name); // ""
console.log(person.name); //'match'
var person= new Person('match',28,'Software Engineer');
console.log(window.name); // ""
console.log(person.name); //'match'

However, inheritance of the constructor stealing pattern will bring side effects. This is because, in the following code, the this object is not an instance of the Polygon object, so the constructor Polygon() will create and return a new instance.

function Polygon(sides) {
    if (this instanceof Polygon) {
        this.sides = sides;
        this.getArea = function() {
            return 0;
        }
    } else {
        return new Polygon(sides);
    }
}
function Rectangle(wifth, height) {
    Polygon.call(this, 2);
    this.width = this.width;
    this.height = height;
    this.getArea = function() {
        return this.width * this.height;
    };
}
var rect = new Rectangle(5, 10);
console.log(rect.sides); //undefined

If you want to use the scope-safe constructor stealing pattern, you need to combine prototype chain inheritance and rewrite the prototype attribute of Rectangle so that its instance also becomes an instance of Polygon.

function Polygon(sides) {
    if (this instanceof Polygon) {
        this.sides = sides;
        this.getArea = function() {
            return 0;
        }
    } else {
        return new Polygon(sides);
    }
}
function Rectangle(wifth, height) {
    Polygon.call(this, 2);
    this.width = this.width;
    this.height = height;
    this.getArea = function() {
        return this.width * this.height;
    };
}
Rectangle.prototype = new Polygo

Lazy loading function

Because of the differences in behavior between browsers, we often include a large number of if statements in the function to check the browsing browser features to solve compatibility issues with different browsers. For example, our most common function for adding events to dom nodes

function addEvent(type, element, fun) {
    if (element.addEventListener) {
        element.addEventListener(type, fun, false);
    } else if (element.attachEvent) {
        element.attachEvent('on' + type, fun);
    } else {
        element['on' + type] = fun;
    }
}

Every time the addEvent function is called, it must check the capabilities supported by the browser. First, check whether the addEventListener method is supported. If not, If it is supported, then check whether the attachEvent method is supported. If it is not supported yet, use the dom0 level method to add the event.

This process must be carried out every time the addEvent function is called. In fact, if the browser supports one of the methods, then it will always support it, and there is no need to carry out other branches. Detected. In other words, the if statement does not have to be executed every time, and the code can run faster.

The solution is lazy loading. The so-called lazy loading means that the branch of function execution will only occur once. There are two ways to implement lazy loading

1. The first is to process the function when the function is called. When the function is called for the first time, the function will be overwritten as another function that is executed in an appropriate manner, so that any call to the original function does not need to go through the branch of execution.

We can use the following method Rewrite addEvent() using lazy loading

function addEvent(type, element, fun) {
    if (element.addEventListener) {
        addEvent = function(type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    } else if (element.attachEvent) {
        addEvent = function(type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    } else {
        addEvent = function(type, element, fun) {
            element['on' + type] = fun;
        }
    }
    return addEvent(type, element, fun);
}

In this lazy loading addEvent(), each branch of the if statement assigns a value to the addEvent variable, effectively covering the original function. The last step is to call the new assignment function. The next time addEvent() is called, the newly assigned function will be called directly, so there is no need to execute the if statement.

However, this method has a disadvantage. If the function name changes, it will be more troublesome to modify.

2. The second is to specify the appropriate function when declaring the function. In this way, there will be no performance loss when the function is called for the first time, but only a small performance loss when the code is loaded. The following is addEvent() rewritten according to this idea. The following code creates an anonymous self-executing function that branches through different functions to determine which function implementation should be used.

var addEvent = (function() {
    if (document.addEventListener) {
        return function(type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    } else if (document.attachEvent) {
        return function(type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    } else {
        return function(type, element, fun) {
            element['on' + type] = fun;
        }
    }
})();

Function binding

In the interaction between javascript and DOM, it is often necessary to use function binding. Define a function and then bind it to a specific DOM element or collection. On an event triggering program, binding functions are often used together with callback functions and event handlers to pass functions as variables while retaining the code execution environment.

<button id="btn">按钮</button>
<script>var handler = {
    message: "Event handled.",
    handlerFun: function() {
      alert(this.message);
    }
  };
  btn.onclick = handler.handlerFun;</script>

The above code creates an object called handler. The handler.handlerFun() method is assigned as an event handler for a DOM button. When the button is pressed, this function is called and an alert box is displayed.

Although it seems that the warning box should display Event handled, it actually displays undefiend. The problem is that the environment of handler.handleClick() is not saved, so this object ends up pointing to the DOM button instead of the handler.

You can use closures to fix this problem

<button id="btn">按钮</button>
<script>var handler = {
    message: "Event handled.",
    handlerFun: function() {
      alert(this.message);
    }
  };
  btn.onclick = function() {
    handler.handlerFun();
  }</script>

Of course this is a solution specific to this scenario, creating multiple closures may make the code difficult to understand and debug. A better approach is to use function binding.

A simple binding function bind() accepts a function and an environment, and returns a function that calls the given function in the given environment, passing all parameters intact.

function bind(fn, context) {
    return function() {
        return fn.apply(context, arguments);
    }
}

This function seems simple, but its function is very powerful. A closure is created in bind(). The closure uses apply() to call the incoming function and passes the context object and parameters to apply(). When the returned function is called, it executes the passed function in the given environment and gives all arguments.

<button id="btn">按钮</button>
<script>function bind(fn, context) {
    return function() {
      return fn.apply(context, arguments);
    }
  }
  var handler = {
    message: "Event handled.",
    handlerFun: function() {
      alert(this.message);
    }
  };
  btn.onclick = bind(handler.handlerFun, handler);</script>

ECMAScript5 defines a native bind() method for all functions, further simplifying operations.

只要是将某个函数指针以值的形式进行传递,同时该函数必须在特定环境中执行,被绑定函数的效用就突显出来了。它们主要用于事件处理程序以及setTimeout()和setInterval()。

然而,被绑定函数与普通函数相比有更多的开销,它们需要更多内存,同时也因为多重函数调用稍微慢一点,所以最好只在必要时使用。

函数柯里化

与函数绑定紧密相关的主题是函数柯里化(function currying),它用于创建已经设置好了一个或多个参数的函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。

function add(num1, num2) {
    return num1 + num2;
}
function curriedAdd(num2) {
    return add(5, num2);
}
console.log(add(2, 3)); //5
console.log(curriedAdd(3));//8

这段代码定义了两个函数:add()和curriedAdd()。后者本质上是在任何情况下第一个参数为5的add()版本。尽管从技术来说curriedAdd()并非柯里化的函数,但它很好地展示了其概念。

柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。

下面是创建柯里化函数的通用方式:

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

curry()函数的主要工作就是将被返回函数的参数进行排序。curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。

为了获取第一个参数之后的所有参数,在arguments对象上调用了slice()方法,并传入参数1表示被返回的数组包含从第二个参数开始的所有参数。然后args数组包含了来自外部函数的参数。在内部函数中,创建了innerArgs数组用来存放所有传入的参数(又一次用到了slice())。

有了存放来自外部函数和内部函数的参数数组后,就可以使用concat()方法将它们组合为finalArgs,然后使用apply()将结果传递给函数。注意这个函数并没有考虑到执行环境,所以调用apply()时第一个参数是null。curry()函数可以按以下方式应用。

function add(num1, num2) {
    return num1 + num2;
}
var curriedAdd = curry(add, 5);
alert(curriedAdd(3)); //8

在这个例子中,创建了第一个参数绑定为5的add()的柯里化版本。当调用cuurriedAdd()并传入3时,3会成为add()的第二个参数,同时第一个参数依然是5,最后结果便是和8。也可以像下例这样给出所有的函数参数:

function add(num1, num2) {
    return num1 + num2;
}
var curriedAdd2 = curry(add, 5, 12);
alert(curriedAdd2()); //17

在这里,柯里化的add()函数两个参数都提供了,所以以后就无需再传递给它们了,函数柯里化还常常作为函数绑定的一部分包含在其中,构造出更为复杂的bind()函数。

function bind(fn, context) {
    var args = Array.prototype.slice.call(arguments, 2);
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments),
        finalArgs = args.concat(innerArgs);
        return fn.apply(context, finalArgs);
    };
}

对curry()函数的主要更改在于传入的参数个数,以及它如何影响代码的结果。curry()仅仅接受一个要包裹的函数作为参数,而bind()同时接受函数和一个object对象。

这表示给被绑定的函数的参数是从第三个开始而不是第二个,这就要更改slice()的第一处调用。另一处更改是在倒数第3行将object对象传给apply()。当使用bind()时,它会返回绑定到给定环境的函数,并且可能它其中某些函数参数已经被设好。

要想除了event对象再额外给事件处理程序传递参数时,这非常有用。

var handler = {
    message: "Event handled",
    handleClick: function(name, event){
        alert(this.message + ":" + name + ":" + event.type);
    }
};var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler, "my-btn"));

handler.handleClick()方法接受了两个参数:要处理的元素的名字和event对象。作为第三个参数传递给bind()函数的名字,又被传递给了handler.handleClick(),而handler.handleClick()也会同时接收到event对象。

ECMAScript5的bind()方法也实现函数柯里化,只要在this的值之后再传入另一个参数即可。

var handler = {
    message: "Event handled",
    handleClick: function(name, event) {
        alert(this.message + ":" + name + ":" + event.type);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler, "my-btn"));

javaScript中的柯里化函数和绑定函数提供了强大的动态函数创建功能。使用bind()还是curry()要根据是否需要object对象响应来决定。它们都能用于创建复杂的算法和功能,当然两者都不应滥用,因为每个函数都会带来额外的开销。

函数重写

由于一个函数可以返回另一个函数,因此可以用新的函数来覆盖旧的函数。

function a(){
    console.log(&#39;a&#39;);
    a = function(){
        console.log(&#39;b&#39;);
    }
}

这样一来,当我们第一次调用该函数时会console.log('a')会被执行;全局变量a被重定义,并被赋予新的函数

当该函数再次被调用时, console.log('b')会被执行。

再复杂一点的情况如下所示:

var a = (function() {
    function someSetup() {
        var setup = &#39;done&#39;;
    }
    function actualWork() {
        console.log(&#39;work&#39;);
    }
    someSetup();
    return actualWork;
})()

我们使用了私有函数someSetup()和actualWork(),当函数a()第一次被调用时,它会调用someSetup(),并返回函数actualWork()的引用。

相关免费学习推荐:js视频教程

更多编程相关知识,请访问:编程入门!!

The above is the detailed content of Share 5 advanced techniques for JS functions. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:51cto. If there is any infringement, please contact admin@php.cn delete
JavaScript Engines: Comparing ImplementationsJavaScript Engines: Comparing ImplementationsApr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Beyond the Browser: JavaScript in the Real WorldBeyond the Browser: JavaScript in the Real WorldApr 12, 2025 am 12:06 AM

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)Apr 11, 2025 am 08:22 AM

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

JavaScript: Exploring the Versatility of a Web LanguageJavaScript: Exploring the Versatility of a Web LanguageApr 11, 2025 am 12:01 AM

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

The Evolution of JavaScript: Current Trends and Future ProspectsThe Evolution of JavaScript: Current Trends and Future ProspectsApr 10, 2025 am 09:33 AM

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

Demystifying JavaScript: What It Does and Why It MattersDemystifying JavaScript: What It Does and Why It MattersApr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

Is Python or JavaScript better?Is Python or JavaScript better?Apr 06, 2025 am 12:14 AM

Python is more suitable for data science and machine learning, while JavaScript is more suitable for front-end and full-stack development. 1. Python is known for its concise syntax and rich library ecosystem, and is suitable for data analysis and web development. 2. JavaScript is the core of front-end development. Node.js supports server-side programming and is suitable for full-stack development.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

VSCode Windows 64-bit Download

VSCode Windows 64-bit Download

A free and powerful IDE editor launched by Microsoft

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools