JS趣味见闻1

日期:2015-2-28 16:51 | 标签: 趣味见闻 JS | 阅读:989

这里记录我平常使用JS时遇到的好玩的东东,当然,如果您见得多了话,也就见怪不怪了。

作用域

突然觉得function的bind用法甚是有趣,写了段代码,有兴趣可以打开控制台瞧瞧。

function outf(cb){
    setTimeout(function(){cb.haha();},1000);
}
var a={
    inf:function(){
        var a={
            haha:function(){console.log(this);}.bind(this)
        }
        outf(a);
    }
}; 
a.inf();

同时这里也提个醒,要非常注意IIFE,其有单独的作用域。

变量提升

这里就不多说了,把自己的console截图整上来了。 变量提升
这里主要考虑变量提升对函数与一般变量处理的差异,以及变量名称冲突时的处理策略,变量名称冲突我总结的如下:

  1. 一般变量参数名称与局部变量名称冲突时,该处理时再处理。
  2. 函数参数名称与局部函数名称冲突时,直接覆盖(函数参数被)。
  3. 函数参数名称与局局部变量名称冲突时,函数占优 (初始化以前)。

可参考三水清文章javascript的词法作用域

大小比较

网上众说纷纭,最终得参考标准才行:
http://www.barretlee.com/ST/ES5.1/#sec-9.1
此外,与false比较相同的值有,这货[]也在其中。

0, '0':待考量, +0, -0, false, '',undefined,null,NaN

__defineGetter__

可以定义在获取某个属性时执行某个函数,实现方式有两种

