• JavaScript语言知识收藏


     接触Web开发也已经有一段时间了,对javascript的认识也比以前有了更加深入的认识了,所以觉得应该整理一下。

    一、JavaScript不支持函数(方法)的重载,用一个例子证明如下: 
    function add(number) 

        alert('hello'); 


    function add(number1, number2) 

        alert('world'); 

    此时调用add(1),会弹出'world',而不是'hello',由此现象说明写在文档后面的方法会覆盖掉前面的方法,所以有一个我认为暂时是正确的原则,就是如果方法名相同,则以后面对方法为主。 

    二、JavaScript中函数(方法)就是一个对象,这里就不解释了,看一个例子比较直观 
    function add(number) 

        alert('hello'); 

    是等价于下面这种写法的 
    var add = new Function("number","alert('hello')"); 
    以此类推 
    function add(number1, number2) 

        alert('world'); 

    等价于 
    var add = new Function("number1","number2","alert('world')"); 
    这里一和二都是一样的,只是写法不同,底层是一样的,所以可以把JavaScript的不支持重载的现象按照面向对象的概念来理解:首先add对象指向第一个Function对象,而后引用的对象改变了,指向了第二个新的Function对象了。示意图如下

     所以可以得出一个这样的结论:JavaScript中的每个函数function都是new出来的Function对象。 
       
    三、如果在调用某个JavaScript函数的时候,没有给函数中的参数传值,则参数为undefined,例子如下: 
    function add(number) 

        alert(number); 
        alert(number + 30); 

    当在触发处调用add()的时候,显然没有传入参数值,此时先弹出undefined(未定义), 
    然后弹出NaN(不是一个数Not A Number) 

    四、arguments是每个函数的内置对象,应用这个内置对象可以模拟面向对象的重载功能,例如 
    function sum() 

        if(1 == arguments.length) 
        { 
            alert(arguments[0]); 
        } 
        else if(2 == arguments.length) 
        { 
            alert(arguments[0] + arguments[1]); 
        } 
        else if(3 == arguments.length) 
        { 
            alert(arguments[0] + arguments[1] + arguments[2]); 
        } 

    调用如下: 
    sum(1);    =>    1 
    sum(1, 2);    =>    3 
    sum(1, 2, 3);    =>    6 

    五、由上面的例子又可以得到,JavaScript的函数就是Function的对象,函数都有一个length属性,表示函数接收参数的个数。证明如下: 
    function add() {.....} 
    function minus(num) {....} 
    function multiply(num1, num2) {.....} 
    调用如下: 
    alert(add.length)    =>    0 
    alert(minus.length)    =>    1 
    alert(multiply.length)    =>    2 

    六、JavaScript中有五种原始值,可以理解为原生数据类型(这里仅仅是值JavaScript的,不同于3GL语言),它们分别是:Undifined,Null,Boolean,Number,String 
    (1)Undefined数据类型的值只有一个:undefined,这里要注意一点就是,对于JavaScript中的变量,如果只声明,而没有赋值,则该变量的值为undefined。 
    例如:var s;    alert(s);   此时弹出的是undefined 

    (2)Null数据类型的值只有一个:null 

    (3)Boolean数据类型的值有两个:true和false 

    (4)任何整数或者浮点数都是Number数据类型中的值,另外typeof(..)函数会返回参数的类型名称,例如: 
    var s;   alert(typeof(s));     弹出undefined 
    var a = 1;    alert(typeof(a));    弹出number 
    var b = 'hello';    alert(typeof(b));    弹出string     双引号表示原始类型在栈里 
    而var c = new String("hello");    alert(typeof(c));    弹出object,是在堆中的对象了 

    (5)一个函数如果不返回值,则返回'undefined',typeof(..)返回的值是字符串类型的,证明如下: 
    function aa() {..//里面没有return出值..}         alert(aa()); 会弹出undefined 

    function bb() {....;   return;  }      alert(bb);会弹出bb函数体{}中的所有源代码内容 

    (6)使用没有声明,并且没有赋值的变量会报错,例如, 
    var s;    alert(s2);  因为s2没有声明也没有赋值,所以会报错 
    alert(typeof(s));  弹出undefined 
    alert(typeof(s2));  尽管s2没有声明也没有赋值,但会弹出undefined 

    由此可以归纳出,typeof(..)的返回值有五个:undefined,boolean,number,string,object; 

    (7)null与undefined的关系:undefined实际上是从null派生而来的,证明如下, 
    alert(undefined == null);    会弹出true 

    (8)在函数体内加不加var的区别:如果在函数体的内部,变量不加var,则默认该变量为全局变量,证明如下: 
    function test() 

        var s = 'hello'; 

    test(); 
    alert(typeof(s));此时会返回undefined 
    然而 
    function test() 

        s = 'hello'; 

    test(); 
    alert(typeof(s));会弹出string 
    alert(s);会弹出hello 
    由此可知,对于函数定义中的变量来说,加var表示局部变量,不加var表示全局变量。 

    (9)强制类型转换有三种:Boolean(value),Number(value),String(value) [这里可以看作函数] 
    例如, 
    var s = Boolean(null);    alert(s); 会弹出false 
    var s = Boolean("");     alert(s);会弹出false 
    var s = Boolean("a");   alert(s);会弹出true 
    new Boolean(),new String("..."),new Number("...")都是object类型的 

    (10)在JavaScript中,Object是所有类的父类,类似于高级语言java 
    var s = new Object(); 
    alert(s);    弹出[object Object] 
    alert(typeof(s)); 弹出object 
    alert(s.propertyIsEnumerable("prototype"));弹出false,这里是判断s中的属性是否可以枚举出来 

    遍历window对象中的所有属性 
    for(var temp in window) 

        alert(temp); 


    delete操作和JavaScript中的晚绑定: 
    var o = new Object(); 
    o.name = "scott"; 
    alert(o.name);   //会弹出scott 
    delete(o.name); //删除晚绑定的name属性 
    alert(o.name); //会弹出undefined 

    七、JavaScript的面向对象的特性: 
    (1)JavaScript是基于ECMAScript的,构造对象时可以直接用名字,例如 
    var object = new Object;       <=>        var object = new Object(); 
    var s = new String;            <=>         var s = new String(); 
    var date = new Date;         <=>        var date = new Date(); 
    尽管如此,还是建议加上括号,增加可读性!!!! 

    (2)JavaScript中的数组,长度可以动态的增加,类似于java中的ArrayList,例如 
    var array = new Array();        <=>      var array = [ ]; 
    array.push(1); 
    array.push(2); 
    array.push(3); 
    alert(array.length); //弹出3 
    这里也可以用var array = [1,2,3];    alert(array.length); //弹出3 

    (3)数组对象有一个方法sort(),可以对数组进行升序排序,例如 
    var array = [3,2,1]; 
    array.sort(); 
    alert(array); //弹出[1,2,3] 
    咋一看,很爽,但是 
    var array = [1,3,21]; 
    array.sort(); 
    alert(array); //弹出[1,21,3] 
    原因就在于:sort()方法对数组进行排序的时候,首先将数组中的每一个元素都转化为字符串,即调用每个元素的toString()方法,然后用字符串的ASCII码进行比较! 所以'21' < '3'很正常! 
    另外,sort()可以接受一个排序的函数作为参数,根据参数排序,类似于java中的compare()方法 
    例如, 
    function compare(num1, num2) 

        var temp1 = parseInt(num1); 
        var temp2 = parseInt(num2); 
        return temp1 - temp2; 

    var array = [3,1,21]; 
    array.sort(compare); 
    alert(array);  //弹出[1,3,21] 
    这里还可以用匿名函数的方法,类似于java中的匿名类 
    array.sort(function(num1, num2) { 
        var temp1 = parseInt(num1); 
        var temp2 = parseInt(num2); 
        return temp1 - temp2; 
    }); 

    (4)对象的属性方式:[1]早绑定 [2]玩绑定
    所谓早绑定,就是在对象生成之前绑定好的属性,例如,
    var object = new Object();
    object.name = "scott";
    alert(object.name);

    所谓晚绑定,就是对生成好的对象增加或减少它的属性,例如,
    object.hello = function() { alert('welcome'); }
    object.hello();  //此时会调用object的hello方法,弹出welcome
    delete object.hello();  //删除方法
    object.sayName = function() { alert(this.name); }  //这里this指的是object对象,类似于java一样
    object.sayName();  //此时会弹出scott
    object.sayName = function(name) {   //绑定一个传参数的方法
        this.name = name;
        alert(this.name);
    }
    object.sayHello('tiger');   //此时弹出tiger

    =================================================================

    一、用工厂方式定义对象(类),这里是参照java的设计模式的工厂模式写的,例子如下

    function createObject()
    {
        var object = new Object();  //这里请加上var,因为是方法体内部的局部变量
        object.username = "scott";
        object.password = "tiger";

        object.get = function()
        {
            alert("username: " + this.username + "/npassword: " + password);
        }
        return object;
    }
    调用如下,
    var o = createObject();
    o.get();  //此时会弹出username: scott
              //         password: tiger
    该方法的好处是凡是学要对象了,不需要自己new一个出来,直接可以通过createObject生成对象,具体的细节都被封装起来了~  

    上面的工厂方式固然有优点,但是生成的对象属性都被默认写死成scott和tiger了,所以可以改良成如下带参数的工厂方法,例子如下,
    function createObject(username, password)
    {
        var object = new Object();
        object.username = username;
        object.password = password;

        object.get = function()
        {
            alert("username: " + this.username + "/npassword: " + password);
        }
        return object;
    }
    调用如下,
    var o = createObject("scott","tiger");
    o.get();
    该方法的好处比起一楼的方式,就是更灵活的控制了要生成的对象。

    然而对于以上两种工厂方式,方法get()定义在createObject()函数的内部,从性能上考虑,没创建一个对象,就要生成一个get的function对象,但是在高级语言java中所有的对象都共同的用同一个方法,需要注意到是在JavaScript中get方法不是如此,工厂每次生成对象的时候,都会为get再生成一次相同的对象,比较消耗内存,因此,可以将get方法的定义放在createObject之外。例如,

    function get()
    {
        alert("username: " + this.username + "/npassword: " + this.password);
    }

    function createObject()
    {
        var object = new Object();
        object.username = "scott";
        object.password = "tiger";
        object.get = get;
        return object;
    }
    调用方法一样的,有点就是优化了性能,功能还是一样~

    二、构造函数的方式
    function Person()
    {
        this.username = "scott";
        this.password = "tiger";
        this.get = function()
        {
            alert("username: " + this.username + "/npassword: " + this.password);
        }
    }
    用这种方法定义比较直观,与Java中生成对象很类似了,调用如下,
    var person = new Person();
    person.get();

    注解:当调用new Person()的时候,执行流程跳到了函数中去了,在执行第一行代码之前,会生成一个对象,而this则会指向该对象,虽然没有return该对象,但是此构造函数隐式地将对象return出去了;

    另外,传递参数也是类似的,内部函数的定义也可以改良从而降低对内存的消耗,将它拿到构造函数外面单独定义,所以可以改写成如下,
    function get()
    {
        alert("username: " + this.username + "/npassword: " + this.password);
    }

    function Person(username, password)
    {
        this.username = username;
        this.password = password;
        this.get = get;
    }

    以上这种方式还是不够直观,有另一种解决方案如下, 

    原型方式创建类:prototype 
    function Person(){ } 
    Person.prototype.username = "scott"; 
    Person.prototype.password = "tiger"; 
    Person.prototype.get = function() 
    { alert("username: " + this.username + "/npassword: " + this.password); } 
    调用方法: 
    var p = new Person(); 
    p.get(); 

    但是这里使用prototype方法生成对象,不能创建的时候初始化值,必须等对象创建出来以后,对属性修改。 
    var person1 = new Person(); 
    var person2 = new Person(); 
    person1.username = 'hello'; 
    person1.get();   //hello tiger 
    person2.get();   //scott tiger

     

     JavaScript中的字符串也是不可变的,与java机制中一样,属于final类型的,字符串的拼接一会生成新对象

    如果Person.prototype.username = new Array(); //如下面一楼贴出的图片person1和person2会共享scott
        person1.username.push("scott");
        person1.get(); //scott
        person2.get(); //scott

     

     混合的构造函数与原型方式,属性采用构造函数的方式定义,方法采用原型方式定义(这里比较推荐这种方式)
    可以避免上面的共享属性的弊端,例如,
    function Person(username,password)
    {
        this.username = username;  //这里如果this.username = new Array(); 则新对象不会共享username
        this.password = password;
    }
    Person.prototype.get = function()
    {
        alert("username: " + this.username + "/npassword: " + this.password);
    }
    调用方法:
    var p = new Person("scott","tiger");
    p.get();

    另外还有一种方式:动态的原型方式
    function Person()
    {
        this.username = "scott";
        this.password = "tiger";
        if(typeof Person.flag == "undefined")  //或者Person.flag == undefined
        {
            Person.prototype.get = function()
            {
                alert("username: " + this.username + "/npassword: " + this.password);
            }
            Person.flag = true;
        }
    }

    下面来看看用JavaScript模拟java的继承特性
    (1)继承的第一种方式:对象冒充
    function Parent(username)
    {
        this.username = username;
        this.hello = function()
        { alert("username: " + this.username); }
    }

    function Child(username,password)
    {
        this.method = Parent;
        this.method(username);
        delete this.method;
        this.password = password;
        this.world = function()
        { alert("password: " + this.password); }
    }

     

     根据上图,和带下划线的代码段,method属性作为桥梁引用Parent对象,调用Parent的构造函数后,删除了该属性!!
    注意如果吧带下划线的代码段替换为Parent(username);是不行的,因为这样的话Parent中的hello()方法不能继承下来~

     调用上面的继承
    var parent = new Parent('father');
    var child = new Child('son','scott');

    parent.hello(); //father
    child.hello();  //son
    child.world();  //scott

    由此可见继承机制确实实现了!!!!

    (2)继承的第二种方式:call()方法
    这里先介绍call()方法:每个function,即Function对象都有call()这个方法,call(param1,param2,...),
    param1表示调用call()方法的函数内部的this,param2,...对应调用call()方法的函数中的参数列表,例如,

    function test(str)
    {
        alert(this.name + " " + str);
    }
    var obj = new Object();
    obj.name = 'scott';
    test.call(obj,'tiger'); //这里将obj对象赋给test中的this,弹出scott tiger


    了解了call()的功能以后,我们来用call()实现继承机制,例子如下:

    function Parent(username)
    {
        this.username = username;
        this.hello = function()
        {
            alert(this.username);
        }
    }

    function Child(username, password)
    {
        Parent.call(this,username);
        this.password = password;
        this.world = function()
        { alert(this.password); }
    }

    调用方法类似,这里就省略了。。。

    (3)继承的第三种方式:apply()方式
    这里对比一下apply()和call()
    call(parm1,parm2,...,parmN)  多个参数

    apply(parm1,new Array())  <=> apply(parm1,[parm2,...,parmN])  两个参数

    归纳一下,apply方法的第一个参数和call一样,第二个参数是call后面参数组成的一个数组

    下面用apply()来实现继承的机制,如下:
    function Parent(username)
    {
        this.username = username;
        this.hello = function()
        { alert(this.username); }
    }

    function Child(username,password)
    {
        Parent.apply(this,new Array(username));  //等价于Parent.apply(this,[username]);
        this.password = password;
        this.world = function()
        { alert(this.password); }
    }

    (4)继承的第四种方式:原型链方式
    function Parent() { }
    Parent.prototype.hello = "hello";
    Parent.prototype.sayHello = function()
    { alert(this.hello); }

    function Child() { }
    Child.prototype = new Parent();
    Child.prototype = "world";
    child.prototype.sayWorld = function()
    {
        alert(this.world);
    }

    调用一下:
    var child = new Child();
    child.sayHello();  //hello
    child.sayWorld();  //world
    (5)继承的第五种方式:混合方式(最佳实践,推荐使用)

    function Parent(hello)
    {
        this.hello = hello;
    }

    Parent.prototype.sayHello = function()
    { alert(this.hello); }

    function Child(hello,world)
    {
        Parent.call(this,hello);
        this.world = world;
    }

    Child.prototype = new Parent();
    Child.prototype.sayWorld = function()
    { alert(this.world); }

    调用一下:
    var child = new Child('hello','world');
    child.sayHello();  //hello
    child.sayWorld();  //world

    最后举个例子来应用JavaScript的继承机制的应用

    function Shape(edge) //一个抽象的形状
    {
        this.edge = edge;
    }

    Shape.prototype.getArea = function() //获取形状的面积,类似于接口中的方法,这里先返回-1
    { return -1; }

    Shape.prototype.getEdge = function() //返回形状的边有多少条
    { return this.edge; }

    下面定义子类,三角形
    function Triangle(bottom,height) //三角形,出入参数为底边和高
    {
        Shape.call(this,3);
        this.bottom = bottom;
        this.height = height;
    }
    Triangle.prototype = new Shape();
    Triangle.prototype.getArea = function() //返回三角形的面积,覆盖父类的方法
    { return 0.5 * this.bottom * this.height; }

    调用三角形的对象和方法:
    var triangle = new Triangle(10,4);
    alert(triangle.getEdge()); //3
    alert(triangle.getArea()); //20

    下面再定义一个四边形
    function Rectangle(bottom, height)
    {
        Shape.call(this,4);
        this.bottom = bottom;
        this.height = height;
    }
    Rectangle.prototype = new Shape();
    Rectangle.prototype.getArea = function()
    { return this.bottom * this.height; }

    调用四边形的对象和方法
    var rectangle = new Rectangle(10,20);
    alert(rectangle.getEdge());  //4
    alert(rectangle.getArea());  //200

  • 相关阅读:
    python模块安装路径
    yum软件搜索
    项目里用到的python知识点
    python调用C函数
    opencv VideoCapture使用示例
    Django模型层之多表操作
    博客园 装饰
    mysql条件查询-排除null ---oracle、mysql 区分总结
    Android——Fragment详解
    Android——监听事件总结
  • 原文地址:https://www.cnblogs.com/roucheng/p/3453066.html
Copyright © 2020-2023  润新知