资讯专栏INFORMATION COLUMN

代码艺术家之JS

quietin / 1662人阅读

摘要:大话先给大家意淫一下前端的目前的应该是工业革命时代了。即在每个变量名前加上一个或多个字符表示相应的类型。这对于大型查找是非常有好处的。当然,一般的技术人员也不会手贱写这么麻烦的。由于是弱类型的,所以可以直接使用或者进行连续赋值。

大话js

先给大家意淫一下前端的futrue.
目前的JS应该是工业革命时代了。以前js就只是作为什么移动一下图片,更换一下背景颜色等, 比较废的活. 但是现在h5,nodeJS,ECMA-6,gulp,grunt,webpack,react...等等各种框架,工具的出现,基本上颠覆了js的角色。以前js就是作为一个配角,html+CSS才是主要的,现在,你说你写网页的不会用js,呵呵,U ~= 渣渣. 而且庸俗一点来说,现在前端的薪资range应该是其他技术类职业变化最大的,年薪2w+ 到 200w+ 的都有。所以js对于前端来说莫过于一块金子招牌,如果你js真的吃透了,相信你的路真的是太宽了~
意淫完毕,该谈正事了,JS最佳实践应该是很多地方都会提到的。我这里引用的是高级程序设计里面的内容,如有出错的地方,欢迎纠正.

类型注释

由于js是一门弱类型的语言,所以往往造成了类型的不清楚,有可能胡乱使用不同类型上的方法,导致出错。
所以,一般给js的变量加上一些类型注释是很有好处的。 通常我们会缺少加注释的动力,这样想吧,如果未来的某一天,你需要接手别人的项目的时候,而别人的项目里面一条注释也没有,你的想不想死。。。所以, 有因才有果,一个良好的注释真的很有用.

</>复制代码

  1. var found = "s"; //"string"
  2. var abc = true; //boolean

这应该算是一种简单的吧
还有一种是匈牙利标记法。即在每个变量名前加上一个或多个字符表示相应的类型。
通常,"o"为对象,"s"为string,"b"为Boolean,"i"表示整数,"a"表示数组等

</>复制代码

  1. var sName ="string";

但是由于看起来很丑,推荐只在函数参数里面使用就足够了。

算法的复杂度

这也是面试时候会常常问到的。

flag name description
O(1) 常数 表示不管有多少值,执行的时间都是很定的。表示简单值和存储在变量中的值
O(log n) 对数 总的执行时间和值的数量相关,但完成算法不一定获取每一个值,比如二分查找
O(n) 线性 执行时间和值的数量直接相关.ex: 遍历数组
O(n^2) 平方 总执行时间和数量有关,每个值要获取n次。ex: 插入排序

一个一个解释:

O(1)

表示你无论有多少值,获取常量值的时间都一样。

</>复制代码

  1. var value = 5;
  2. var num = value + 4;
  3. console.log(num);

上面的复杂度整体为1,因为这只是简单的变量查找。 O(1)的操作还有,数组的读取

</>复制代码

  1. var value = [1,2,3,4,5];
  2. console.log(value[1]); //2

同样也是1,不管你是多少次查找都一样。
所以说算法复杂度为O(1)的情况:只有在获取变量以及数组的时候

O(n)

最常用的是在你进行属性查找的时候。因为查找属性的时候,会遍历所有的对象上的属性,然后才返回。所以他的复杂度为O(n).

</>复制代码

  1. var obj = {
  2. name:"jimmy",
  3. age:19
  4. };
  5. console.log(obj.name);

上面访问obj.name的属性的复杂度为O(n).还有一个例子:

</>复制代码

  1. var name = window.location.href.substring(window.location.href.indexOf("."));

可以数一下,上面算法的复杂度为6个O(n)因为存在了6个"."进行属性访问。这种情况下,可以优化一下,使用变量进行保存,要知道变量始终是O(1)的

</>复制代码

  1. var href = window.location.href;
  2. var name = href.substring(href.indexOf("."));

上面就缩减到了4次".",节约了33%的查询成本。 这对于大型查找是非常有好处的。但是如果你只是一次两次的查找,则使用变量和未使用变量是没有差别的。
另外对于变量的复杂度和属性的复杂度,一般来说,如果可以使用arr[xxx]形式的遍历的话,最好使用。

</>复制代码

  1. //jquery对象---$val
  2. for(var i = 0;i<$val.length;i++){
  3. $val.eq(i).html(); //输出innerHTML
  4. }
  5. //优化过后
  6. for(var i in $val){
  7. $val[i].innerHTML; //输出的innerHTML
  8. }

