JS学习笔记摘录

深入JavaScript - 基础

  1. 类型(Type): 数据的集合
  2. 原始值(Primitive Value):  只能是 Undefined, Null, Boolean, Number or String其中之一的值. : undefined, null, true / false, 3.1415926, "Hello world!"
  3. 对象(object): Object类型的一员(注意大小写), 它是一些无序的,属性的集合; 属性可以是原始值, 另一个对象 或一个函数. 保存在对象属性里的函数通常叫做方法(method).
  4. 原型(prototype): 原型属性指向的是一个对象! 一般叫它原型对象. JavaScript用它来实现好的继承机制.待续... 欢迎指正, 共同进步. 后面就是涉及宿住环境的对象, 和内建对象一些说明. 这些是开始, 可能看到上面关于prototype介绍, 还是一大堆问号, 在以后会继续一点点的写 :)  尽量每一篇的topic, 内容多 :)

    Javascript 风格向导

       

    类型

       

     原始类型:我们可以直接使用值。

      ο  string

      ο  number

      ο  boolean

      ο  null

      ο  undefined

    •   复合类型:我们通过`引用`对值进行间接访问。

      ο  object

      ο  array

      ο  function

       

    var foo = [1, 2],

    bar = foo;

     

    bar[0] = 9;

     

    console.log(foo[0], bar[0]); // => 9, 9

        

    Objects

       

     使用{}创建对象。

    var item = {};

     不要使用保留字作为关键字。

    Arrays

       

     • 使用[]创建数组

    // bad

    var items = new Array();

     

    // good

    var items = [];

     • 如果你不知道数组长度,使用Array#push

    var someStack = [];

     

    // bad

    someStack[someStack.length] = 'abracadabra';

     

    // good

    someStack.push('abracadabra');

       

      • 当你需要复制数组的时候,请使用Array#slice

    var len = items.length,

    itemsCopy = [],

    i;

     

    // bad

    for (i = 0; i < len; i++) {

    itemsCopy[i] = items[i];

    }

     

    // good

    itemsCopy = items.slice();

       

    Strings

     • 对于字符串,我们使用单引号''

     • 当我们在编程的时候,需要拼接出一个字符串,我们可以使用Array#join 代替字符串连接。尤其是对IE浏览器。 

    var items,

    messages,

    length, i;

     

    messages = [{

    state: 'success',

    message: 'This one worked.'

    },{

    state: 'success',

    message: 'This one worked as well.'

    },{

    state: 'error',

    message: 'This one did not work.'

    }];

     

    length = messages.length;

     

    // bad

    function inbox(messages) {

    items = '<ul>';

     

    for (i = 0; i < length; i++) {

    items += '<li>' + messages[i].message + '</li>';

    }

     

    return items + '</ul>';

    }

     

    // good

    function inbox(messages) {

    items = [];

     

    for (i = 0; i < length; i++) {

    items[i] = messages[i].message;

    }

     

    return '<ul><li>' + items.join('</li><li>') + '</li></ul>';

    }

       

    Functions

     • 绝对不要在非函数块(if,while)申明一个函数。我们可以把函数申明变成一个函数表达式。

    // bad

    if (currentUser) {

    function test() {

    console.log('Nope.');

    }

    }

     

    // good

    if (currentUser) {

    var test = function test() {

    console.log('Yup.');

    };

    }

     • 绝对不要把一个参数命名为argumentsarguments参数是函数作用域内给出的一个特殊变量,如果你把参数命名为arguments,那么这个参数就会覆盖它原有的特殊变量。

    Javascript 风格向导(续)

    Properties

     • 当访问属性的时候,我们使用点(.)操作符。

     • 当以变量的方式访问属性的时候,用下标符号([])。——除非特殊需求,否则尽量避免使用obj[variable]的方式进行属性访问。

    var luke = {

    jedi: true,

    age: 28

    };

     

    function getProp(prop) {

    return luke[prop];

    }

     

    var isJedi = getProp('jedi');

       

    Variables

       

     • 总是使用var定义变量,否则会导致产生隐含全局变量。我们要尽量避免污染全局变量命名空间。

    汤姆大叔—javascript系列文章中提到"JavaScript有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性。在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete操作符删除的,而变量是不能的。"

     • 使用一个var定义多个变量,每个变量在一个新行上。

    // good

    var items = getItems(),

    goSportsTeam = true,

    dragonball = 'z';

     • 用var定义多个变量的时候,把不进行赋值的变量放置到最后——这是相当有益的。尤其是当你的变量需要前面变量值的时候。

    // good

    var items = getItems(),

    goSportsTeam = true,

    dragonball,

    length,

    i;

     • 把你的赋值变量放置在当前作用域的顶端。这将避免变量声明和hoisting(悬置/置顶解析/预解析)的问题。

    Hoisting

       

    汤姆大叔:

      1JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)。

      2、对于JavaScript,只 要你的变量是在同一个作用域中(同一函数),它都被当做是声明的,即使是它在var声明前使用的时候。

     •  匿名表达式会自动提升它们的变量名称(也就是说在var anonymous上面,example函数就已经知道有这个变量了),但是它们的函数体不会。

    function example() {

    console.log(anonymous); // => undefined

     

    anonymous(); // => TypeError anonymous is not a function

     

    var anonymous = function() {

    console.log('anonymous function expression');

    };

    }

     •  命名函数表达式也会提升它们的变量名称,而它们的函数名称和函数体不会这样做。

    function example() {

    console.log(named); // => undefined

     

    named(); // => TypeError named is not a function

     

    superPower(); // => ReferenceError superPower is not defined

     

    var named = function superPower() {

    console.log('Flying');

    };

     

     

    function example() {

    console.log(named); // => undefined

     

    named(); // => TypeError named is not a function

     

    var named = function named() {

    console.log('named');

    };

    }

    }

     •  注意:函数声明会提升它们的变量名称还有它们的函数体

    function example() {

    superPower(); // => Flying

     

    function superPower() {

    console.log('Flying');

    }

    }

        

    Conditional Expressions & Equality

       

     •  使用 === !== 代替==!=

    == != 会进行隐式类型转换,所以建议使用===!==

     •  强制使用对象的特性(ToBoolean)得到条件表达式的值,大致遵循以下简单规则。

      ◊ Objects 得到的值是true

      ◊ Undefined得到的值是false

      ◊ Null得到的值是false

      ◊ Booleans得到的值是Boolean值(呵呵,当然)。

      ◊ Numbers 得到的值是:如果是+0-0,或者NaN就是false,否则就是true

      ◊ Strings 得到的值是:如果是'',就是false,否则就是true

    if ([0]) {

    // true

    // An array is an object, objects evaluate to true

    }

     •  使用快捷方式。

    // bad

    if (name !== '') {

    // ...stuff...

    }

     

    // good

    if (name) {

    // ...stuff...

    }

     

    // bad

    if (collection.length > 0) {

    // ...stuff...

    }

     

    // good

    if (collection.length) {

    // ...stuff...

    }

     Javascript 风格向导(终结)

    {}的代码,我们换行处理。

    // bad

    if (test)

    return false;

     

    // good

    if (test) return false;

     

    // good

    if (test) {

    return false;

    }

     

    // bad

    function() { return false; }

     

    // good

    function() {

    return false;

    }

       

    Comments

       

    对于多行注释使用/**  ... */。包含描述信息、参数类型和返回值。

    对于单行注释使用//。单行注释单独放置在一个新行上。在注释前面放置一个空行。

    对于一些问题,注释前加FIXMETODO,这样将快速帮助开发者快速明白代码意图。

    使用 // FIXME: 注释问题

    function Calculator() {

     

    // FIXME: shouldn't use a global here

    total = 0;

     

    return this;

    }

    使用 // TODO: 注释问题的解决方案

    function Calculator() {

     

    // TODO: total should be configurable by an options param

    this.total = 0;

     

    return this;

    }

    Constructors

       

     • 用方法扩展对象,而不是用一个新对象。

    function Jedi() {

    console.log('new jedi');

    }

     

    // bad

    Jedi.prototype = {

    fight: function fight() {

    console.log('fighting');

    },

     

    block: function block() {

    console.log('blocking');

    }

    };

     

    // good

    Jedi.prototype.fight = function fight() {

    console.log('fighting');

    };

     

    Jedi.prototype.block = function block() {

    console.log('blocking');

    };

       

    javascript 杂谈之哪种写法你更喜欢?

     直接初始化法

    JS学习笔记摘录_第1张图片

    优点:

    1userData本身就是对象实例。——上来就实例化一个类出来,也不怕浏览器受不了。

    2、代码紧凑。

    3、编程效率高。

    缺点:

    1、代码的重用性比较差。

    2、不符合面向对象的编程思路。——设计模式这种玩意,经常是在类上,弄来弄去。这种直接在对象上使用,够呛!

    总结:应避免使用该方法创建自定义对象。

    使用案例: QQ迷你弹窗

     构造函数法

       

    JS学习笔记摘录_第2张图片

    使用方法:需要使用"new 构造函数"创建实例。

    优点:

    只有new的时候,才分配内存。如果不new,浏览器一辈子都不会给你内存资源的。——想要就要,不想要就不理她!

       

     Object表达式法

       

    类似于第一种"直接初始化法"——其实是一种变种。

    JS学习笔记摘录_第3张图片

    上面那一坨红色标出来的部分,让人看着眼晕。——这代码让谁看了,估计都要狂吐血!

     匿名函数法

       

    JS学习笔记摘录_第4张图片

    上面那个是我经常用的,我在项目中写了一堆的扩展,用这玩意,层次感非常强。

    案例:jQuery

    对《javascript 杂谈之哪种写法你更喜欢?》最后一种"匿名函数法"的解释

    第一部分

    第一部分中,我们把extend相关的方法抽离,剩余代码如下:

    (function () { 

     var yQuery = (function () { 

     var yQuery = function () { 

     return yQuery.fn.init(); 

     }; 

     

     yQuery.fn = yQuery.prototype = { 

     init: function () { 

     return this; 

     } 

     }; 

     return yQuery; 

     })(); 

     window.yQuery = window.$ = yQuery(); 

     })(); 

    知识点1:无引用的匿名函数调用

    (function() { 

     })(); 

    这种写法作用是声明并执行一个方法,等同于:

    function Test() { 

     } 

     Test(); 

    知识点2:属性变量无需声明

    var obj = new Object(); 

     obj.name = "abc"; 

    obj并没有name属性,但无需声明就可以使用,初始值为undefined。上例中yQuery.fn 就没有声明。

    知识点3:{}二义性,相当于创建一个对象。

    var obj = new Object(); 

    var obj = { }; 

    在js中,{}除了可作为复合语句边界以外,还有创建一个空对象的作用,因此上面这两句相同。而在例子中用到的情况如下:

     { 

     init: function () { 

     return this; 

     } 

     }; 

    这段代码猛一看像方法,实质是一个包含了init方法的对象,而方法中的this指向这个对象本身。

    知识点4:连等表达式

    var a = b = 1; 

    这个比较好理解,相当于对他们分别赋同一个值。在上例中,yQuery.fn就用到了这个写法。

    知识点5:原型继承prototype

    yQuery.fn = yQuery.prototype = { 

     init: function () { 

     return this; 

     } 

     }; 

    例子中,通过连等分别对yQuery.fn和yQuery.prototype赋值给了同一个对象。而fn的作用只是一个别名,只为书写方便,重点是给prototype赋值,为什么要给它赋值?在本例中无法解释。

    在jQuery中,init方法会返回不同对象,而本例中永远返回同一个对象,因此这里prototype没有多大意义。至于jQuery为什么要用prototype,算是题外话了,有兴趣的可点这里

    第一部分代码含义

    这段代码第二行yQuery和第三行的yQuery是两个变量,因名字相同,所有很有迷惑性。整段代码意思就是:yQuery.prototype指向了一个包含init方法的对象,prototype有个别名fn,可通过yQuery.fn.init()返回这个对象,最后把这个对象赋值给window.$和window.yQuery属性。

    第二部分

    看完了第一部分,第二部分就相对简单了,代码如下:

    yQuery.extend = yQuery.fn.extend = function () { 

     var options, name, src, copy, 

     target = arguments[0] || {}, 

     i = 1, 

     length = arguments.length; 

     if (length === i) { 

     target = this; 

     --i; 

     } 

     

     for (; i < length; i++) { 

     if ((options = arguments[i]) != null) { 

     for (name in options) { 

     src = target[name]; 

     copy = options[name]; 

     

     if (src === copy) { 

     continue; 

     } 

     if (copy!==undefined) { 

     target[name] = copy; 

     } 

     } 

     } 

     } 

     return target; 

     }; 

    知识点1:函数中的arguments变量

    函数内部会自带一个arguments变量,该变量记录传入的参数,从左至右分别是arguments[0],arguments[1]等,js奇怪的地方在于,你声明了一个无参函数,在调用的时候依然可以传入参数,比如:

    function NoArg() { 

     console.log(arguments[0]); 

     console.log(arguments[1]); 

     console.log(arguments[2]); 

     } 

     NoArg(1, 2, "a"); 

    该例NoArg调用时,会正常显示传入参数。

    知识点2:结果类型不确定的逻辑运算

    js中,所有类型都可以进行逻辑判断(true或false),js会将值转化为布尔值,但并不改变原值。如:

    var str = "a"; 

     if(str) { 

     } 

    此处的str为true,该特性与逻辑运算符"||"和"&&"结合形成了js一大特点,代码如下:

    var str = "a"; 

    var num = 1; 

    var x = str || num; //x="a" 

    var y = str && num; //y=1; 

    js支持"逻辑短路",所谓逻辑短路是指:

    1. 在"||" 运算中,第一个条件符合就结束判断。
    2. 在"&&"运算中,第一个条件不符合就结束判断。

    因此,"str || num"的str为true,则结束判断,返回str。"str&&num"的str为true,则继续判断num,num为true,则返回num。在本文案例中,有几个地方用到了这个特性:

    target = arguments[0] || {} 

    容易看出,如果arguments[0]有值则返回该值,不然就通过{}返回一个空的对象。还有一处在图片中有,我文中没有打出来的代码:

    $.ui = $.ui || { }; 

    知识点3:数组方式访问对象属性

    var obj = new Object(); 

    obj.name = "a"; 

    obj["name"] = "a"; 

    最后两行代码等效。

    第二部分代码含义

    这部分代码可简单描述为:定义一个方法,将参数1之外的所有参数的属性成员赋值给参数1。我把循环部分修改一下,能更容易看懂,代码如下:

    for (; i < length; i++) { 

     if ((options = arguments[i]) != null) { 

     for (var name in options) { 

     if (options[name] !== undefined) { 

     target[name] = options[name]; 

     } 

     } 

     } 

     } 

     

你可能感兴趣的:(学习笔记)