记我最近犯过的错和知识不熟悉的地方

    前些时候,发现了自己的很多问题,因为手头当时有项目要做,所以找到问题的原因,写了demo后,就放在了一边,并没有整理心得,今天把先前的稍微整理下。对大家来说可能并没有实际意义。可以忽略。


    js获得时间戳的东西

    下面是总结的五种获得时间戳的方法。

    1
    2
    3
    4
    5
    console.log(new Date().getTime());
    console.log(+new Date());
    console.log(Date.parse(new Date()));
    console.log(new Date().valueOf());
    console.log(Date.now());


    chrome里面测试代码用时的小tip

    在代码前面使用console.time。在代码之后使用console.timeEnd();即可

    chrome


    children和childNodes的区别

    直接打印下,直观的感受下:

    1
    2
    3
    4
    5
    6
    7
    8
    <div id="test">
    hello start;
    <p class="a">this is p1</p>
    <p>this is p2</p>
    <p id="test">this is p3</p>
    hello end;
    <p>this is p4</p>
    </div>

    1
    2
    3
    4
    var o = document.getElementById("test");
    console.log(o.hasChildNodes());
    console.log(o.children);
    console.log(o.childNodes);

    不看答案,看都能不能说对。

    打印结果

    我们可以看到childNodes返回html节点和文本等节点。children只返回html节点,不返回文本节点。

    childNodes,是一个标准属性,它返回指定元素的子元素集合,包括HTML节点,所有属性,文本。可以通过nodeType来判断是哪种类型的节点,只有当nodeType==1时才是元素节点,2是属性节点,3是文本节点。

    children,非标准的属性,它返回指定元素的子元素集合。它只返回HTML节点,甚至不返回文本节点。

    所以当我们如果要用childNodes获取html节点的时候,就要进行过滤,如下:

    1
    2
    3
    4
    5
    for(var i=0,len=o.childNodes.length;i<len;i++){
    if(o.childNodes[i].nodeType == 1){
    console.log(o.childNodes[i]);
    }
    }

    中间还有一个问题,如果我们想要获得元素的第一个html节点或者最后一个节点,我们肯定先想到的是firstChild和lastChild,如下,我们是获取不到的,获得到的是text文本。而且仔细看上面,空格也算是文本,所以一定是获取不到节点的。空格和换行我们都可以在控制台看到。

    1
    2
    console.log(o.firstChild);
    console.log(o.lastChild);

    打印结果

    但是如果我们稍微改一下,把<p></div>中间的空格去掉,我们就可以获得到最后一个节点是p啦。

    1
    2
    3
    4
    5
    6
    7
    <div id="test">
    hello start;
    <p class="a">this is p1</p>
    <p>this is p2</p>
    <p id="test">this is p3</p>
    hello end;
    <p>this is p4</p></div>

    打印结果

    这里就要接着认识下,element和node的区别是什么呢?

    元素(Element)和结点(Node)有区别,节点包含了元素,元素一定是节点,而必须是含有完整信息的结点才是一个元素。DOM将文档中的所有都看作节点 node>element,两个标签之间的空白也是这棵树的一个节点(Text节点)

    想一想下面会输出什么呢?

    1
    2
    3
    4
    5
    6
    7
    console.log(o);
    console.log(o.firstChild);
    console.log(o instanceof Node);
    console.log(o instanceof Element);
    console.log(o.firstChild instanceof Node);
    console.log(o.firstChild instanceof Element);

    打印结果

    我们可以看到用document.getElementById(“xxx”)取到的既是Element也是Node。children是Element的属性,childNodes是Node的属性。

    dom选取页面元素对象的子对象时,children 选取不包括空白节点, 而childNodes在firefox会选取空白节点。


    记录一个可以异步加载js文件并可以调用回调函数的脚本

    主要想法是创建script标签,然后给script设置异步执行,然后每次加载完一个js文件,就把count+1,并且检查当前的已经加载了的文件是否等于传入的文件的数量,如果已经相等了,表示所有的文件已经加载完毕,这时候,调用回调函数。这里我利用的是以构造函数的形式创建对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    function Loader(){
    var head = document.getElementsByTagName("head")[0];
    var loadCount = 0;
    this.require = function (scripts,callback){
    this.totalScripts = scripts.length;
    this.callback = callback;
    for(var i=0;i<this.totalScripts;i++){
    this.createScript(scripts[i]);
    }
    };
    this.createScript = function(url){
    var script = document.createElement("script");
    var self = this;
    script.src = url;
    script.defer = true;
    script.type = "text/javascript";
    script.addEventListener("load",function(e){
    loadCount++;
    self.check();
    },false);
    head.appendChild(script);
    };
    this.check = function(){
    if(this.totalScripts == loadCount && typeof this.callback == 'function'){
    this.callback();
    }
    }
    }
    var load = new Loader();
    load.require(['33.js','44.js'],function(){
    console.log("all scripts have been loaded");
    });


    引用赋值时的坑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var a = {"x": 1};
    var b = a;
    a.x = 2;
    console.log(b.x);
    a = {"x":3};
    console.log(b.x);
    a.x = 4;
    console.log(b.x);

    这个例子我觉得很经典。答案是b.x的值一直是2。我们要理解这个过程中发生了什么事。首先声明了一个a对象,b=a,因为是引用赋值,所以b和a指向同一个对象。所以这个时候,a改变或者b改变都是会影响对方的。后来,我们给a重新赋值,这个时候,是重新开辟了一个空间,a指向新的对象,b还是指向原来的对象,这个时候a和b已经没有关系了。


    用JS画一个圆

    这个主要就是利用数学的原理,然后把点画出来定位就可以了。就是记录一下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    var Circle = function(){
    var PI = Math.PI;
    return {
    draw:function(r,_x,_y){
    var x,y;
    for(var i=0;i<360;i++){
    x = Math.cos(PI/180 * i)*r+_x;
    y = Math.sin(PI/180 * i)*r+_y;
    var point = document.createElement("span");
    point.appendChild(document.createTextNode("."));
    document.body.appendChild(point);
    point.style.position = "absolute";
    point.style.top = y+"px";
    point.style.left = x+"px";
    }
    }
    }
    }();
    Circle.draw(100, 500, 600);

    打印结果


    jquery中.closet和.parents的区别

    打印结果

    有时候看代码可能会更容易理解,我们看下面这个例子。具体的来看下面这个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <ul>
    <li>I</li>
    <li>II
    <ul>
    <li class="item-a">A</li>
    <li>B
    <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    </ul>
    </li>
    <li>C</li>
    </ul>
    </li>
    <li>III</li>
    </ul>

    如果我们用parents得到的结果是这样的:

    1
    $('li.item-a').parents('ul').css('background-color', 'red');

    打印结果

    如果我们用parents得到的结果是这样的:

    1
    $('li.item-a').closest('ul').css('background-color', 'red');

    打印结果


    fiddler的工作原理

    从图中我们可以看到,fiddler充当的就是一个代理的作用,当我们的从客户端发送请求时,就是先通过代理服务器,让后由代理服务器发送给服务器。这样我们就可以通过fiddler中间做很多事情。
    fiddler工作原理
    回头我仔细会用fiddler了,再来专门写一篇。现在不是很会用。


    闭包的坑

    看看下面是输出什么,如果一眼看不出来,就是闭包掌握的还不好,最后输出的都是Z。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function A(params) {
    params = params || {};
    for (var key in params) {
    this[key] = function() { return params[key];};
    }
    }
    var a = new A({
    'x': 'X',
    'y': 'Y',
    'z': 'Z'
    });
    console.log(a.x());
    console.log(a.y());
    console.log(a.z());

    记录和整理二,接着上次的整理。主要记录的是容易犯的错和一些知识点的归纳总结。


    关于typeof和instanceof的坑

    typeof 123          
    typeof new Number(123)  
    typeof null         
    typeof NaN          
    123 instanceof Number  
    new Number(123) instanceof Number  
    Number(123) instanceof Number
    

    上面的答案是什么呢?

    typeof and instanceof

    typeof的返回值有number,boolean,string,function,object,undefined这6个。记住只有这6个,而且里面没有array。typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。

    这里面要注意的就是第4个,NaN是一个特殊的东西,它和任何东西都不相等,用typeof返回的是Number。注意只有new的结果返回的是一个对象,Number和直接定义数字直接量都是返回的数字值。

    1
    2
    3
    console.log(Number(123));
    console.log(new Number(123));
    console.log(123);

    typeof and instanceof

    再来一波测测是否理解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    console.log(typeof(1));
    console.log(typeof(NaN));
    console.log(typeof(Number.MIN_VALUE));
    console.log(typeof(Infinity));
    console.log(typeof("123"));
    console.log(typeof(true));
    console.log(typeof(window));
    console.log(typeof(document));
    console.log(typeof(null));
    console.log(typeof(eval));
    console.log(typeof(Date));
    console.log(typeof(sss));
    console.log(typeof(undefined));

    typeof and instanceof


    看看fragment的用法

    1
    2
    3
    4
    5
    6
    7
    8
    var frament = document.createDocumentFragment();
    for(var i = 0;i<10;i++){
    var ele = document.createElement("p");
    var node = document.createTextNode("hello");
    ele.appendChild(node);
    frament.appendChild(ele);
    }
    document.body.appendChild(frament);

    createdocumentfragment()方法创建了一虚拟的节点对象,节点对象包含所有属性和方法。
    当你想提取文档的一部分,改变,增加,或删除某些内容及插入到文档末尾可以使用createDocumentFragment() 方法。
    你也可以使用文档的文档对象来执行这些变化,但要防止文件结构被破坏,createDocumentFragment() 方法可以更安全改变文档的结构及节点。

    说明:添加多个dom元素时,先将元素append到DocumentFragment中,最后统一将DocumentFragment添加到页面。 该做法可以减少页面渲染dom元素的次数。经IE和FireFox下测试,在append1000个元素时,效率能提高10%-30%,FireFox下提升较为明显。


    看下下面这几个输出

    1
    2
    3
    console.log(Number.MAX_VALUE);
    console.log(Number.MIN_VALUE);
    console.log(Math.pow(2,53));

    chrome


    打乱数组的一种方法

    随机生成一个在数组长度内的数,每次把数组中的一个元素和该生成数对应的值调换即可。据说是目前打乱数组的最好方法(交换);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function shuffle (arr){
    var length = arr.length;
    while(length){
    var index = Math.floor(Math.random()*length);
    length--;
    var temp = arr[length];
    arr[length] = arr[index];
    arr[index] = temp;
    }
    return arr;
    }
    var myArray = ['1','2','3','4','5','6','7','8','9'];
    console.log(shuffle(myArray));


    arguments对象

    1
    2
    3
    4
    5
    6
    7
    8
    (function(){
    console.log(arguments instanceof Array);
    var argArr = Array.prototype.slice.call(arguments);
    console.log(argArr instanceof Array);
    console.log(Function instanceof Object);
    console.log(Object instanceof Function);
    })()

    输出值分别为false和true,true,true。记住Array.prototype.slice.call(arguments)这也是一种把arguments转化成数组的方法。


    sort方法

    有一个数组,其中保存的都是小写英文字符串,现在要把它按照除了第一个字母外的字符的字典顺序(字典顺序就是按首字母从a-z顺序排列,如果首字母相同则按第二个字母……)排序。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var compare = function (a,b){
    if(typeof(a) === "string" && typeof(b) === "string"){
    var new_a = a.slice(1);
    var new_b = b.slice(1);
    if(new_a>new_b){
    return 1;
    }else if(new_a<new_b){
    return -1;
    }
    }
    return 0;
    }
    var arr = ["abd","cba","ba"];


    获取文档中的所有links标签,然后获取里面的内容。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var links = document.links;
    var length = links.length;
    for(var i = 0;i<length;i++){
    (function(i){
    links[i].onclick = function(e){
    alert(e.target.innerHTML);
    e.preventDefault();
    }
    })(i)
    }


    写一个ua函数,判断当前浏览器是什么浏览器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var Sys = {};
    var ua = navigator.userAgent.toLowerCase();
    console.log(ua);
    var s;
    (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
    (s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
    (s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
    (s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
    (s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;
    //以下进行测试
    if (Sys.ie) console.log('IE: ' + Sys.ie);
    if (Sys.firefox) console.log('Firefox: ' + Sys.firefox);
    if (Sys.chrome) console.log('Chrome: ' + Sys.chrome);
    if (Sys.opera) console.log('Opera: ' + Sys.opera);
    if (Sys.safari) console.log('Safari: ' + Sys.safari);

    尽量用最简单的达到想要的要求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function spacify(str){
    return str.split('').join(' ');
    }
    console.log(spacify('hello world'));
    String.prototype.spacify = function(){
    return this.split('').join(' ');
    }
    console.log("hello world".spacify());
    function log(){
    var args = Array.prototype.slice.call(arguments);
    args.unshift("(app)");
    console.log.apply(console,args);
    }
    log("hello","world");

    编写一个方法 求一个字符串的字节长度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function getLength(str){
    var length = str.length;
    var init = length;
    for(var i = 0;i<init;i++){
    if(str.charCodeAt(i) >255){
    length++;
    }
    }
    return length;
    }
    console.log(getLength("woshi好人"));