《Javascript for PHP Developers》读书笔记

    这本书一共才130多页,当时在图书馆借这本书的时候,纯粹是因为它把部分php和javascript放在一起对比。后来看下去,知识点讲的不细,但是对Javascript整体容易犯错的地方都有解释。而且由于书特别薄,所以读起来也比较方便,目录很清晰。所以还是不错的。下面记录的是我看书的时候发现的一些知识点的漏洞或者是总结。先让我们看看这本书的真面目:


    默认参数可能要注意的一个坑

    1
    2
    3
    4
    5
    function sum(a,b){
    b = b||2;
    return a+b;
    }
    console.log(sum(2,0));

    我想要把2和0相加,最后得到2,但是这个的输出结果确实4,大家一看肯定明白为什么会输出4了吧。因为当我们传入0的时候,这种比较会得到结果为false。一个可行解决方案是使用typeof。平时要注意这个。

    1
    2
    3
    4
    5
    function sum(a,b){
    b = typeof b === "undefined"?2:b;
    return a+b;
    }
    console.log(sum(2,0));


    substr是非标准的

    顺便总结下截取字符串的三种方法。

    1
    2
    3
    console.log(s.slice(4,7));
    console.log(s.substring(4,7));
    console.log(s.substr(4,3));


    几种编码URL方法和它们的区别和联系

    encodeURIdecodeURI类似于encodeURIComponentdecodeURIComponent,区别在于前者只是编码需要编码的那一部分,将类似于Http://的这个部分是不用动的。并且要注意encodeURI不编码&,具体想用哪个可以根据具体的需求来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var testUrl = "https://www.baidu.com/s?r ds v_bp=0&bar=&rsv_spt=3";
    console.log(encodeURIComponent(testUrl));
    console.log(decodeURIComponent(encodeURIComponent(testUrl)));
    console.log(encodeURI(testUrl));
    console.log(decodeURI(encodeURI(testUrl)));
    console.log(escape(testUrl));
    console.log(unescape(escape(testUrl)));

    编码Url

    这里提一下escape和unescape,他们不是ECMAScript的一部分,他们来自于BOM,我们尽量应该避免使用它们。


    关于null和undefined

    undefined返回的值总是字符串,所以下面这种情况要注意。

    1
    2
    3
    4
    5
    6
    var a;
    console.log(a);
    console.log(a == undefined);
    console.log(a == "undefined");
    console.log(typeof a == undefined);
    console.log(typeof a == "undefined");

    答案是: undefined, true, false, false, true。null要注意的就是typeof null结果是object就行了。


    删除属性

    1
    2
    3
    4
    var obj = {one:1,two:2};
    delete obj.one;
    //obj.one = null;
    console.log(obj);

    以前删除一个属性,大部分都是用的obj.one = null这种形式,现在看来我真的是大错特错了。用delete删除,最后obj是Object {two: 2},one确实被去掉了,而且通过obj.one再去访问的时候,返回的是undefined。但是当我们通过赋值为null这种形式时,它只是被重新赋值为null了,而不是完全的删除了。


    php和js的try-catch有什么区别?

    区别记录如下:

    1. js抛出的是Error对象,而不是Exception对象。
    2. 捕获时,js没有声明类型。
    3. 访问message属性,而不是调用getMessage方法。
    

    具体来看看代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var msg = "";
    try{
    throw new Error("ouch");
    }catch(e){
    msg += e.message;
    }finally{
    msg += "-finally";
    }
    console.log(msg);

    答案是ouch-finally;看看php是怎么写的:

    1
    2
    3
    4
    5
    try{
    throw new Exception("ouch");
    }catch(Exception $e){
    $msg = $e.getMessage();
    }


    全局变量和全局对象的属性的细微区别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var john = "Jo";
    console.log(john);
    console.log(window.john);
    window.jane = "Jane";
    console.log(jane);
    console.log(window.jane);
    console.log(delete window.john);
    console.log(delete window.jane);

    结果是Jo,Jo,Jane,Jane,false,true。主要注意下这个false。
    我们可以把全局变量当成是全局对象的属性来看,唯一的不同之处在于,你无法删除它们。看这里的john是无法被delete删除的。


    利用parseInt把CSS十六进制颜色定义转换为rgb()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function getRGB(color){
    var r = parseInt(color[1]+color[2],16);
    var g = parseInt(color[3]+color[4],16);
    var b = parseInt(color[5]+color[6],16);
    return "rgb("+r+","+g+","+b+")";
    }
    var color = "#ff0000";
    console.log(getRGB(color));

    最后的结果是:rgb(255,0,0),总结下全局函数中四个与数字相关的函数分别是:isNaN(),isFinite(),parseInt(),parseFloat()


    toString()方法

    1
    2
    3
    4
    5
    var o = {};
    console.log(o.toString());
    console.log(Object.prototype.toString.call(o));
    //字符串"[object Object]"对于任何对象都是相同的,所以下面返回true
    console.log(Object.prototype.toString.call({}) === Object.prototype.toString({a:1}));

    toString()方法存在于Object.prototype之上,因此,可以像上面那样使用它们。toString方法一般用于测试数组,由于一些原因,其他的一些测试数组方法都会有缺陷,下面的是目前稍微好一点的解决办法。

    1
    2
    3
    4
    5
    6
    7
    function isArray(arr){
    if(!Array.isArray){
    return Object.prototype.toString.call(arr) === "[object Object]";
    }
    return Array.isArray(arr);
    }
    isArray([1,2]);

    构造器函数

    Number,String,Boolean,这些,如果直接使用构造器函数,而不是以new一个对象的形式,就返回的是原始类型,而不是对象。这个先前博客里有提到过。
    比如typeof Number(1.1)返回结果是"number"typeof new Number("1,1"),结果是objectNumber(1.1)返回的结果是1.1。Number(123).toFixed(2);结果是123.00。

    1
    2
    3
    console.log(Number(123).toFixed(2));
    console.log((100000000000).toExponential());
    console.log((100000000000).toPrecision(3));

    构造器函数


    forEach传递给回调函数的参数

    我容易把第一个和第二个写反。比如写成function(index,item)这样是不能得到正确结果的。正确的格式如下:[元素,元素索引,整个数组]

    1
    2
    3
    ["a","b","c"].forEach(function(){
    console.log(arguments);
    })

    forEach


    通过JSON深拷贝

    创建一个深拷贝的最简单方式,是使用JSON编码后再解码该对象,这可能不是最高效的方式,特别是在不能使用JSON的浏览器中。

    1
    2
    3
    4
    5
    6
    7
    var stuff = {
    a:{
    b:[1,2]
    }
    };
    console.log(JSON.stringify(stuff));
    console.log(JSON.parse(JSON.stringify(stuff)));

    JSON深拷贝


    构造器和类

    下面的篇幅有点长,涉及到构造器,类,返回对象和this指针。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Dog(){
    this.name = "littleDog";
    this.sayName = function(){
    return this.name;
    }
    }
    var myDog = new Dog();
    console.log(myDog.sayName());

    上面是一个再简单不过的我们创建的构造器函数了。我们回顾下,在我们使用new调用任何一个函数时,会发生下面的事情

    1. 在后台自动创建一个空的对象,通过this引用该对象。var this = {};//伪代码,直接这样是会报错的。
    2. 程序员可以给任意的this添加属性。如this.name="littleDog"。
    3. 在函数的末尾,我们隐式的返回了this。return this,这不是一个错误,但是我们不需要使用它。
    

    我们可以通过返回一个对象,从而改变步骤3,但是这个会发生下面的问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Dog(){
    this.name = "littleDog";
    var notthis = {noname:"noname"};
    return notthis;
    }
    var myDog = new Dog();
    console.log(myDog.noname);
    console.log(myDog.name);

    noname, undefined这是我们会得到的结果结果,我们在这个构造器中返回了一个自定义对象,但也使用了this,当我们用返回的对象,访问对象的属性是肯定没有问题,但我们访问this定义的却是undefined。原因是:

    在这个实例中,我们给this添加的任何内容,在函数返回的时候都直接销毁了,你可以删除它,并且在这种情况下,我们不需要借助new的魔力,我们可以就把它当作一般的函数调用,也可以实现相同的效果。如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Dog(){
    this.name = "littleDog";
    var notthis = {noname:"noname"};
    return notthis;
    }
    var myDog = Dog();
    console.log(myDog.noname);
    console.log(myDog.name);

    这个过程中我们又要注意,如果我们返回的任何this以外的内容,都会导致instanceof运算符和constructor属性无法正常工作。

    1
    2
    3
    var myDog = new Dog();
    console.log(myDog instanceof Dog);
    console.log(myDog.constructor === Object);

    结果是,false,true。

    当我们使用new的时候,可以返回一个定制的对象,而不是this,但是它必须是一个对象,如果你尝试返回一个非对象,将导致返回值被忽略,最后还是会得到this

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Dog(){
    this.name = "littleDog";
    this.sayName = function(){
    return "hello, "+this.name;
    }
    return 1;
    }
    var myDog = new Dog();
    console.log(myDog.sayName());

    这个例子里1将会被忽略。同样是返回this。但如果我们var myDog = Dog();肯定结果就是1了,对吧。


    增强构造器

    我们是可以通过变成来确保即便调用者忘记了new,函数也会像是构造器函数一样工作。可以使用instanceof,它接受一个对象和一个构造器函数的引用,返回true或者false。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function Dog(){
    if(!(this instanceof Dog)){
    return new Dog();
    }
    this.name = "littleDog";
    this.sayName = function(){
    return "hello, "+this.name;
    }
    return 1;
    }
    var myDog = Dog();
    console.log(myDog.sayName());


    总结

    主要就是一个记录,方便以后查阅,也是给花的时间的一个交代,每次看完一个书,如果不把重点记下来,估计过了不久就又忘了,心痛。是我记忆太差了吗?明天就可以把书还回去啦,完美。感谢这本书的作者,Stoyan Stefanov。学习了。