JavaScript學習----初步

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>JavaScript Study 2015.11.9--</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type="text/css">  

    </style>
    
    <script type="text/javascript">
    
     //JavaScript = ECMAScript(function,closure,OO) + DOM + BOM
    
        /*
        var sColor = "red";
        //alert(sColor.length);    //輸出 "3"
        
        var bFound = false;
        //alert(bFound.toString());    //輸出 "false"

        var iNum1 = parseInt("12345red");    //返回 12345
        var iNum1 = parseInt("red12345");  //返回 NaN
        //alert(iNum1);
        //alert(inum1); // error: inum1 is not defined
        var iNum1 = parseInt("0xA");    //返回 10
        var iNum1 = parseInt("56.9");    //返回 56
        var iNum1 = parseInt("red");    //返回 NaN


        //解析16進制的值, 第二個參數
        var iNum1 = parseInt("AF", 16);    //返回 175
        //alert(iNum1);
        //2進制
        var iNum1 = parseInt("10", 2);    //返回 2
        //8進制
        var iNum2 = parseInt("10", 8);    //返回 8
        //10進制
        var iNum3 = parseInt("10", 10);    //返回 10
        
        //若是10進制數,包含0做前導,最好使用第二個參數爲10
        var iNum1 = parseInt("010");    //返回 8
        var iNum2 = parseInt("010", 8);    //返回 8
        var iNum3 = parseInt("010", 10);    //返回 10

        
        
        var b1 = Boolean("");        //false - 空字符串
        var b2 = Boolean("hello");        //true - 非空字符串
        var b1 = Boolean(50);        //true - 非零數字
        var b1 = Boolean(null);        //false - null
        var b1 = Boolean(0);        //false - 零
        var b1 = Boolean(new Object());    //true - 對象

        
        
        
        ECMAScript 中可用的 3 種強制類型轉換以下:
        Boolean(value) - 把給定的值轉換成 Boolean 型;
        Number(value) - 把給定的值轉換成數字(能夠是整數或浮點數);
        String(value) - 把給定的值轉換成字符串;
        
        
        
        var b1 = Boolean("");        //false - 空字符串
        var b2 = Boolean("hello");        //true - 非空字符串
        var b3 = Boolean(50);        //true - 非零數字
        var b4 = Boolean(null);        //false - null
        var b5 = Boolean(0);        //false - 零
        var b6 = Boolean(new Object());    //true - 對象
        
        document.write(b1+"<br>");
        document.write(b2+"<br>");
        document.write(b3+"<br>");
        document.write(b4+"<br>");
        document.write(b5+"<br>");
        document.write(b6+"<br>");
        
        //特別注意
        document.write(Number(false)+"<br>");//    0  
        document.write(Number(true)+"<br>");//        1  
        document.write(Number(undefined)+"<br>");//        NaN  
        document.write(Number(null)    +"<br>");//    0
        document.write(Number("1.2")+"<br>");//        1.2
        document.write(Number("12")+"<br>");//        12
        document.write(Number("1.2.3")+"<br>");//        NaN
        document.write(Number(new Object())+"<br>");//        NaN
        document.write(Number(50)    +"<br>");//    50

        var s1 = String(null);    //"null"
        var oNull = null;
        var s2 = oNull.toString();    //會引起錯誤
        
        //兩種方式均可以
        var obj = new Object;
        var obj1 = new Object();
        
        
        Object 對象具備下列屬性:
        constructor
        對建立對象的函數的引用(指針)。對於 Object 對象,該指針指向原始的 Object() 函數。
        Prototype
        對該對象的對象原型的引用。對於全部的對象,它默認返回 Object 對象的一個實例。
        Object 對象還具備幾個方法:
        hasOwnProperty(property)
        判斷對象是否有某個特定的屬性。必須用字符串指定該屬性。(例如,o.hasOwnProperty("name"))
        IsPrototypeOf(object)
        判斷該對象是否爲另外一個對象的原型。
        PropertyIsEnumerable
        判斷給定的屬性是否能夠用 for...in 語句進行枚舉。
        ToString()
        返回對象的原始字符串表示。對於 Object 對象,ECMA-262 沒有定義這個值,因此不一樣的 ECMAScript 實現具備不一樣的值。
        ValueOf()
        返回最適合該對象的原始值。對於許多對象,該方法返回的值都與 ToString() 的返回值相同。
*/


        
        /*
        
        //函數
        
        function sayHi() {
          if (arguments[0] == "bye") {
            return;
          }

          alert(arguments[0]);
        }

        //下面的調用方式都不報錯
        sayHi();
        sayHi("hehe");

        
        function howManyArgs() {
          alert(arguments.length);
        }

        howManyArgs("string", 45);
        howManyArgs();
        howManyArgs(12);

        
        
        //模擬函數重載
        function doAdd() {
          if(arguments.length == 1) {
            alert(arguments[0] + 5);
          } else if(arguments.length == 2) {
            alert(arguments[0] + arguments[1]);
          }
        }

        doAdd(10);    //輸出 "15"
        doAdd(40, 20);    //輸出 "60"
        
    
        
        function doAdd(){
          var j =0;
           for(var i=0;i<arguments.length;i++){
            j= j+ arguments[i];
           }
           alert(j); 
        }
        
        doAdd(20);
        doAdd(20,40);


            
            
        
        //函數的覆蓋
        function doAdd(iNum) {
          alert(iNum + 20);
        }

        function doAdd(iNum) {
          alert(iNum + 10);
        }

        doAdd(10);    //輸出 "20"
        
        var doAdd = new Function("iNum", "alert(iNum + 20)");
        var doAdd = new Function("iNum", "alert(iNum + 10)");
        doAdd(10);

    //畫出內存結構
    function fn(){
        return 100;
    }
    //x 指向 fn 所指向的內存區域
    var x = fn;
    
    var y = fn();
    var z = x();


    //定義對象
  function Person(name,age,address){
       this.name = name;
       this.age = age;
       this.address = address;
       this.say = function(){
            alert(this.name+","+this.age+","+this.address);
       }
  }
  var p1 = new Person("p1",23,"bj");
  var p2 = new Person("p2",24,"nj");
  //存在的問題:
  //每建立一個對象p,都會在內存中有一份Person的say function拷貝,會致使內存空間的浪費。
  //而實際的對象的建立,應該是:每建立一個對象p,只會建立一個變量,指向內存中的say function的同一區域。
  //p1.say();
 // p2.say();
  
  
  
  //定義對象的方式1:
  function Person(name,age){
     this.name = name;
     this.age = age;
  }
  
  Person.prototype.say = function(){
    alert(this.name+","+this.age);
  }
  
  var p1 = new Person("p1",20);
  p1.say();
  var p2 = new Person("p2",21);
  p2.say();
  
 
  
  //定義對象的方式2:
 
 
 
 person = new Object();
 person.name = "li";
 person.age = 34;
 person.say= function(){alert(person.name);}
 
 person.say();
  
 //定義對象的方式3:
 
 person={
     name:"li",
     age:34,
     say:function(){
     alert(this.name);
     }
 }
 person.say();
 
  
  var person ={
    name:"li",
    age:34,
    say:function(){
        alert(this.name);
    }
  }
 
 for(x in person){
    alert(x);  // name,age,say
 }
 */
 
 
 
  
  
  
  
  /*
  //http://www.jb51.net/article/24101.htm
  //閉包
  閉包,指的是詞法表示包括不被計算的變量的函數,也就是說,函數可使用函數以外定義的變量。
  //做用:
  一個是前面提到的能夠讀取函數內部的變量,
  另外一個就是讓這些變量的值始終保持在內存中。
  //何時使用:
   一、保護函數內的變量安全。以最開始的例子爲例,函數a中i只有函數b才能訪問,而沒法經過其餘途徑訪問到,所以保護了i的安全性。
   二、在內存中維持一個變量。依然如前例,因爲閉包,函數a中i的一直存在於內存中,所以每次執行c(),都會給i自加1。
   三、經過保護變量的安全實現JS私有屬性和私有方法(不能被外部訪問)
    私有屬性和方法在Constructor外是沒法被訪問的
    function Constructor(...) {  
      var that = this;  
      var membername = value; 
      function membername(...) {...}
    }
    以上3點是閉包最基本的應用場景,不少經典案例都源於此。


 //這是一個最簡單的閉包
 
 var sMessage = "hello closure";
 function sayHelloClosure(){
    alert(sMessage);
 }
sayHelloClosure();
//在上面這段代碼中,腳本被載入內存後,並無爲函數 sayHelloWorld() 計算變量 sMessage 的值。
//該函數捕獲 sMessage 的值只是爲了之後的使用,也就是說,解釋程序知道在調用該函數時要檢查 sMessage 的值。
//sMessage 將在函數調用 sayHelloWorld() 時(最後一行)被賦值,顯示消息 "hello world"。


var iBaseNum = 10;
function addNum(inum1,inum2){
    //定義一個閉包
    function doAdd(){
        return inum1+iNum2+iBaseNum;
    }
    //調用
    return doAdd(); 
}

//這裏,函數 addNum() 包括函數 doAdd() (閉包)。
//內部函數是一個閉包,由於它將獲取外部函數的參數 iNum1 和 iNum2 以及全局變量 iBaseNum 的值。 
//addNum() 的最後一步調用了 doAdd(),把兩個參數和全局變量相加,並返回它們的和。
//這裏要掌握的重要概念是,doAdd() 函數根本不接受參數,它使用的值是從執行環境中獲取的。
//能夠看到,閉包是 ECMAScript 中很是強大多用的一部分,可用於執行復雜的計算。
//提示:就像使用任何高級函數同樣,使用閉包要當心,由於它們可能會變得很是複雜。

  
//這裏很關鍵,也很難理解,須要畫內存圖。
  function foo(x){
    var tmp = 3;
    return function(y){
        alert(x + y + (++tmp) );
    }
  }
  //這裏纔是閉包
  var bar = foo(2); // 至關於 var bar = function(y){alert(2+y+(++tmp));} 但仍是有所不一樣。 
  bar(10);//16
  bar(10);//17  因爲tmp仍存在於bar閉包的內部,因此它仍是會自加1,並且你每次調用bar時它都會自加1.
  
    //閉包的理解:
    //http://kb.cnblogs.com/page/105708/
    
    //Javascript的垃圾回收機制
   在Javascript中,若是一個對象再也不被引用,那麼這個對象就會被GC回收。
    若是兩個對象互相引用,而再也不被第3者所引用,那麼這兩個互相引用的對象也會被回收。
    由於函數a被b引用,b又被a外的c引用,這就是爲何函數a執行後不會被回收的緣由。


    var name = "The Window";   
      var object = {   
        name : "My Object",   
        getNameFunc : function(){   
          return function(){   
            return this.name;   
         };   
        }   
    };   
    
    
    var func = object.getNameFunc(); //返回匿名的閉包函數
    var returnName = func();
    //alert(returnName);
    //alert(object.getNameFunc()());  //The Window   爲何不是: My Object


    function outerFun()
    {
         var a=0;
         function innerFun()
         {
              a++; //a 的值不會被GC回收。
              alert(a);
         }
         return innerFun;  //注意這裏
    }
    
    var obj = outerFun();
    obj();  //結果爲1
    obj();  //結果爲2
    obj(); //3  ....
    
    var obj2 = outerFun();
    obj2();  //結果爲1
    obj2();  //結果爲2

    
    function outerFun()
    {
         var a =0;
         alert(a);  
    }
    var a=4;
    outerFun();//0
    alert(a);//40
    
    
    function outerFun()
    {
         //沒有var 
         a =0;
         alert(a);  
    }
    var a=4;
    outerFun();//0
    alert(a);//0

//做用域鏈是描述一種路徑的術語,沿着該路徑能夠肯定變量的值 .當執行a=0時,由於沒有使用var關鍵字,所以賦值操做會沿着做用域鏈到var a=4;  並改變其值.
   */ 
   //做用域鏈
  // http://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html
  
  
  //OO面向對象
   /*
  function Cat(name,age){
       this.name = name;
       this.age = age;
       this.type = "動物";
       this.say = function(){
         alert(this.name);
       }
  }
  
  var cat1 = new Cat("haha",3);
  var cat2 = new Cat("wwww",4);

  
  上面的定義方式,存在的問題:
  cat1, cat2 ...的
   type, say 都是相同的內容,在new的時候,會給每一個cat1,cat2,都建立一塊內存,用來存儲type,say.
   這就形成了內存空間的浪費。
   可使用下面的改良的方式定義:
  
  
  function Cat(name,age){
     this.name = name;
     this.age = age;
  }
  
  Cat.prototype.type = "動物";
  Cat.prototype.say = function(){
    alert(this.name);
  }
   */
  /*
  上面的定義方式,存在的問題:
  雖然解決了內存空間浪費的問題,但在形式上看起來,並不像java裏的Class的定義方式。
  可使用下面的改良的方式定義:

 function Cat(name,age){
     this.name = name;
     this.age = age;
     if(!this.type)
     Cat.prototype.type = "動物";
     if(!this.say){
         Cat.prototype.say = function(){
            alert(this.name);
        }
    }
  
  }
  
  var cat1 = new Cat("haha",3);
  var cat2 = new Cat("wwww",4);
  
  cat1.say();
  cat2.say();
   */ 
  //繼承
  
  //http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
     /* 
 // 1、 構造函數綁定
//第一種方法也是最簡單的方法,使用call或apply方法,將父對象的構造函數綁定在子對象上,即在子對象構造函數中加一行:
  //父類
   function Animal(){
    this.species = "動物";
  }
  //子類
    function Cat(name,color){
         Animal.apply(this, arguments);//
        this.name = name;
        this.color = color;
      }
  
   var cat1 = new Cat("大毛","黃色");
   alert(cat1.species); // 動物
  
 
  
 // 2、 prototype模式
//第二種方法更常見,使用prototype屬性。
//若是"貓"的prototype對象,指向一個Animal的實例,那麼全部"貓"的實例,就能繼承Animal了。
   //父類
   function Animal(){
    this.species = "動物";
  }
 //子類
    function Cat(name,color){
        this.name = name;
        this.color = color;
      }
  //實現繼承
   Cat.prototype = new Animal();//重寫了Cat.prototype
   Cat.prototype.constructor = Cat;//將新的Cat.prototype.constructor再指向Cat

  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動物
  
  
 
 
 // 3、 直接繼承prototype (有問題)
//第三種方法是對第二種方法的改進。因爲Animal對象中,不變的屬性均可以直接寫入Animal.prototype。因此,咱們也可讓Cat()跳過 Animal(),直接繼承Animal.prototype。
//如今,咱們先將Animal對象改寫:


    function Animal(){}
    Animal.prototype.species = "動物";

//而後,將Cat的prototype對象,而後指向Animal的prototype對象,這樣就完成了繼承。
  
   function Cat(name,color){
        this.name = name;
        this.color = color;
      }
    
    Cat.prototype = Animal.prototype;
    Cat.prototype.constructor = Cat;//這一句實際上把Animal.prototype對象的constructor屬性也改掉了!
    
   var cat1 = new Cat("大毛","黃色");
   alert(cat1.species); // 動物
  //與前一種方法相比,這樣作的優勢是效率比較高(不用執行和創建Animal的實例了),比較省內存。缺點是 Cat.prototype和Animal.prototype如今指向了同一個對象,那麼任何對Cat.prototype的修改,都會反映到Animal.prototype。
  //因此,上面這一段代碼實際上是有問題的。
 
  
  
  //4、 利用空對象做爲中介
//因爲"直接繼承prototype"存在上述的缺點,因此就有第四種方法,利用一個空對象做爲中介。
    
    /*
    function Animal(){}
    Animal.prototype.species = "動物";
    
   function Cat(name,color){
        this.name = name;
        this.color = color;
      }
    
    var F = function(){};
   F.prototype = Animal.prototype;
   Cat.prototype = new F();
   Cat.prototype.constructor = Cat;


   var cat1 = new Cat("大毛","黃色");
   alert(cat1.species); // 動物

  
   //F是空對象,因此幾乎不佔內存。這時,修改Cat的prototype對象,就不會影響到Animal的prototype對象。

   //
   function Animal(){}
    Animal.prototype.species = "動物";
    
   function Cat(name,color){
        this.name = name;
        this.color = color;
      }
    
   function extend(Child, Parent) {
    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.uber = Parent.prototype;
  }

  extend(Cat,Animal);//YUI提供的實現繼承的方式
  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動物

 
//5、 拷貝繼承
//上面是採用prototype對象,實現繼承。咱們也能夠換一種思路,純粹採用"拷貝"方法實現繼承。簡單說,若是把父對象的全部屬性和方法,拷貝進子對象,不也可以實現繼承嗎?這樣咱們就有了第五種方法。
 
  function Animal(){}
    Animal.prototype.species = "動物";
    
   function Cat(name,color){
        this.name = name;
        this.color = color;
      }
    
     function extend2(Child, Parent) {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
      c[i] = p[i];
      }
    c.uber = p;
  }

 extend2(Cat, Animal);
  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動物
*/
/*
//1、什麼是"非構造函數"的繼承?
//好比,如今有一個對象,叫作"中國人"。
    var Chinese = {
        nation:"中國"
    }
    
    var Doctor ={
      career:"醫生"
    }
    
    
//1, object方法
    function object(o) {
        function F() {}  //空對象
        F.prototype = o;  //父對象
        return new F();
    }
//這個object()函數,其實只作一件事,就是把子對象的prototype屬性,指向父對象,從而使得子對象與父對象連在一塊兒。


//2, 淺拷貝方法
//除了使用"prototype鏈"之外,還有另外一種思路:把父對象的屬性,所有拷貝給子對象,也能實現繼承。

    function extendCopy(p){
        var c = {};
        for(var i in p){
            c[i] = p[i];
        }
        return c;
    }
    
    //var Doctor = extendCopy(Chinese);
    //Doctor.career = '醫生';
    //alert(Doctor.nation); // 中國
    
//可是,這樣的拷貝有一個問題。那就是,若是父對象的屬性等於數組或另外一個對象,那麼實際上,子對象得到的只是一個內存地址,而不是真正拷貝,所以存在父對象被篡改的可能。

 Chinese.birthPlaces = ['北京','上海','香港'];
 var Doctor = extendCopy(Chinese);
 Doctor.birthPlaces.push('廈門');
 alert(Doctor.birthPlaces); //北京, 上海, 香港, 廈門
 alert(Chinese.birthPlaces); //北京, 上海, 香港, 廈門

//3, 深拷貝方法 (JQuery使用的實現繼承的方式)

function deepCopy(p,c){
    var c = c || {};
    for(var i in p){
        if(typeof p[i] === 'object'){
            c[i] = (p[i].constructor === Array)? []:{};//? 什麼意思
            deepCopy(p[i],c[i]);//遞歸
        }else{
            c[i] = p[i];
        }
    }
    return c;
}

 Chinese.birthPlaces = ['北京','上海','香港'];
 var Doctor = deepCopy(Chinese);
 Doctor.birthPlaces.push('廈門');
 alert(Doctor.birthPlaces); //北京, 上海, 香港, 廈門
 alert(Chinese.birthPlaces); //北京, 上海, 香港, 廈門
*/





    </script>
  </head>
  <body>
    <div id="wrap">
      
    </div>
  </body>
</html>
相關文章
相關標籤/搜索