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
  //闭包
  闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。
  //作用:
  一个是前面提到的可以读取函数内部的变量,
  另一个就是让这些变量的值始终保持在内存中。
  //什么时候使用:
   1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
   2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
   3、通过保护变量的安全实现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
     /* 
 // 一、 构造函数绑定
//第一种方法也是最简单的方法,使用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); // 动物
  
 
  
 // 二、 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); // 动物
  
  
 
 
 // 三、 直接继承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。
  //所以,上面这一段代码其实是有问题的。
 
  
  
  //四、 利用空对象作为中介
//由于"直接继承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); // 动物

 
//五、 拷贝继承
//上面是采用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); // 动物
*/
/*
//一、什么是"非构造函数"的继承?
//比如,现在有一个对象,叫做"中国人"。
    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>
原文地址:https://www.cnblogs.com/heavyhe/p/4978256.html