【js基础--1】一些基础性知识和技巧的记录

本文摘自MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript

1、通过如下的规则,任何值都可以被转换成布尔型:

  1)false0, 空字串(""), NaNnull, 和undefined 都被转换为 false

  2)其他值会被转换为 true

  该特性可以直接应用于判断语句中,减少代码量。

2、在对象中定义一个对象

1 var obj = {
2     name: "Carrot",
3     "for": "Max",
4     details: {
5         color: "orange",
6         size: 12
7     }
8 }

3、array.length并不是指数组中准确的元素的个数,如下所示:

var a = ["dog", "cat", "hen"];
a[100] = "fox";
a.length
101

4、遍历数组的高效率写法

  传统方式上可以通过如下方式遍历一个数组:

for (var i = 0; i < a.length; i++) {
    // Do something with a[i]
}

  这样做效率稍微有些低,因为每循环一遍都要计算一次长度。改进的方法是:

for (var i = 0, len = a.length; i < len; i++) {
    // Do something with a[i]
}

  一种更好的写法是:

for (var i = 0, item; item = a[i]; i++) {
    // Do something with item
}

  在这里我们使用了两个变量。for循环中间部分的表达式仍旧是用来监测是否为真--如果成功,那么循环继续。因为i每次递增1,这个数组的每个元素即被按顺序地传递给item变量。当一个“falsy”元素(如undefined)被发现时,循环就结束了。注意,这个技巧只能在你确认数组中不包含“falsy”值时才可以使用。如果你想要遍历可能包含0或空字符串的数组,你应该使用i, j的写法替代。

 

遍历数组的另外一种方式是使用for...in循环。注意,如果有人向Array.prototype添加新的属性,通过这样的循环它们也同样会被遍历:

for (var i in a) {
  // Do something with a[i]
}

 

5、如果你希望在一个数组后面添加元素,最安全的方式是:

a[a.length] = item;                 // 与 a.push(item)等效;
 因为a.length是比数组的最大索引值大一的数组,这样就可以保证你在数组的最后分配了一个空的位置给新的元素。

6、数组类包含了许多方法:

a.toString(), a.toLocaleString(), a.concat(item, ..), a.join(sep),
a.pop(), a.push(item, ..), a.reverse(), a.shift(), a.slice(start, end),
a.sort(cmpfn), a.splice(start, delcount, [item]..), a.unshift([item]..)
  • concat 返回一个新数组,将元素添加在结尾。
  • pop 移除并返回最后一个元素。
  • push 在数组的结尾添加一个或多个元素(类似于ar[ar.length]
  • slice 返回一个子数组
  • sort 对数组排序
  • splice 把数组中的一部分去掉并用其它值取代
  • unshift 将元素拼接到数组的开头

7、我们能知道可以给函数传递不定数量的参数,要想获取所有参数可以:

   函数可以在函数体中存取一个名为arguments的内部对象,这个对象就如同一个类似于数组的对象一样,它包括了所有被传入函数的值。让我们重写一下上面的函数,使他可以接收我们所期望的任意数量的值。

function add() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum;
}

> add(2, 3, 4, 5)
14

8、匿名函数甚至可以直接这样:

(function() {
    var b = 3;
    a += b;
})();

9、如何处理匿名函数的递归调用(因为他们并没有实际的名称)?答案是通过arguments对象,那个用来指代一系列参数的对象,它还提供了一个名为arguments.callee的属性。这个东西通常是指向当前的(调用)函数,因此它可以用来进行递归调用:

var charsInBody = (function(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += arguments.callee(child);
    }
    return count;
})(document.body);

10.通过原型(prototype)可以重写或添加对象方法及属性等,比如:

>var s = "Simon";
> s.reversed()
TypeError on line 1: s.reversed is not a function
> String.prototype.reversed = function() {
    var r = "";
    for (var i = this.length - 1; i >= 0; i--) {
        r += this[i];
    }
    return r;
}
> s.reversed()
nomiS

11、关于apply()和call()方法,不常用到但是有必要了解一下,有时间再说。

12、闭包

  下面我们将看到的是javaScript中不能不提到的功能最强大的结构之一:闭包。但它同时也有很多潜在的困扰。那么它究竟是做什么的呢?

function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?

  makeAdder函数的名字自身应该就揭示了很多秘密:它创建了一个新的‘adder‘函数,这个函数自身带有一个参数,它被调用的时候这个参数会被加在外层函数传进来的参数上。

  这里发生的事情和前面介绍过的内嵌函数十分相似:一个函数被定义在了另外一个函数的内部,内部函数可以存取外部函数的变量。这里唯一的不同就是:外部函数被返回了,那么常识告诉我们局部变量“应该”不再存在。但是它们却仍然存在--否则adder函数将不能工作。也就是说,这里存在了makeAdder的局部变量的两个不同的“副本”--一个是a等于5,另一个是a等于20。所以那些函数的结果就如下所示了:

x(6) // 返回 11
y(7) // 返回 27

  这里就是实际发生了的事情。每当javascript执行一个函数的时候,会创建一个‘范围对象‘,并用来保存在这个函数中创建的局部变量。它和被传入函数的变量一同被初始化。这与那些保存的所有全局变量和函数的全局对象(global object)相似,但有一些很重要的不同点是:第一,每次函数被执行的时候,就会创建一个新的,特定的范围对象;第二,与全局对象(在浏览器里面是当做 window 对象来访问的)不同的是,你可以从javascript代码中直接访问范围对象。目前并没有机制可以遍历当前的范围对象里面的属性。

所以当调用makeAdder时,创建了一个范围对象,它带有一个属性:a,被当做参数传入makeAdder函数。makeAdder然后返回一个新创建的函数。通常JavaScript的垃圾回收器会在这个点上清理掉makeAdder创建的范围对象,但是返回的函数却保留着一个指向那个范围对象的引用。结果,这个范围对象将不会被垃圾回收器回收,直到指向makeAdder返回的那个函数对象的引用计数为零。

  范围对象组成了一个名为范围链的链。它类似于原形(prototype)链一样,被javascript的对象系统使用。

  一个闭包就是一个函数和被创建的函数中的范围对象的组合。

  闭包允许你保存状态--所以,它们通常可以代替对象来使用。

13、内存泄露

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。