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

前些时候,发现了自己的很多问题,因为手头当时有项目要做,所以找到问题的原因,写了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好人"));