// 旧
Object.prototype.__defineGetter__('prop', function(){ // doing smething
});
// 新
Object.defineProperty(obj, 'key', { // descriptor });

参考Mozilla API :defineProperty

scrollTop

在混杂模式下,由于所有浏览器均使用 document.body.scrollTop 获取页面的垂直滚动条的位置,所以不会出现兼容性问题。而在标准模式下,由于 Chrome 与 Safari 仍然使用 document.body.scrollTop,而对于 document.documentElement.scrollTop 返回为 0。 解决办法

var rootElement = document.scrollingElement || docuemnt.body;

事件监听(原生)

var obj2 = {
    addEvent:function(el){
        el.addEventListener('click',this,false);
    },
    handleEvent:function(e){
        alert(e.target);
    }
};
obj2.addEvent(document.body);

参考链接: addeventlistener第二个参数的handleevent

字符串

delete趣事

猜猜b是什么?

var obj={a:{b:'i am b!'}};
var b=obj.a.b;
delete obj.a;
console.log(b);

setInterval

var obj={a:{c:1},b:2}
function dd(){
    function bb(c){
        console.log(c);
        debugger;
    };
    setInterval(bb,1000,obj.a);
}
dd();
obj=3;

Array

  1. length
    很多人以为JS数组的length是可读的,事实上却是可写的,此外,不小心的话还会造成灾难性的影响。

    • 设置的值比当前值大,数组增大,使用undefined填充。
    • 设置的值比当前值小,数组被截断,其尾部的元素将丢失。
  2. indexOf (hack:还可以用于数组去重) 看到indexOf第一反应是字符串类型的方法,事实上数组类型也可以使用。

    var index= [1, 2, "i", "b", "a", "b", "a"].indexOf(2);
    console.log(index);
    
  3. Array.prototype.slice.call(s) 转化步骤如下:

    1. 将参数s转化为数组
    2. 使用slice切割返回新数组
      结果是可将伪数组转化为数组,以下是保险方法。
      var toArray = function(s){
      try{
         return Array.prototype.slice.call(s);
      } catch(e){
            var arr = [];
            for(var i = 0,len = s.length; i < len; i++){
                   //arr.push(s[i]);
                   arr[i] = s[i];  //据说这样比push快
            }
            return arr;
      }
      }
      
  4. 平常用多了push,其实也可以用用unshift(直接在数组前面插入元素)
  5. reverse有坑,会改变数组本身,并返回原数组的引用。

JSON.stringify

其接受三个参数,很多人都知道第三个参数可以设置空白字符来美化输出,但是你可能不知道第二个参数的作用,它为 {Array|Function} 类型,如果为 Array 则用于过滤 key,如果为 Function 则可以对 value 做处理。
摘自@Barret李靖

运算符

以下这类的题目在网上很常见,倒不见得有多难,主要是你还记得运算符优先级不?

var a = {n:1};
a.x = a = {n:2};
alert(a.x);
// 再加一道类似的
var a==null;
var str = 'a:'+ a==null? 0 :a;

再加一道有意思的字符串拼接题:

console.log(1 +  "2" + "2");
console.log(1 +  +"2" + "2");
console.log(1 +  -"1" + "2");
console.log(+"1" +  "1" + "2");
console.log( "A" - "B" + "2");
console.log( "A" - "B" + 2);

window/document href

一个窗口下只有一个window.location.href,但是可能有多个document.URL、document.location.href,其中window.location.href和document.location.href可以被赋值,然后跳转到其它页面,document.URL只能读不能写

void

  1. 我有好几次看到了这种写法:

    <a href="javascript:dosomething();void(0);">link</a>
    

    使用 void 操作符指定超级链接,表达式会被计算但是不会为当前文档处装入任何内容。

  2. 关于void的0用法 系统级、出乎意料的或者类似错误的值的空缺使用 undefined,而程序级、正常的或意料之中的值的空缺使用 null。平时编程给变量赋值时,不要使用 undefined 而应该用 null。值得注意的是 ES3 中的 undefined 是可以被重新赋值的,ES5 修复了这个 bug。通常我们使用 void 0 来还原/代替 undefined 的值。[摘自小胡子哥微博]

延迟加载JS

大家都知道JS会阻塞UI渲染,不把JS加载脚本卸载head中,而是写在</body>前,此外,也有很多人知道发起请求的并发数有限,最好是将JS进行合并,从减少流量出发还得压缩JS脚本。
但是JS毕竟是阻塞式加载,不管怎样都会阻塞浏览器,所以我们还可以做到延迟加载,这个估计只有小部分人知道了。
这里我们暂且看看腾讯(www.qq.com)是怎么做的[请忽略AutoSiteSearch]:

JsLoader:{
        load: function(sUrl, fCallback, chset){
            var _script = document.createElement("script");
            _script.setAttribute("type", "text/javascript");
            _script.setAttribute("src", sUrl);

            if (chset)
                _script.setAttribute("charset", chset);
            else
                _script.setAttribute("charset", "gb2312");

            document.getElementsByTagName("head")[0].appendChild(_script);

            if (AutoSiteSearch.Browser.ie){
                _script.onreadystatechange = function(){
                    if (this.readyState=="loaded" || this.readyState=="complete"){fCallback(); }
                };
            }
            else if (AutoSiteSearch.Browser.moz){
                _script.onload = function() { fCallback(); };
            }
            else
                fCallback();
        }
    }

但是要提出的是做一个内容展示性网站这个没啥问题,如果利用ExtJS以及AngualarJS这样的框架来构建的话,还得注意组件加载顺序,此外页面的展示逻辑基本上都是在JS中写的,最好想清楚哪些模块可以先加载,做到不影响用户体验。其中按顺序加载我们可以这么干(不好意思,这明显是传说中的回调地狱,可以使用promise改造):

JsLoader.load('1.js',function(){
    JsLoader.load('2.js',function(){
         JsLoader.load('3.js',function(){
        });
    });
});

this.fn与prototype.fn

定义在this上使得每个实例都会有一份拷贝,定义在prototype上则会共享。一般需要使用到私有变量才定义在this上。
转念一想,所谓的原型继承顿时了然于胸。

toLocaleString

  1. 本地格式化,虽然没用过,但是看到还是比较惊奇,引自@barrentlee的微博 tolocalstring
  2. 数字千分位分割
    这个设计到一点点国际化的知识
    var a = 111222333;
    // 结果为: '111,222,333'
    console.log(a.toLocaleString());
    

杂记

记录一些有趣的输入输出

  1. JSON.stringify(undefined); JSON.stringify(null);
  2. window.localStorage.setItem('aa',undefined);window.localStorage.get('aa');

参考

小胡子哥分享 http://www.barretlee.com/blog/2016/04/18/javascript-detail/
大漠分享的12个JavaScript技巧 http://web.jobbole.com/86146/

版权声明: 署名-非商业性使用-禁止演绎 4.0 国际(CC BY-NC-ND 4.0
Copyright ©2013-2017 | 粤ICP备14081691号 | yipeng手工打造 | 联系方式