JavaScript 的那些坑

Ecmascript

  1. 大括号的位置

    function f() {
      return
      {
        h:'Hello World'
      }
    }
    console.log(f())  //undefined
    

    Javascript自动在return语句后面添加了分号结束该行,所以该函数返回的是undefined
    相当于执行了下面的语句

    function f() {
      return ;
      {
        h:'Hello World'
      }
    }
    console.log(f())  //undefined
    
  2. 语句合并造成的坑

    function g() {
      var a = b = 0;
    }
    
    g()
    
    console.log(a)  //Type Error: a is not defined
    console.log(b)  // 0
    

    上面的语var a = b = 0, 你以为的解析为 var a = 0; var b = a; 实际上解析为
    b = 0; var a = b; 所以b是一个全局变量, 挂载到全局对象上, a是一个局部对象,在函数外部无法访问.

  3. 变量提升

    • 局部变量提升, 只提升声明
    if (!o) {
        var o = {a:1};
        console.log(o);
    }// 变量的声明被提升
    // 实际上解析成这样
    var o;
    if (!o) {
      o = {a:1};
      console.log(o)
    }
    
    • 下面的代码会报 f is not a function
    if (false) {
      function f() {
        console.log("Hello World")
      }
    }
    f()  // 报错
    
    • 变量提升和函数提升
    var myname = "";
    console.log(typeof myname) // string
    
    function myname() {}
    console.log(typeof myname)  //string
    
    • 不会被条件判断所控制
    foo(); // TypeError: foo is not a function()
    var a = true;
    if (a) {
        function foo() {console.log("a")}
    } else {
        function foo() {console.log("b")}
    }
    
    // 这种情况下打印出 undefined
    console.log(typeof foo)
    var a = true;
    if (a) {
        function foo() {console.log("a")}
    } else {
        function foo() {console.log("b")}
    }
    
  4. 分号坑

    var a = 1
    (function() {
      console.log(a)
    })()
    

    以为会安全的打印a的值,实际上报错,如果下一行的第一个字元(token)是下面这五个字符之一,Javascript将不对上一行句尾添加分号:"("、"["、"/"、"+"和"-"。

  5. 内存泄漏的识别方法
    怎样可以观察到内存泄漏呢?

    经验法则是,如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。这就要求实时查看内存占用。

  6. setTimeout与this

    //setTimeout中的函数所处在于全局作用域中,所以函数中使用this关键字时,这个this关键字指向的是全局对象(Window): 
    var Value1 = 200;
    var Value2 = 20;
    var myObj = {
        Value1 : 10,
        Value2 : 1,
        caleculatedIt: function(){
            setTimeout(function(){
                console.log(this.Value1 * this.Value2);
                
            }, 1000);
        }
    }
    myObj.caleculatedIt(); //4000
    
  7. typeof的坑

    • typeof 查看变量的类型
    typeof null //"object"
    typeof NaN  // "number"
    typeof eval // "function"
    
    // 判断Class的类型: 
    ({}).toString.call(classA);
    
    • instanceof
      • 适合自定义对象
      • 也可以检测原生对象, 但在iframe和window检测失效
  8. NaN判断

    • parseInt("abc") === NaN // NaN与任何值比较都为false, 即使NaN==NaN也是false

    • 正确的判断方式

      var b = isNaN(parseInt(abc))
      
  9. 类型转换

    • parseInt和Number

      var num = parseInt(str);  //会提取其中的数字
          //str="abc"           //NaN(not a number)
          //str = "abc 12 bc"   //NaN
          //str = "123px"       //123 从最左边提取
      
      var num = Number("123");
      var num = Number("123abc"); //NaN, 比Number严格转换
      
      
    • 隐式转换 隐式转换坑

      var a = 12, b = "12";
          alert(a==b) //返回true b字符串转成数字, 但是typeof b仍然是string
      
      
      alert('12' - '7')  // 5  两边都转成数字后计算
      alert('12' + '7')  // '127' 字符串串联
      alert(12 + '7')  // '127' 数字转字符串
      // 总结: 减法,乘法,除,取余,大于小于等操作都转成Number类型
      
      
  10. 构造器中的this

    function c()
    {
        this.a = 37;
        return {a:38};
    }
    
    o= new c();
    console.log(o.a); //38 o为返回的对象 如果返回的是基本类型 那么就返回this
    
    
    function d()
    {
        this.e = 37;
        return {f:38};
    }
    o1 = new d()
    console.log(o1.e) // undefined   o1对象中只有f属性 没有e属性
    
    
  11. 严格模式下, arguments跟踪问题

    // 两次都是1
    (function fn(a) {
      'use strict';
      console.log(arguments[0]);
      a = 2;
      console.log(arguments[0]);
    })(1);
    // 两次打印的都是1, 如果实在非严格模式下, 打印的是1,2
    
  12. 实参和形参

    var add = function (a,b) {
      console.log(arguments.length);//3,表示实参长度
      console.log(arguments.callee.length);//2,表示形参长度
    };
    
    add(1,2,3);
    

