javascript编写

Have you ever asked yourself how a framework works?

您是否曾经问过自己框架是如何工作的?

When I discovered AngularJS after learning jQuery many years ago, AngularJS seemed like dark magic to me.

多年前学习jQuery后,当我发现AngularJS时 ,AngularJS在我看来就像是黑魔法。

Then Vue.js came out, and upon analyzing how it works under the hood, I was encouraged to try writing my own two-way binding system.

然后Vue.js出现了,并且在分析了它的幕后工作原理后,我被鼓励尝试编写自己的双向绑定系统 。

In this article, I’ll show you how to write a modern JavaScript framework with custom HTML element attributes, reactivity, and double-binding.

在本文中,我将向您展示如何编写具有自定义HTML元素属性,React性和双重绑定的现代JavaScript框架。

React性如何工作? (How does reactivity work?)

It would be good to start with an understanding of how reactivity works. The good news is that this is simple. Actually, when you declare a new component in Vue.js, the framework will proxify each property (getters and setters) using the proxy design pattern.

最好先了解React性如何工作。 好消息是,这很简单。 实际上,当您在Vue.js中声明一个新组件时,该框架将使用代理设计模式代理 每个属性 (getter和setter)。

Thus it will be able to detect property value changes both from code and user inputs.

因此,它将能够从代码和用户输入中检测属性值的变化。

代理设计模式是什么样的 (What the proxy design pattern looks like)

The idea behind the proxy pattern is simply to overload access to an object. An analogy in real life could be the access to your bank account.

代理模式背后的想法仅仅是使对对象的访问超载。 现实生活中的类比可能是访问您的银行帐户。

For example, you can’t directly access your bank account balance and change the value according to your needs. It is necessary for you to ask someone that has this permission, in this case, your bank.

例如,您不能直接访问您的银行帐户余额并根据需要更改值。 您必须询问具有此权限的人,在这种情况下,是您的银行。

var account = {balance: 5000
}// A bank acts like a proxy between your bank account and you
var bank = new Proxy(account, {get: function (target, prop) {return 9000000;}
});console.log(account.balance); // 5,000 (your real balance)
console.log(bank.balance);    // 9,000,000 (the bank is lying)
console.log(bank.currency);   // 9,000,000 (the bank is doing anything)

In the example above, when using the bank object to access the account balance, the getter function is overloaded, and it always returns 9,000,000 instead of the property value, even if the property doesn’t exist.

在上面的示例中,当使用bank对象访问account余额时,getter函数被重载,即使该属性不存在,它也总是返回9,000,000而不是该属性值。

