整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JavaScript命名冲突不可避免?


【CSDN 编者按】从1995年开始,本文作者Dr.Axel Rauschmayer就专门从事JavaScript和Web开发,已经有30多年了。2010年,他获得慕尼黑大学信息学博士学位。自2011年以来,他一直在2ality.com写博客,并写了几本关于JavaScript的书,比如《JavaScript for impatient programmers》、《Deep JavaScript: Theory and techniques》等。今天这篇文章就来自于他的博客,介绍了在JavaScript命名冲突时,现有代码如何强制对提议的功能进行重命名。

整理 | 章雨铭 责编 | 张红月
出品 | CSDN(ID:CSDNnews)

不断发展的JavaScript:不要破坏web!


JavaScript的一个发展核心原则就是"不要破坏Web":在将新特性添加到语言中后,所有现有代码都必须能够继续运行。

这样有一个坏处,就是不能从语言中删除现有的quirks。但这样做益处多多,比如旧的代码可以继续运行,而且升级到新的ECMAScript版本很简便等等。

在为新特征(如方法名称)选择名称时,需要进行一个重要的测试,即在浏览器的nightly版本(早期预发布版本)中添加该特征,并检查是否有任何网站出现错误。

接下来将介绍过去案例中的的四个冲突源,当产生这四种冲突时,就必须重命名特征。


冲突源1:向内置原型添加方法


