在 Web 应用程序中使用 Vanilla JS






3.45/5 (3投票s)
为 IE 和其他过时浏览器编写 JavaScript 意味着 ES6 中的类和其他有用的功能将不可用。但是,可以实现类似的效果,而且实际上很容易做到!
为什么使用 原生 JS 而不是众多可用的框架,甚至 TypeScript?如果选择已经做出,那么答案基本上无关紧要。然而,决定用其他替代品替换所有用例的 JavaScript 是一种脱离实际的绝对主义。本文将描述原生 JS 的使用,让您自己选择使用哪种语言。
类定义和命名空间
ES6 类尚未在浏览器中完全支持。本文提到的大部分限制在开发 ES5 时最为相关——例如,为 Internet Explorer 或其他过时浏览器开发。即使没有类的完全支持,在 JavaScript 中也可以实现类似的效果,而且实际上很容易做到!
我们首先要确保类定义是受限的。这意味着它不应该用方法和变量污染全局
命名空间。这可以通过使用闭包来实现——一个特殊的闭包,称为立即执行函数表达式(IIFE)。
(function (global) {
"use strict";
global.API = new MyObject();
function MyObject() {
var self = this;
... var privateVariable ...
... function privateMethod() ...
... self.publicMethod ...
}
})((1,eval)('this'));
请注意,全局命名空间已传递给 IIFE——因为它们只是方法,所以可以像这样使用它们!如果您想了解有关如何获取全局命名空间的更多信息,请查看这个发人深省的 StackOverflow 帖子:(1,eval)(‘this’) vs eval(‘this’) in JavaScript?
“严格模式”
"use strict"; //<a href="https://mdn.org.cn/en-US/docs/Web/JavaScript/Reference/Strict_mode">
//seriously, do it.</a>
类可以初始化并存储在全局范围内,例如在单个应用程序特定的命名空间内
(function (global,app,http) {
"use strict";
global[app] = global[app] || {};
global[app][http] = new Http();
// global.App.http.publicMethods()
function Http() {
var self = this;
// var privateVariables ...
// self.publicMethods = function ...
// function privateFunctions() ...
}
})((1,eval)('this'),'App','http');
我认为将客户端 JavaScript 编写成 API 更容易。利用这种设计模式可以提高代码质量和可维护性。在上面的代码中,Http
的实例被分配给全局.App
命名空间中的http
属性。当然,这里应该包含我们用于发出 HTTP 请求的方法!通过这种方式处理应用程序的客户端 JavaScript,代码组织是最好的方面之一。通常,存储的将是构造函数本身,而不是实例——这允许应用某些SOLID 原则。
构造函数
Http
函数是一种特殊的函数——一个构造函数。这意味着可以使用构造函数调用中的new
运算符创建实例。
function MyObject() {
}
var instance = new MyObject();
如果您以前创建过面向对象代码的实例,这看起来应该很熟悉。
捕获 this
this
并不总是相同的事实既是 JavaScript 的力量,也是其诅咒。Http
构造函数的第一行捕获特定上下文中的this
,以帮助克服诅咒并利用其力量。
function Http() {
var self = this;
...
}
在构造函数的作用域中,this
指的是 Http
对象。声明一个私有
变量并对其进行初始化,以捕获它并使其可供 Http
的所有公共
和私有
成员使用——无论在调用这些成员时this
是什么。只捕获一次 this
并在相应构造函数的作用域中捕获,可以减少 this
兑现其诅咒的可能性!
私有成员
在 Http
构造函数作用域中创建的变量和函数将可供 Http
对象内的所有公共
和私有
成员使用。
function Http() {
var self = this,
eventHandlers = {};
function addEventHandler(event, handler) { }
function removeEventHandler(event, handler) { }
}
在这种情况下,self
、eventHandlers
以及添加/删除事件处理函数的函数是 Http
的私有
成员。它们不对外部源开放——只有 Http
的公共
和私有
成员才能访问 Http
的私有
成员。
公共成员
暴露在 Http
对象上的属性和方法,例如原型链中存在的属性和方法,可以从外部源访问,被认为是公共
的。
function Http() {
var self = this;
self.get = function (request) { ...
self.post = function (request, data) { ...
}
在构造函数中将公共
成员添加到 self
变量。这允许其他代码执行 Http
实例的操作。
静态成员
成员也可以是静态
的。通过在构造函数本身上声明一个变量,可以为其分配一个值、实例或函数,该值、实例或函数是公共
的,同时不依赖于使用构造函数创建实例。
function Http() {
}
Http.setup = function () { ...
静态
Http
成员可以在不创建 Http
实例的情况下使用。
// ... application code doesn't create an Http instance
Http.setup();
// ... application code doesn't create an Http instance
该成员是公共
的,并且在 Http
构造函数可用的任何地方都可以使用。
执行上下文
在不深入探讨JavaScript 中的执行上下文的情况下,有几点需要注意。本节将描述几种不同的执行上下文以及 JavaScript 代码执行的集成点。
全局上下文
只有一个全局上下文——或全局作用域或全局命名空间。在函数外部定义的任何变量都存在于全局上下文中。
var x = 9;
function XManager() {
var self = this;
self.getX = function () { return x; }
self.setX = function (value) { x = value; }
}
全局作用域变量 x
在 XManager
函数外部定义,并被赋予值 9。当调用 getX
时,它将返回全局作用域的 x
(值为 9)。
局部作用域——函数执行上下文
全局作用域的替代是局部作用域。局部作用域由函数执行上下文定义。
var x = 9;
function XManager() {
var self = this,
x = 10;
...
self.getInstanceX = function () {
return x; // returns 10
}
}
在这种情况下,变量 x
被声明了两次。第一次是在全局执行上下文中。此变量在 XManager
中可访问。在 XManager
构造函数中,声明了私有
变量 x
并将其初始化为 10
。getInstanceX
方法将返回其执行上下文堆栈中最先出现的变量 x
。
getInstanceX
方法是“当前活动”,接下来是 XManager
的私有
变量 x
,然后是全局作用域变量 x
,最后是全局执行上下文。所有这些都是为了解释为什么 getInstanceX
返回 10
而不是 9
。非常强大!
let & 块级作用域
在讨论执行上下文时,我不能不提到关键字 let
。此关键字允许声明块级作用域变量。与 ES6 类一样,如果需要支持过时的浏览器,则 let
关键字将不可用。
function Start() {
let x = 9; // variable assigned to value 9
function XManager() {
let x = 10; // different variable assigned to value 10
function getX() {
console.log(x); // return 10
}
console.log(x); // return 10
getX();
}
console.log(x); // return 9
XManager();
}
Start();
块作用域变量在其上下文(Start
)及其包含的子块(XManager
)内可访问。与 var
的主要区别在于,var
的作用域是整个封闭函数。这意味着,在使用 let
时,XManager
和包含的子块(getX
)可以访问被赋值为 10 的新变量 x
,而 Start
上下文中的变量 x
仍将具有值 9
。
事件处理程序
用户通过 DOM 事件与渲染的 HTML 交互时,会触发客户端 JavaScript 代码。当触发事件时,其订阅者(事件处理程序)将被调用来处理该事件。
HTML – 事件订阅
<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>
<div id="submit">Button</div>
JAVASCRIPT – 事件订阅
var button = document.getElementById("submit");
button.addEventHandler('click', clickHandler);
JAVASCRIPT – 事件处理程序
function clickHandler() {
console.log("Click event handled!");
}
事件处理程序是用户与 HTML 的交互与 JavaScript 中的应用程序 API 之间的集成点。
编写客户端 JavaScript 时,理解如何创建对象和执行上下文非常重要。将 JavaScript 设计成 API 将有助于进一步管理该语言的优缺点。