-----------分割线----------
这里感谢@Dreamacro 童鞋的提醒。这里特此说明一下,在V8里面引擎对于对象属性的查找其实是O(1)的操作。
(Ps:我操,你到底再说什么鬼)
其实在V8里面对于对象属性的存储同样是散列hash,但是V8就是快,为了实现向java一样的遍历速度,于是做了一点改动。在你每次新建属性的时候,V8会使用hidden class,新建一份原来对象的Copy并且添加上新属性。于是在你下次查找属性的时候他都会直接从这个新建的Class info寻找。 如果你一不小心手贱使用了delete的话,你查找的复杂度便会退化为O(n).
参考: hidden Class, V8引擎对象优化

关于O(log n)和 O(n^2),由于目前对算法不精通,还是别误导人了。

循环优化

一个常见的循环

</>复制代码

  1. for(var i= 0 ;i
  2. 这个循环可以,但是不是很高效,因为每一次循环你都会去调用一次nodelist.length这个值,造成了 nodelist.length * O(n)这样一个复杂度. 优化的办法就是将length提出去

  3. </>复制代码

    1. for(var i= 0,len = nodelist.length;i
    2. 上面的循环的复杂度就变为1O(1) + 1O(n); 当然上面那种简单而且更高效.
      但是试想一下,如果你在循环体还需要使用nodelist[i]

    3. </>复制代码

      1. for(var i= 0,len = nodelist.length;i
      2. 想一想,nodelist[i]乍看起来并不是循环体内所需要的。那我们应该怎么做呢?
        很简单,利用nullfalse的条件自动转换

      3. </>复制代码

        1. for(var i = 0,node; node = nodelist[i++];){
        2. node...
        3. }
        4. //当然你也可以直接使用
        5. for(var node of nodelit){ //这种方式更加方便简洁,但是是es6的一个新特性
        6. node
        7. ...
        8. }
      4. 另外循坏可以通过以下几个点来进行优化

      5. </>复制代码

        1. 1.减值迭代

        2. </>复制代码

          1. 2.简化终止条件
          2. 3.简化循环体
          3. 4.使用后测试循环--forwhile都是前测试循环, do-while是后测试循环
      6. 减值迭代
        : 从最大值开始减值,而不是从最小值减值迭代。

      7. 简化终止条件
        : 即就是想上面例子一样,对终止条件寄存在变量当中.

      8. 简化循环体
        : 这应该是一个复杂的活,简单的就是把不需要参与循环的语句提出来

      9. 使用后测试
        : 这其实就是防止对空值进行循环

      10. </>复制代码

        1. var len = nodelist.length,
        2. i = 0;
        3. if(len>0){
        4. do{
        5. ...
        6. }while(++i===len);
        7. }
      11. 这一部分可以参考一下Naraku_的读书笔记。
        还有一个例子,是我在腾讯面试的时候遇到的。

      12. </>复制代码

        1. 从一篇全英文的文章中找到频率次数最高的单词

      13. 这里是我写的一部分代码,可以看一看
        筛选单词

      14. Duff优化
      15. 每次看的时候,都会被他的精髓刺瞎了我24K金钛合金*眼.
        将循环次数展开书写
        这是Andrew B.King 写出的一个比较著名的Duff装置.将do-while分成两个多带带的循环。简单易懂。

      16. </>复制代码

        1. var iter = Math.floor(values.length/8);
        2. var leftover = values.length%8;
        3. var i = 0;
        4. if(leftover>0){
        5. do{
        6. process(values[i++]);
        7. }while(--leftover>0);
        8. }
        9. do {
        10. process(values[i++]); //8次处理
        11. process(values[i++]);
        12. process(values[i++]);
        13. process(values[i++]);
        14. process(values[i++]);
        15. process(values[i++]);
        16. process(values[i++]);
        17. process(values[i++]);
        18. }while(--iter>0);
      17. 感觉比一般的for循环更加复杂,没错。Duff一般是用来处理比较多的循环次数的时候才会真正显示他的效率。如果你使用的循环次数就50+。那使用for效率会更高一点. 通常我们前端也用不到,因为TM这是给后端用的。

      18. 避免双重解释
      19. 这种情况一般只会发生在3种情况下, 即使用eval,Function,setTimeout里面.

      20. </>复制代码

        1. eval("alert("hehe")");
        2. var sayHi = new Function("alert("hehe")");
        3. setTimeout("alert("hehe")",500);
      21. 以上3中会发生双重解释,原因是,原本的js解析器不能直接解析上面的string字符串,需要额外新开一个解析器来进行解释,导致的结果就是速度被拖屎了。 当然,一般的技术人员也不会手贱写这么麻烦的。
        修改

      22. </>复制代码

        1. alert("hehe");
        2. var sayHi = function(){alert("hehe")}
        3. setTimeout(function(){alert("hehe")},500);
      23. 这样写就没什么问题了。

      24. 最小化语句
      25. 即就是整合语句了。由于js是弱类型的,所以可以直接使用var或者let进行连续赋值。而且这也是JIT编译器帮你干的事.(JIT是一种能让你代码越运行越快的编译器)

      26. </>复制代码

        1. //用了5条语句声明5个变量
        2. var count = 5;
        3. var color = "red";
        4. var values = [1,2,3];
        5. var now = new Date();
        6. //用了1条语句声明5个变量,注意每个变量用逗号隔开
        7. var count = 5,
        8. color = "red",
        9. values = [1,2,3],
        10. now = new Date();
      27. 还有就是使用数组和对象字面量
        : 因为语句量减少,解析器的压力也减小了

      28. </>复制代码

        1. // 创建两个对象 ----不好的方式
        2. //one 四条语句
        3. var values = new Array();
        4. values[0] = 123;
        5. values[1] = 456;
        6. values[2] = 789;
        7. //two 四条语句
        8. var person = new Object();
        9. person.name = "jozo";
        10. person.age = 21;
        11. person.sayName = function(){
        12. alert(this.name);
        13. };
        14. // 创建两个对象 ----推荐的方式
        15. //one 1条语句
        16. var values = [123,456,789]
        17. //two 1条语句
        18. var person = {
        19. name : "jozo",
        20. age : 21,
        21. sayName : function(){
        22. alert(this.name);
        23. };
      29. 总的来说, js优化之路漫漫,没有年年月月的积累,是不可能达到什么特别高的level的。所以说,活到老学到老,这是永恒的真理~~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78421.html

相关文章

  • 我的阿里路+Java面经考点

    摘要:我的是忙碌的一年,从年初备战实习春招,年三十都在死磕源码,三月份经历了阿里五次面试,四月顺利收到实习。因为我心理很清楚,我的目标是阿里。所以在收到阿里之后的那晚,我重新规划了接下来的学习计划,将我的短期目标更新成拿下阿里转正。 我的2017是忙碌的一年,从年初备战实习春招,年三十都在死磕JDK源码,三月份经历了阿里五次面试,四月顺利收到实习offer。然后五月怀着忐忑的心情开始了蚂蚁金...

    姘搁『 评论0 收藏0
  • 《DOM编程艺术》中初步实现的图片库的总结(二)

    摘要:前言在编程艺术中初步实现的图片库的总结一中,有很多不足之处比如事件处理嵌套在中,显得如此笨重和屌丝没有对函数进行相应的安全检查等,本篇文章对上述问题做了全面的升级。 前言:在《DOM编程艺术》中初步实现的图片库的总结(一)中,有很多不足之处:比如事件处理嵌套在HTML中,显得如此笨重和屌丝;没有对showPic函数进行相应的安全检查等,本篇文章对上述问题做了全面的升级。--------...

    阿罗 评论0 收藏0
  • 用Canvas实现文本编辑器(支持艺术字渲染与动画)

    摘要:项目中文字由进行渲染。待触发时,取消中文输入标记,将文字渲染到上。而其中一些有趣的细节实现如文本渲染,对中文笔画分割实现有趣的动画等并没有描写。 导言 目前富文本编辑器的实现主要有两种技术方案:一个是利用contenteditable属性直接对html元素进行编辑,如draft.js;另一种是代理textarea + 自定义div + 模拟光标实现。对于类似word的经典富文本编辑器,...

    OldPanda 评论0 收藏0
  • 【Java并发编程的艺术】第二章读书笔记synchronized关键字

    摘要:在之前的文章中学习了关键字,可以保证变量在线程间的可见性,但他不能真正的保证线程安全。线程执行到指令时,将会尝试获取对象所对应的的所有权,即尝试获得对象的锁。从可见性上来说,线程通过持有锁的方式获取变量的最新值。 在之前的文章中学习了volatile关键字,volatile可以保证变量在线程间的可见性,但他不能真正的保证线程安全。 /** * @author cenkailun *...

    GT 评论0 收藏0
  • 开放封闭原则模式的黄金法则

    摘要:开放封闭原则应该算是这几个原则里面最容易理解的一个。另外,语句就是开放封闭原则的死敌这个是状态模式中的一个例子。处理开放封闭模式的特例我们都是人,不可能一开始都写出完美的代码。 开放-封闭原则应该算是这几个原则里面最容易理解的一个。它的宗旨就是:如果你想扩展或者改变一个程序的功能,可以增加代码,但是不能改变程序的源码。如果,是对于那些码农来说,最快捷的办法就是改变源码,但是我们面向的是...

    MasonEast 评论0 收藏0

发表评论

0条评论

quietin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<