JavaScript操作DOM的坑

  1. 获取鼠标点击的位置 (即鼠标点击的位置距离document左上角的位置)

Firefox,Chrome、Safari和IE9都是通过非标准事件的pageX和pageY属性来获取web页面的鼠标位置的。

function mouseClick(event) {
    event = event || window.event;
    var x = 0, y = 0;
    if (event.pageX) {
        x = event.pageX;
        y = event.pageY;
    } else if(event.clientX){
        var scrollLeft, scrollTop
        if (document.documentElement.scrollLeft) {
            scrollLeft = document.documentElement.scrollLeft
            scrollTop = document.documentElement.scrollTop
        } else if (document.body.scrollLeft) {
            scrollLeft = document.body.scrollLeft
            scrollTop = document.body.scrollTop
        }
        x = event.clientX + scrollLeft
        y = event.clientY + scrollTop
    }
    
    return {
        x,
        y
    }
}
  • scrollLeft, scrollTop 为滚动轴卷起的左侧距离和顶部距离, 即滑动轴滚动的距离
  • clientX, clientY 为鼠标点击的位置距离浏览器可视区域左上边角的距离, 与有无滚动轴无关
    image
  1. offsetLeft和style.left区别

    • style.left返回的是字符串,比如10px。而offsetLeft返回的是数值,比如数值10
    • style.left是可读写的,offsetLeft是只读的
    • style.left的值需要事先定义(在样式表中定义无效,只能取到在html中定义的值),否则取到的值是空的
  2. getComputedStyle 和 elment.currentStyle

    • getComputedStyle(obj, false) 是支持w3c(FF12、chrome14、safari):在FF新版本中只需要第一个参数,即操作对象,第二个参数写“false”也是大家通用的写法,目的是为了兼容老版本的火狐浏览器。缺点:在标准浏览器中正常,但在IE6/7/8中不支持
    • 在IE6,7,8中,并不支持getComputedStyle,IE提供了currentStyle属性
    var oDiv=document.getElementById('div1');
    if(oDiv.currentStyle){ // IE6,7,8
        alert(oDiv.currentStyle.width);
    }else{// IE9+ FF Chrome Opera
        alert(getComputedStyle(oDiv).width);
    }
    
  3. 事件监听和默认时间, 冒泡处理

    • addListener|removeListener, preventDefault(), stopBubble(): IE9+ FF Chrome Opera w3c
    • attachEvent|detachEvent, returnValue=true, cancelBubblue=true, cancel: IE6,7,8
    function listenEvent(target,type,handler){
        if(target.addEventListener){//w3c
            target.addEventListener(type,handler,false);
        }else if(target.attachEvent){//IE
            type = "on" + type;
            target.attachEvent(type,handler);//IE
        }else{
            target["on" + type] = handler;
        }
    }
    
    //取消事件
    function cancelEvent(e){
        if(e.preventDefault){
            e.preventDefault();//w3c
        }else{
            e.returnValue = false;//IE
        }
    }
    //取消传递
    function cancelPropagation(e){
        if(e.stopPropagation){
            e.stopPropagation();//w3c
        }else{
            e.cancelBubble = true;//IE
        }
    }
    
  4. 获取浏览器窗口尺寸

    function size(){
        var w = 0, h=0;
         // IE6, 7, 8
        if(!window.innerWidth){
            w = (document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth);
    
            h = (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight);
        }
        // IE9+ FF Chrome Opera W3C 
        else{
            w = window.innerWidth;
            h = window.innerHeight;
        }
        return {width:w,height:h};
    }
    
    //实用的 JavaScript 方案(涵盖所有浏览器):
    
    var w=window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    
    var h=window.innerHeight || document.documentElement.clientHeight|| document.body.clientHeight;
    

    Document对象的body属性对应HTML文档的<body>标签。
    Document对象的documentElement属性则表示 HTML文档的根节点。

  5. attributes属性

    attributes 属性返回该节点的属性节点集合。

    document.getElementById('box').attributes//NamedNodeMap
    document.getElementById('box').attributes.length;//返回属性节点个数
    document.getElementById('box').attributes[0]; //Attr,返回第一个属性节点
    document.getElementById('box').attributes[0].nodeType; //2,节点类型
    document.getElementById('box').attributes[0].nodeValue; //属性值
    document.getElementById('box').attributes['id']; //Attr,返回属性为 id 的节点
    document.getElementById('box').attributes.getNamedItem('id'); //Attr
    
    • setAttribute(attrName, value) 不建议使用设置class和style
      • setAttribute('class', 'container') for FF
      • setAttribute('className', 'conatainer') forIE, IE不认识class
    • getAtribute(attrName) 统一获取自定义属性
    • removeAttrite(attrName)
  6. 获取目标对象

    //跨浏览器获取目标对象
    function getTarget(ev){
        var ev = ev || window.event
        if(ev.target){ //w3c IE9+
            return ev.target;
        }else if(window.event.srcElement){//IE6, 7, 8
            return window.event.srcElement;
        }
    }
    
    target = event.target ?  event.target: event.srcElement;
    
  7. Node接口

    特性/方法 类型/返回类型 说明
    nodeName String 节点的名称, 节点类型而定义
    nodeValue String 节点的值 文本节点返回文本
    nodeType Number 节点类型常量值 元素0 属性1 文本2
    childNodes NodeList 所有子节点列表(包括元素节点和文本节点)
    firstNode Node childNodes列表中的第一个节点
    lastNode Node childNodes列表中的最后一个节点
    children NodeList 子节点列表中只返回元素节点
    previouSibling Node 上一同级节点
    nextSibling Node 下一同级节点
    hasChildNodes() Boolean 是否拥有子节点
    attributes NamedNodeMap 返回属性NamedNodeMap
    appendChild(Node) Node 节点添加到childNodes末尾
    removeChild(Node) Node 从childNodes中删除node
    replaceNode(new, old) Node 将childNodes中的old替换成new
    insertBefore Node 在已有子节点之前插入新子节点
    • 返回父节点: node.parentNode || node.parentElement (IE)
    • 返回子文本节点集合:node.textNodes
    • 节点信息
      • 是否包含某节点:node.contains()
      • 是否有子节点node.hasChildNodes()
    • 创建新节点
      • createDocumentFragment() -创建文档碎片节点
      • createElement(tagname) -创建标签名为tagname的元素
      • createTextNode(text) -创建包含文本text的文本节点
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341

推荐阅读更多精彩内容

  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,710评论 2 17
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,046评论 1 10
  • 转载请声明出处 博客原文 随手翻阅以前的学习笔记,顺便整理一下放在这里,方便自己复习,也希望你有也有帮助吧 第一课...
    程序员poetry阅读 12,636评论 13 94
  • 转载请著名出处 GitHub-TYRMars 文章Github地址 JavaScript基础知识剖析 01 01-...
    TYRMars阅读 551评论 0 7
  • 1 天还没亮吗?我从昏迷中睁开眼,但见头顶的灯光白惨惨的,我怕再也见不到太阳了吧? 老公趴在床沿上,紧紧攥着我的手...
    有故事的牛魔王阅读 620评论 5 4