zoukankan      html  css  js  c++  java
  • JS函数与面向对象

    本文摘自北风网CJ讲的javascript+jquery+ajax教程。摘以自娱。

    函数是一组可以随时随地运行的语句。

    创建函数

    function fnOne() {//具有名称的函数,函数名必须符合变量名命名规范
            //可以没有符何语句
        }
        var fnTwo = function () {//匿名函数
        };
        function () {//创建匿名函数而不立即创建其引用,那么之后就没办法调用此函数
        }
        (function fnThree() {
        })();//创建函数并立即执行一次
        (function () {})();//创建匿名函数并立即执行一次

    匿名函数与命名函数的区别

       fnOne();//不会出错,使用function创建的具有名称的函数在任何与之相同作用域的地方都能调用
        fnTwo();//出错
        var fnTwo =function () {};//因为只有执行了这个赋值语句后,fnTwo才会被创建
        function fnOne() {}

    函数返回值

    function fnTest() {
            return "value";//使用return来返回值
            alert("Hello!!!");//执行了return之后,函数就会退出 
        }

    函数参数

    function fnTest(arg1,arg2,arg3) {
            alert(arg1+"\n"+arg2+"\n"+arg3);
        }
    fnTest(1,2,3);
    fnTest(1,2);//没有传值过去时,就会是undefined

     arguments对象:在函数执行时函数内部就会有arguments对象,它包含了所有的参数,arguments的length属性报告了传入参数个数

    function fnTest() {
            for (var i=0;i< arguments.length;i++) {
                alert(arguments[i]);
            }
        }
        fnTest(1,2,3);
        fnTest(45);

    使用arguments对象模拟函数重载

    function fnTest() {
            var args = arguments;
            switch (arguments.length) {
                case 0 :
                    return "没有输入!!!";
                case 1 :
                    return "一个参数:"+args[0];
                case 2 :
                    return "二个参数:"+args[0]+" 和 "+ args[1];
            }
        }
        alert(fnTest());
        alert(fnTest(1));
        alert(fnTest(2));

    arguments对象补充:arguments对象的callee属性指向它所在的函数

    function fnTest() {alert(arguments.callee);}

    闭包

    "闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。" 请理解透并牢牢记住这句话,否则你就可能永远不知道什么是闭包,理解好,其实闭包还是蛮简单的。-----摘者注。

    在 ECMAScript 中使用全局变量是一个简单的闭包实例。请思考下面这段代码:

    var msg = "我是全局变量!!!";
        function say() {
          alert(msg);
        }
        say();

    在ECMAScript中,在函数声明处向函数外部看到的声明的所有变量,在函数内部都能访问到它们的最终值!

    var g = "全局变量!!!";
        function fnA() {
            var a="A";
            function fnB() {
                var b="B";
                alert(a);//可以访问到a
                alert(c);//但不以访问c
                function fnC() {
                    var c = "C";
                    alert(a+"\n"+b);//只要遵循从里向外看的原则,看到的变量都可以访问到
                }
            }
        }
        //更复杂的闭包
        function fnTest(num1,num2) {
            var num3 = num1+num2;
            return function () {
                alert("num1+num2结果为"+num3);
            };
        }
        var result = fnTest(23,56);
        result();

    闭包函数只能访问变量的最终值!!!

    function fnTest(arr) {
            for (var i=0;i < arr.length;i++) {
                arr[i]=function () {
                    alert(i+" | "+arr[i]);
                };
            }
        }
        var arr = [0,1,2,3,4,5];
        fnTest(arr);
        for (var i=0;i < arr.length;i++) {
            arr[i]();//始终输出6还有一个undefined
            //因为函数退出后,i值为6,所以访问到的值只有6
        }
    //我开始一看感觉应该不怎么复杂,不过只细看过后,再运行过后,感觉还真不简单呢!很意思的一段代码。

    不但在闭包中可以访问闭包外的变量值,而且还可以设置它的值

    function fnTest() {
            var a=123;
            return {
                set:function (param) {a = param},
                get:function () {return a}
            };
        }
        var obj = fnTest();
        alert(obj.get());//123
        obj.set(4);
        alert(obj.get());//4

    对象,构造函数

    创建一个对象

    var obj = new Object();
        alert(obj);
        alert(Object);//一个函数
        Object();//可以直接执行
        //构造函数也是一个普通的函数
        function Demo() {
        }
        var d = new Demo();//不会出错,使用new运算符来创建对象实例
        alert(d);//object

    this关键字的用法

    function Demo() {
            this.property = "属性!!!";
        }
        d = new Demo();
        alert(d.property);//属性!!!

    不使用new而直接执行构造函数时,this指向window

    function Demo() {
            this.property = "属性!!!";
        }
        var d = Demo();
    alert(d.property);
    //undefined alert(window.property);//属性!!!

    可以给构造函数传递参数,然后可以将参数赋值给对象的属性

    function Person(name,age) {
            this.name = name;
            this.age = age;
        }
        var p1 = new Person("CJ",18);

    instanceof 运算符,用来判断对象是否是某个类(虽然ECMAScript中并不存在类,但我们在这里依然使用这一术语)的实例

    var str = new String("string");
        alert(str instanceof String);//true
        var arr = new Array();
        alert(arr instanceof Array);//true
        function Demo() {}
        var d = new Demo();
        alert(d instanceof Demo);//true

    面向对象术语

    一种面向对象语言需要向开发者提供四种基本能力:

    • 封装——把相关的信息(无论数据或方法)存储在对象中的能力。
    • 聚集——把一个对象存储在另一个对象内的能力。
    • 继承——由另一个类(或多个类)得来类的属性和方法的能力。
    • 多态——编写能以多种方法运行的函数或方法的能力。

    ECMAScript支持这些要求,因此可被看作面向对象的。

    封装与私有属性:封装并不要求私有!

    function Person(name,age) {
            this.name = name;//将值存储为对象的属性即是封装
            this.age = age;
        }
        var p1 = new Person("CJ",18);

    ECMAScript目前版本并不支持私有属性,但可以通过闭包来模拟

    function Person(name,age) {
            this.getName = function () {return name};
            this.setName = function (param) {name=param};
            this.getAge = function () {return age};
            this.setAge = function (param) {age=param};
        }
        var p1 = new Person("CJ",18);
        alert(p1.name);//undefined
        alert(p1.getName());//CJ
        p1.setName("XXX");
        alert(p1.getName());//XXX

    继承:prototype属性

    ECMAScript中,继承是通过构造函数的prototype属性实现的

    function Person(name,age) {
            this.name=name;
            this.age = name;
        }
        alert(Person.prototype);//object
        Person.prototype.sort = "人";
        var p1 = new Person("CJ",18);
        alert(p1.sort);//所有的Person对象的实例继承了sort这个属性

    所有对象都有一个方法isPrototypeOf(),用来判断它是不是另一个对象的原型

    function Person() {}
        var p1 = new Person();
        alert(Person.prototype.isPrototypeOf(p1));//true    P1的原型是不是Person

    在ECMAScript中让一个类继承另一个类的方式比较特殊 

    function ClassA() {
            this.a = "A";
        }
        function ClassB() {
            this.b = "B";
        }
        ClassB.prototype = new ClassA(); //让ClassB继承ClassA
        var b = new ClassB();
        alert(b.a);//"A",继承了属性a
        alert(b instanceof ClassB);//true
        alert(b instanceof ClassA);//true,因为继承,b也是ClassA的后代
        alert(ClassB.prototype.isPrototypeOf(b));//true
        alert(ClassA.prototype.isPrototypeOf(b));//true,ClassA.prototype也是b的原型

    然而这样的继承有个注意点——

    function ClassA() {
            this.a = "A";
        }
        function ClassB() {
            this.b = "B";
        }
        var b = new ClassB();//先实例化ClassB
        ClassB.prototype = new ClassA();//再去继承ClassA,将prototype重置为另一个对象
        alert(b instanceof ClassB);//false
        alert(b instanceof ClassA);//false
        alert(ClassB.prototype.isPrototypeOf(b));//false
        alert(ClassA.prototype.isprototypeOf(b));//false

    当构造函数需要参数时

    function Person(name,age) {
            this.name = name;
            this.age = age;
        }
        function Teacher(name,age,lesson) {
            this.tempMethod = Person;//对象冒充
            this.tempMethod(name,age);
            //当执行Person时,由于是在Teacher某个实例上调用的,所以在Person函数中的this指向了Teacher的实例
            delete this.tempMethod;//删除临时方法
            this.lesson = lesson;
        }
        ClassB.prototype =new ClassA();//始终不应在继承时放参数
        var t1 = new Teacher("HUXP",18,"C#");
        alert(t1.name+" | "+ this.age+ " | "+this.lesson);

    事实上,对于对象冒充,ECMAScript提供了更简洁的内置方法call,在每个函数上调用,第一个参数即为要冒充的对象,剩下的是函数需要的其它参数

    function Demo(arg) {
            this.name = arg;
        }
        var obj = new Object();
        Demo.call(obj,"name");
        alert(obj.name);//"name"
        //使用call重写上面继承的例子
        function Person(name,age) {
            this.name = name;
            this.age = age;
        }
        function Teacher(name,age,lesson) {
            Person.call(this,name,age);//对象冒充
            this.lesson = lesson;
        }

    静态属性与Function类

    在ECMAScript里有个有趣的地方是,函数本身也是对象(和数组也一样),也可使用new来创建.Function构造函数至少要传两个字符串参数,可以是空字符串。除了最后一个字符串会被当做函数体语句去执行,其它参数都会作为函数参数变量名! 

    var fn = new Function();//一个空函数
        //创建有内容的函数
        fn = new Function("arg1","alert(arg1)");//最后一个参数为执行语句的字符串,前面参数全是函数要用到的参数
        //上面的代码等效于
        fn = function (arg1) {alert(arg1)};//同样,由于都是赋值语句,所以要注意出现次序
        fn.property ="既然是对象,那么就要以添加属性"

    事实上,在构造函数上添加的属性就被称之为静态属性,它不会被实例所继承 

    function ClassDemo() {
        }
        ClassDemo.property = new Array();
        var d =new ClassDemo();
        alert(d.property);//undefined
        alert(ClassDemo.property);//object

    Function类的实例还有其它一些方法和属性(当然,使用function关键字声明的函数也是一样的) 

    function outer() {
            inner();
            function inner() {
                alert(inner.caller);
                //函数的caller属性指向调用自身的上下文函数,这里指向outer
            }
        }
        function applyTest() {
            var args = arguments;
            this.name = args[0];
            this.age=args[1];
        }
        var obj = new Object();
        applyTest.apply(obj,["name",18]);
        alert(obj.name);
        alert(obj.age);
        //apply方法与call方法类似,也用于对象冒充,只是apply方法只有两个参数
        //第一个是要冒充的对象,第二个是所有参数组成的数组

     感谢你的阅读。

    欢迎访问草根帮【https://www.caogenbang.top】 草根帮带你走向人生巅峰,迎娶白富美!!!
  • 相关阅读:
    Hibernate Tomcat JNDI数据源配置(转)
    使用Spring的@Autowired 实现DAO, Service, Controller三层的注入(转)
    丢弃重口味的xml配置--spring4用groovy配置bean(转)
    Java 对象的生命周期
    设计模式学习总结(23) 中介者模式
    WebSocket初探
    设计模式 之 建造者
    谈谈CListCtrl 扩展风格设置方法-SetExtendedStyle和ModifyStyleEx 比較
    linux signal 处理
    UVA 1546
  • 原文地址:https://www.cnblogs.com/koeltp/p/2676028.html
Copyright © 2011-2022 走看看