在JavaScript中,我们可以通过改变其原型来为内置值添加方法:

  • // Creating a new Array methodArray.prototype.myArrayMethod = function () { return this.join('-');};assert.equal( ['a', 'b', 'c'].myArrayMethod(), 'a-b-c');

    // Creating a new string methodString.prototype.myStringMethod = function () { return '¡' + this + '!';};assert.equal( 'Hola'.myStringMethod(), '¡Hola!');

    神奇的是,语言可以通过这种方式改变。这种运行时的修改被称为猴子补丁(monkey patch)。

    什么是猴子补丁?

    如果我们给内置原型添加方法,我们就是在运行时修改一个软件系统。这样的修改被称为猴子补丁。简单来说,对其含义有两种可能的解释。

    这个叫法起源于Zope框架,人们在修正Zope的Bug的时候经常在程序后面追加更新部分,这些被称作是“杂牌军补丁(guerilla patch)”,后来guerilla就渐渐的写成了gorllia((猩猩),再后来就写了monkey(猴子),所以猴子补丁的叫法是这么莫名其妙的得来的。

    另一种说法是,它指的是搞乱(monkeying about)代码。

    反对改变内置原型的原因

    对任何类型的全局命名,都会存在名称冲突的风险。如果有解决冲突的机制,就能规避风险。例如:

    • 全局模块是通过裸模块指定器或URLs来识别的。前者之间的名称冲突可以通过npm注册表来解决。后者之间的名称冲突可以通过域名注册处来解决。

    • 可以通过将符号添加到JavaScript中,以避免方法之间的名称冲突。例如,任何对象都可以通过添加一个键为.NET的方法而成为可迭代的。由于每个符号都是唯一的,所以这个键永远不会与任何其他属性键.Symbol.iterator发生冲突。

    然而,带有字符串键的方法会导致名称冲突:

    • 不同的库可能会对他们添加到.Array.prototype的方法使用相同的名字。

    • 如果一个名字已经被某个库使用了,那么这个名称就不能用于命名JavaScript标准库的一个新特性。

    具有讽刺意味的是,谨慎地添加一个方法可能会适得其反:

    • if (!Array.prototype.libraryMethod) { Array.prototype.libraryMethod = function () { /*...*/ };}

      我们会检查一个方法是否已经存在。如果没有,我们就添加它。

      如果我们要实现一个polyfill(模拟原生Web平台功能),将新的JavaScript方法添加到不支持它的引擎中,那么这个技术就能发挥作用。(顺便说一下,这是修改内置原型的一个合法用例。也许是唯一的一个)。

      然而,如果我们对一个普通库的方法使用这种技术,然后JavaScript获取具有相同名称的方法,那么这两种实现的工作方式就不一样了,并且使用库方法的所有代码在使用内置方法时都会中断。

      必须更改名称的原型方法示例

      • ES6的方法最初是与JavaScript框架MooTools(错误报告.String.prototype.includes().contains()全局添加的方法相冲突。

      • ES2016的方法最初是与MooTools(错误报告 ).Array.prototype.includes().contains()添加的方法相冲突。

      • ES2019的方法最初是和MooTools(错误报告 博客文章).Array.prototype.flat().flatten()相冲突。

      修改内置原型并不总是糟糕的

      你可能会对MooTools的创建者粗心大意感到疑惑。但是,向内置原型添加方法并不总是糟糕的。在ES3(1999年12月)和ES5(2009年12月)之间,JavaScript是一种停滞不前的语言。MooTools和Prototype等框架改进了它。这些方法的缺点只有在JavaScript的标准库再次增加之后才会凸显出来。


      冲突源2:检查一个属性的存在

      ES2022的方法最初是.NET的。因为以下库检查属性以确定对象是否是一个HTML集合(而不是一个数组),所以它必须被重新命名:Magic360YUI 2YUI 3.Array.prototype.at().item().item

      冲突源3:检查全局变量是否存在

      自ES2020以来,我们可以通过globalThis访问全局对象。Node.js一直使用该名称来实现此目的。最初的计划是为所有平台标准化该名称.global

      然而,以下模式经常被用来确定当前平台:

      • if (typeof global !== 'undefined') { // We are not running on Node.js}

        如果浏览器也有一个名为.global的全局变量,这种模式(以及类似的模式)就会失效。因此,标准化的名称被改为.globalglobalThis



        冲突源4:通过创建局部变量with语句
        JavaScript的声明with语句

        长期以来,人们一直不鼓励使用JavaScript的with语句,甚至在ES5中引入的严格模式中也被定为非法。在其他地方,严格模式在ECMAScript模块中是活跃的。

        该语句将一个对象的属性变成局部变量:with

        • cons t myObject = { ownProperty: 'yes',};

          with (myObject) { // Own properties become local variables assert.equal( ownProperty, 'yes' );

          // Inherited properties become local variables, too assert.equal( typeof toString, 'function' );}

          由with语句引起的冲突

          框架Ext.js使用的代码与下面的片段有些相似点:

          • function myFunc(values) { with (values) { console.log(values); // (A) }}myFunc([]); // (B)

            当ES6方法被添加到JavaScript中时,如果用Array(B行)来调用它,它就会失效。该语句将Array的所有属性变成了局部变量。其中一个是继承的属性。因此,A行中的语句已记录,不再是参数(错误报告1错误报告2

            Array.prototype.values()myFunc()withvalues.valuesArray.prototype.valuesvalue


            Unscopables:防止with导致的冲突

            公共符号Symbol.unscopables允许对象隐藏语句中的某些属性。它只在标准库中使用一次,对于Array.prototype:with

            • assert.deepEqual( Array.prototype[Symbol.unscopables], { __proto__: , at: true, copyWithin: true, entries: true, fill: true, find: true, findIndex: true, flat: true, flatMap: true, includes: true, keys: true, values: true, });


              结论

              以上提出了JavaScript结构与现有代码发生名称冲突的四种方式:

              • 向内置原型添加方法

              • 检查属性是否存在

              • 检查全局变量是否存在

              • 创建局部变量with

              冲突的某些来源很难预测,但存在以下一些一般规则:

              • 不要更改全局数据。

              • 避免检查是否存在全局数据。

              • 请注意,内置值将来可能会获得其他属性(自己的或继承的属性)。

              对于库来说,为JavaScript值提供功能的最安全方法是通过函数。如果JavaScript得到一个pipe operator,我们也可以像方法一样使用它们。

              参考资料:https://2ality.com/2022/03/naming-conflicts.html

              END

              《新程序员001-004》全面上市,对话世界级大师,报道中国IT行业创新创造

签属性命名规范

下划线连接符命名法“hello_world”

中杠 连接符命名法“hello-world”

骆驼式命名法“helloWorld”


  内容:content/container 导航:nav 侧栏:sidebar    
  栏目:column 标志:logo 页面主体:main   
  广告:banner 热点:hot 新闻:news
  下载:download 子导航:subnav 菜单:menu
  搜索:search 页脚:footer 滚动:scroll
  版权:copyright 友情链接:friendlink 子菜单:submenu
  内容:content 标签页:tab 文章列表:list
  注册:regsiter 提示信息:msg 小技巧:tips
  加入:joinus 栏目标题:title 指南:guild
  服务:service 状态:status 投票:vote
   尾:footer 合作伙伴:partner 登录条:loginbar
  页面外围控制整体布局宽度:wrapper 左右中:left right center   
  
  
(二)注释的写法:
  /* Footer */
  内容区
  /* End Footer */
  
  
(三)id(具有唯一性)的命名:
  
  
(1)页面结构
  容器: container 页头:header 内容:content/container
  页面主体:main 页尾:footer 导航:nav
  侧栏:sidebar 栏目:column 左右中:left right center
  页面外围控制整体布局宽度:wrapper
  
(2)导航
  导航:nav
  主导航:mainbav
  子导航:subnav
  顶导航:topnav
  边导航:sidebar
  左导航:leftsidebar
  右导航:rightsidebar
  菜单:menu 子菜单:submenu 标题: title 摘要: summary
  
  
(3)功能
  标志:logo
  广告:banner
  登陆:login
  登录条:loginbar
  注册:regsiter
  搜索:search
  功能区:shop
  标题:title
  加入:joinus
  状态:status
  按钮:btn
  滚动:scroll
  标签页:tab
  文章列表:list
  提示信息:msg
  当前的: current
  小技巧:tips
  图标: icon
  注释:note
  指南:guild
  服务:service
  热点:hot
  新闻:news
  下载:download
  投票:vote
  合作伙伴:partner
  友情链接:link
  版权:copyright
  
  
(四)class的命名:
  (1)颜色:使用颜色的名称或者16进制代码,如
  .red { color: red; }
  .f60 { color: #f60; }
  .ff8600 { color: #ff8600; }
  (2)字体大小,直接使用"font+字体大小"作为名称,如
  .font12px { font-size: 12px; }
  .font9pt {font-size: 9pt; }
  (3)对齐样式,使用对齐目标的英文名称,如
  .left { float:left; }
  .bottom { float:bottom; }
  (4)标题栏样式,使用"类别+功能"的方式命名,如
  .barnews { }
  .barproduct { }
  
  
注意事项:
  1.一律小写;
  2.尽量用英文;
  3.不加中杠和下划线;
(我倒是经常加)
  4.尽量不缩写,除非一看就明白的单词.
(偷懒经常缩写)
  主要的 master.css 模块 module.css 基本共用 base.css
  主题 themes.css 专栏 columns.css 打印 print.css
  文字 font.css 表单 forms.css 补丁 mend.css
  布局,版面 layout.css

用table布局和表单元素编写一个注册页面

1)注册页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>注册登录页面</title>
</head>
<body>
    <form action="http://www.bd.com/register.aspx" method="get">
        <table cellpadding="5" cellspacing="0" width="380" height="300">
            <tr>
                <td>用户名:</td>
                <td><input name="txtName" /></td>
            </tr>
            <tr>
                <td>密 码:</td>
                <td><input type="password" name="txtPwd" /></td>
            </tr>
            <tr>
                <td>选择省:</td>
                <td>
                    <select name="SS">
                        <option value="HN" selected="selected">河南</option>
                        <option value="HB">河北</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td>性 别:</td>
                <td><input type="radio" name="rd" value="1" />男<input type="radio" name="rd" value="0" />女</td>
            </tr>
            <tr>
                <td colspan="2">
                    <fieldset>
                        <legend>兴趣爱好</legend>
                        <input name="interest" type="checkbox" value="ppq" />乒乓球
                        <input name="interest" type="checkbox" checked="checked" value="ts" />跳水
                        <input name="interest" type="checkbox" value="pq" />排球
                    </fieldset>
                </td>
            </tr>
            <tr>
                <td colspan="2" align="middle">
                    <h3>注册免责协议</h3>
                    <textarea cols="50" rows="3" readonly="readonly">  **提醒您:在使用**搜索引擎(以下简称**)前,请您务必仔细阅读并透彻理解本声明。您可以选择不使用**,但如果您使用**,您的使用行为将被视为对本声明全部内容的认可。
                            鉴于**以非人工检索方式、根据您键入的关键字自动生成到第三方网页的链接,除**注明之服务条款外,其他一切因使用**而可能遭致的意外、疏忽、侵权及其造成的损失(包括因下载被搜索链接到的第三方网站内容而感染电脑病毒),**对其概不负责,亦不承担任何法律责任。
                            任何通过使用**而搜索链接到的第三方网页均系他人制作或提供,您可能从该第三方网页上获得资讯及享用服务,**对其合法性概不负责,亦不承担任何法律责任。
                            **搜索结果根据您键入的关键字自动搜索获得并生成,不代表**赞成被搜索链接到的第三方网页上的内容或立场。
                            您应该对使用搜索引擎的结果自行承担风险。**不做任何形式的保证:不保证搜索结果满足您的要求,不保证搜索服务不中断,不保证搜索结果的安全性、正确性、及时性、合法性。因网络状况、通讯线路、第三方网站等任何原因而导致您不能正常使用**,**不承担任何法律责任。
                    </textarea>
                </td>
            </tr>
            <tr>
                <td colspan="2" align="middle">
                    <input type="submit" value="注册" />      
                    <input type="reset" />
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

action:指定提交到服务器的哪个程序处理,比如asp.net的一般处理程序等

method:提交的方式1)post隐式提交,比较安全 2)get显示提交如下图所示

select:selected="selected"与checkbox的checked="checked"表示默认选中项

textarea:rows与cols表示此文本框内容要显示的行数与列数

注册页面;网址信息自己测试