// Overload setter default function
var bank = new Proxy(account, {set: function (target, prop, value) {// Always set property value to 0return Reflect.set(target, prop, 0); }
});account.balance = 5800;
console.log(account.balance); // 5,800bank.balance = 5400;
console.log(account.balance); // 0 (the bank is doing anything)

By overloading the set function, it’s possible to manipulate its behavior. You can change the value to set, update another property instead, or even not do anything at all.

通过重载set函数,可以操纵其行为。 您可以更改该值以进行设置,改为更新另一个属性,甚至完全不执行任何操作。

React性示例 (Reactivity example)

Now that you’re confident about how the proxy design pattern works, let’s begin writting our JavaScript framework.

现在,您对代理设计模式的工作方式很有信心,让我们开始编写我们JavaScript框架。

To keep it simple, we’ll mimic the AngularJS syntax to do it. Declaring a controller and binding template elements to controller properties is quite straightforward.

为了简单起见,我们将模仿AngularJS语法来做到这一点。 声明一个控制器并将模板元素绑定到控制器属性非常简单。

<div ng-controller="InputController"><!-- "Hello World!" --><input ng-bind="message"/>   <input ng-bind="message"/>
</div><script type="javascript">function InputController () {this.message = 'Hello World!';}angular.controller('InputController', InputController);
</script>

First, define a controller with properties. Then use this controller in a template. Finally, use the ng-bind attribute to enable double-binding with the element value.

首先,定义一个带有属性的控制器。 然后在模板中使用此控制器。 最后,使用ng-bind属性启用与元素值的双重绑定。

解析模板并实例化控制器 (Parse template and instantiate the controller)

To have properties to bind, we need to get a place (aka controller) to declare those properties. Thus, it is necessary to define a controller and introduce it to our framework.

要绑定属性,我们需要一个位置(又称控制器)来声明这些属性。 因此,有必要定义一个控制器并将其引入我们的框架。

During the controller declaration, the framework will look for elements that have ng-controller attributes.

在控制器声明期间,框架将查找具有ng-controller属性的元素。

If it fits with one of the declared controllers, it will create a new instance of this controller. This controller instance is only responsible for this particular piece of template.

如果适合声明的控制器之一,它将创建该控制器的新实例。 该控制器实例仅负责此特定模板。

var controllers = {};
var addController = function (name, constructor) {// Store controller constructorcontrollers[name] = {factory: constructor,instances: []};// Look for elements using the controllervar element = document.querySelector('[ng-controller=' + name + ']');if (!element){return; // No element uses this controller}// Create a new instance and save itvar ctrl = new controllers[name].factory;controllers[name].instances.push(ctrl);// Look for bindings.....
};addController('InputController', InputController);

Here is what the handmade controllers variable declaration looks like. The controllers object contains all controllers declared within the framework by calling addController.

这是手工controllers变量声明的样子。 controllers对象包含通过调用addController在框架内声明的所有控制器。

For each controller, a factory function is saved to instantiate a new controller when needed. The framework also stores each of the new instances of the same controller used in the template.

对于每个控制器,将保存factory功能以在需要时实例化新控制器。 该框架还存储模板中使用的同一控制器的每个新实例。

寻找绑定 (Looking for bindings)

At this point, we’ve got an instance of the controller and a piece of template using this instance.

至此,我们已经有了一个控制器实例和一个使用该实例的模板。

The next step is to look for elements with bindings which use controller properties.

下一步是寻找具有绑定的元素,这些绑定使用控制器属性。

var bindings = {};// Note: element is the dom element using the controller
Array.prototype.slice.call(element.querySelectorAll('[ng-bind]')).map(function (element) {var boundValue = element.getAttribute('ng-bind');if(!bindings[boundValue]) {bindings[boundValue] = {boundValue: boundValue,elements: []}}bindings[boundValue].elements.push(element);});

Quite simple, it stores all bindings of an object (used as a hash map). This variable contains all the properties to bind with the current value and all DOM elements which bind this property.

非常简单,它存储对象的所有绑定(用作哈希映射 )。 此变量包含所有要与当前值绑定的属性以及所有与该属性绑定的DOM元素。

双绑定控制器属性 (Double bind controller properties)

After the preliminary work has been done by the framework, now comes the interesting part: double-binding.

在框架完成了初步工作之后,现在出现了有趣的部分: double-binding

It involves binding the controller property to the DOM elements to update the DOM whenever the code updates the property value.

它涉及将控制器属性绑定到DOM元素以在代码更新属性值时更新DOM。

Also, don’t forget to bind the DOM elements to the controller property. This way, when the user changes the input value, it’ll update the controller property. Then it will also update all other elements bound to this property.

另外,不要忘记将DOM元素绑定到controller属性。 这样,当用户更改输入值时,它将更新控制器属性。 然后,它还将更新绑定到该属性的所有其他元素。

使用代理检测代码更新 (Detect updates from code with a proxy)

As explained above, Vue wraps components within a proxy to react to property changes. Let’s do the same by proxying the setter only for controller bound properties.

如上所述,Vue将组件包装在代理中以对属性更改做出React。 通过仅为控制器绑定的属性代理设置器来进行相同的操作。

// Note: ctrl is the controller instance
var proxy = new Proxy(ctrl, {set: function (target, prop, value) {var bind = bindings[prop];if(bind) {// Update each DOM element bound to the property  bind.elements.forEach(function (element) {element.value = value;element.setAttribute('value', value);});}return Reflect.set(target, prop, value);}
});

Whenever a bound property is set, the proxy will check all elements bound to this property. Then it will update them with the new value.

无论何时设置绑定属性,代理都会检查绑定到该属性的所有元素。 然后它将使用新值更新它们。

In this example, we support only input elements binding, because only the value attribute is set.

在此示例中,我们仅支持输入元素绑定,因为仅设置了value属性。

对元素事件做出React (React to element events)

The last thing to do is reacting to user interactions. DOM elements trigger events when they detect a value change.

最后要做的是对用户交互做出React。 DOM元素在检测到值更改时触发事件。

Listen to those events and update the bound property with the new value from the event. All other elements bound to the same property will update automatically thanks to the proxy.

侦听那些事件,并使用事件中的新值更新绑定属性。 由于代理,绑定到同一属性的所有其他元素将自动更新。

Object.keys(bindings).forEach(function (boundValue) {var bind = bindings[boundValue];// Listen elements event and update proxy property   bind.elements.forEach(function (element) {element.addEventListener('input', function (event) {proxy[bind.boundValue] = event.target.value; // Also triggers the proxy setter});})
});

Once you put everything together, you get handmade double-bound inputs. Here is a working demo including all the code.

将所有内容放到一起后,您将获得手工制作的双向输入。 这是一个包含所有代码的有效演示。

Thank you for reading. I hope it helped you to demystify how JavaScript frameworks work.

感谢您的阅读。 我希望它能帮助您揭开JavaScript框架的神秘面纱。

Congratulations! You’ve developed popular features such as custom HTML element attributes, reactivity, and double-binding!

恭喜你! 您已经开发了流行的功能,例如自定义HTML元素属性,React性和双重绑定!

If you found this article useful, please click on the

javascript编写_如何通过编写自己的Web开发框架来提高JavaScript技能相关推荐

  1. javascript面试_在编码面试中需要注意的3个JavaScript问题

    javascript面试 JavaScript is the official language of all modern web browsers. As such, JavaScript que ...

  2. 软件测试测试用例编写_不要先编写所有软件测试-只需编写一个

    软件测试测试用例编写 Test Driven Development (TDD) is sometimes described as "writing tests first". ...

  3. python学号怎么编写_用python编写学生管理系统

    #该程序在设计返回值时用了flag(标志)和i(标识下标): #之前在travers()函数的编写中for循环中缺少一个return导致在传递参数时会有错误: # 主要体现在修改和删除首个元素时!值得 ...

  4. 单元测试编写_为什么要编写单元测试-测试技巧8

    单元测试编写 我对最近的博客"您应该测试什么"有很多React,有些人出于各种原因与我达成一致,另一些人则认为建议某些类可能不需要单元测试是完全危险的. 已经处理了什么测试,今天的 ...

  5. python hello world程序编写_用Python编写一个简单程序

    按照软件行业传统习惯,当你学习一种新的编程语言如Python时,首先编写一个"Hello World! "程序. 请执行以下步骤,以创造你的"Hello World!&q ...

  6. pythonmacd指标编写_利用python编写macd、kdj、rsi、ma等指标 -

    # -*- coding: utf-8 -*- \ Created on Thu Dec 15 13:57:32 2016 @author: four \ import pandas as pd #获 ...

  7. 战神4 幕后花絮 概念艺术_幕后花絮介绍了锻炼技巧,以提高编码技能

    战神4 幕后花絮 概念艺术 在我们最近的文章中 ,我们讨论了Exercism,这是一个开放源代码项目,旨在通过数十种不同编程语言的练习来帮助人们提高其编程技能. 从业人员完成每项练习,然后收到有关其响 ...

  8. python cs开发框架_我的第一个python web开发框架(24)——系统重构与ORM

    小白弄完代码版本管理和接口文档后,兴奋的找到老菜. 小白:老大,我已经按你讲的要求,将代码版本管理和接口文档都搞好了.从项目开始到现在,除了代码编写,感觉学会好多东西啊. 老菜:嗯嗯,实战确实需要掌握 ...

  9. python定制框架知识点_我的第一个python web开发框架(25)——定制ORM(一)

    在开始编写ORM模块之前,我们需要先对db_helper进行重构,因为ORM最终生成的sql是需要转给db_helper来执行的,所以拥有一个功能完善.健壮的数据库操作类是非常必要的. 这是项目原db ...

最新文章

  1. C++中public protected private关键字
  2. Outlook中自定义新邮件提醒
  3. LOJ #6669 Nauuo and Binary Tree (交互题、树链剖分)
  4. boost::icl模块实现测试 shell 来分割区间图
  5. 安装VMware Tools 灰色解决办法
  6. 在 WSL Ubuntu 上使用 .NET 进行跨平台开发新手入门
  7. 判断一个字符串是否另一个字符串的右移后的
  8. react 布局容器_如何使用容器模式开发React超能力
  9. 常用的分布式唯一ID生成方案
  10. 解刨一台计算机,解剖一台计算机.doc
  11. java虚拟机的内存_Java虚拟机的内存结构
  12. 出现梯度消失与梯度爆炸的原因以及解决方案
  13. Security log is full,only administrator can log on to fix the problem(安全日志满了)
  14. 与7无关的数(前缀和)
  15. Atitit 项目管理之道 attilax著
  16. 怎么复制豆丁网的文字
  17. 全网最详细官网一键换肤教程
  18. ug初始化错误未能创建服务器,UG10.0提示初始化错误-15的处理操作方法
  19. 黄金面试技巧|应届生求职必备
  20. 关于tkinter.Canvas 不显示图片的问题

热门文章

  1. LinkQueue的基本创建
  2. 30005 rust_Steam三连冠老游戏《腐蚀(RUST)》为什么突然火起来了?
  3. a标签怎么传参_jsp页面中怎么利用a标签的href进行传递参数以及需要注意的地方...
  4. synchronized底层原理_你用过synchronized吗?它的底层原理是什么?Java经典面试题来了...
  5. UIView Animation
  6. 20175203 2018-2019 实验五《网络编程与安全》
  7. 深入浅出开源性能测试工具 Locust (使用篇 1)
  8. 优先发展智慧旅游与智慧交通领域
  9. compass安装使用960 Grid System
  10. 什么是三层交换机、网关、DNS、子网掩码、MAC地址