javascript_lesson5_面向对象程序设计

来源:互联网 发布:python的print不换行 编辑:程序博客网 时间:2024/06/02 02:07

**学习目标:
了解面向对象程序的特点
学会JS模拟面向对象的方式
理解prototype及其相关应用模型
理解继承
了解常用设计模式**

5.1 面向对象程序设计

面向对象的语言有一个标志,那就是他们都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。但是在ECMAScript中没有类的概念,但是我们可以通过其他方式来模拟面向对象的类。
工厂模式:工厂模式是软件工厂领域中一种广为人知的设计模式。
构造函数模式:比如像ECMAScript中的Array、Object、Date等都是通过构造函数来创建的。

5.2 原型

我们创建的每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
原型对象实际就是一个构造函数的实例对象,与普通的实例对象没有什么本质上的区别,js中每一个对象都有一个原型对象。不过他比较特殊,该对象所包含的所有属性和方法能够供构造函数的所有实例共享,这就是其他语言所说的继承,而javascript通过原型对象来实现继承,简称原型继承。静态原型继承:Object.prototype.[method
field] ; isPrototypeOf(实例对象) 判断原型的方法 ECMA5:
Object.getPrototypeOf():根据实例对象获得原型对象 object.hasOwnProperty(attribute)
判断属性是否属于对象本身 in 操作符 判断对象中是否存在该属性(无论是实例对象还是原型对象) ECMA5新特性
Object.keys();拿到当前对象里的所有keys 返回一个数组 ECMA5新特性
Object.getOwnPropertyNames 枚举对象所有的属性 :不管该内部属性能否被枚举

这里写图片描述

5.3 原型示例练习

原型的另外一个作用就是扩展对象中的属性和方法的 模拟Array中each循环方法 类似ECMA中的forEach方法

5.4 简单原型

之前我们已经学过了原型如何使用,那么现在我们介绍一种简单原型的使用方式:即直接通过对象字面量来重写整个原型对象(这种方法会改变原型对象的构造器)
ECMA5中的Object.defineProperty()方法可以为原型对象重新加入构造器。 原型的动态性(注意原型和创建实例的前后顺序)

5.5 原型对象存在的问题

原型对象虽然可以对所有实例的属性和方法共享,但是它的局限性也是很明显的,正是因为共享的特性,也导致原型存在的最大问题。
我们一般组合使用构造函数式和原型模式,在实际开发中,这种模式也是应用的最为广泛。
动态原型模式:就是把信息都封装到函数中,这样体现了封装的概念。
稳妥构造函数式:所谓稳妥模式就是没有公共属性,而且其他方法也不引用this对象,稳妥模式最适合在安全的环境中使用。如果你的程序对于安全性要求很高,那么非常适合这种模式。

5.6 继承

我们都知道构造函数、原型和实例直接的关系,如果我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然此时的原型对象将包含一个指向另一个原型的指针,相应的另一个原型中也包含着一个指向另一个构造函数的指针。
原型链:利用原型让一个引用类型继承另外一个引用类型的属性和方法。 简单继承(原型继承) 类继承(模版继承或借用构造函数继承)
混合使用继承实现完整的继承

5.7 原型链示意图

这里写图片描述

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >            /*            var obj = new Object();//var obj = {};            obj.name = 'z3';            obj.sex = '男';            obj.sayName = function(){                alert("我是张三丰");            }*/            //类的概念            //第一种形式 工厂模型            /*            function createPerson(name,sex,age){                var obj = new Object();                obj.name = name;                obj.sex = sex;                obj.age = age;                obj.displayInfo = function(){                    alert("name:" + name + " sex:" + sex + " age:" + age)                }                return obj;            }            var p1 = createPerson('张三丰','男',90);            var p2 = createPerson('张翠山','男',50);            p1.displayInfo();            p2.displayInfo();            */            //第二种形式 构造函数 new Array new Date            //函数的第一个字母大写 (类的模板)            function Person(name,age,sex){                this.name = name;                this.age = age;                this.sex = sex;                this.sayName = function(){                    alert(this.name);                }            }            //构造一个对象 new关键字 传递参数 执行模板代码 返回对象            /*            var p1 = new Person('张三丰','男',90);            var p2 = new Person('张翠山','男',50);            //p1.sayName();            //p2.sayName();            alert(p1.constructor == Person); //true            alert(p2.constructor == Person); //true            alert(p1 instanceof Person);//true            alert(p1 instanceof Object);//true            */            //创建对象的方式:            //1.当作构造函数去使用:            var p1 = new Person('张三丰','男',90);            //2.作为普通的函数去调用            var p2 = Person('张三丰','男',90);            //3.在另一个对象的作用域中调用            var o = new Object();            //call apply            Person.call(o,'z3','男',33);            alert(o.name);        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >            //原型 prototype            //构造函数方式            /*function Person(name,age){                this.name = name;                this.age = age;//              this.sayName = function(){//                  alert("name:" + this.name)//              }                this.sayName = sayName;            }            function sayName(){                alert(this.name);            }            var p1 = new Person('z3',20);            var p2 = new Person('z4',21);//          alert(p1.sayName == p2.sayName );//false            alert(p1.sayName == p2.sayName );//true            */            //prototype 创建每一个函数都有一个prototype属性,这个属性其实是一个指针,而这个指针总是指向一个对象            //这个对象的用途就是将特定的属性和方法包含在内,起到一个所有实例所供享的作用            function Person(){            }            var obj = Person.prototype;//          alert(obj.constructor);            obj.name = 'z3';            obj.age = 20;            obj.sayName = function(){alert(this.name);}            var p1 = new Person();            var p2 = new Person();//          alert(p1.name);//          alert(p2.name);//          alert(p1.sayName == p2.sayName);            //构造函数 原型对象 实例对象            //构造函数.prototype = 原型对象            //原型对象.constructor = 构造函数            //实例对象.prototype = 原型对象//          alert(p1.prototype);//          alert(obj.isPrototypeOf(p1));        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >            //Object.getPrototypeOf(); //根据实例对象获取原型对象            function Person(){            }            Person.prototype.name = 'z3';            Person.prototype.age = 20;            Person.prototype.sayName  = function(){                alert('name:' + this.name);            }            /*var p1 = new Person();//          p1.sayName();            var prototypeObject = Object.getPrototypeOf(p1);            alert(prototypeObject == Person.prototype);            */            //每次代码读取一个对象的属性的时候:首先会进行一次搜索:搜索实例对象里name的属性,看看有没有            //如果没有,再去p2的实例所对应的原型对象里去搜索name属性 如果有就返回 没有返回undefined            /*var p2 = new Person();            p2.name = 'w5';            p2.sayName();            */            //判断一个对象属性是否属于原型属性 还是属于实例属性            /*var p3 = new Person();            p3.name='w2';             var re = p3.hasOwnProperty('name');            alert(re);            */            //in 操作符 : for-in            //in操作符是判断属性是否存在于实例对象和原型对象中            /*var p1 = new Person();            alert('name' in p1);//true            var p2 = new Person();            p2.name = 'w3';            alert('name' in p2);//true            */            //就是判断一个属性 是否存在原型中            //在原型对象中 是否存在这个属性 第一个参数:当前对象,第二个参数:要判断的属性            /*function hasPrototypeProperty(object,name){//              return object.hasOwnProperty(name) || name in object;                return !object.hasOwnProperty(name) && name in object;            }            var p3 = new Person();            alert(hasPrototypeProperty(p3,'name'));            */            //ECMA5新特性 Object.keys();            var p1 = new Person();            p1.name = 'z3';            p1.age = 20;            //拿到对象中的属性            var attributes = Object.keys(p1);//          alert(attributes);            var attributes2 = Object.keys(Person.prototype);//          alert(attributes2);            //ECMA5 constructor属性:该属性是不能被枚举的[eable = false]//          Object.hasOwnPropertyNames();//枚举对象所有属性:不管该内部属性能否被枚举            var attributes3 = Object.getOwnPropertyNames(Person.prototype);//          alert(attributes3); //constructor,name,age,sayName            //isPrototypeOf(new instance);//判断原型的方法        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >                //Array each方法                //ECMA5 forEach循环遍历数组的每一项                /*var arr = [1,2,3,[4,[5]]];                arr.forEach(function(item,index,array){                    alert(item);                });*/                //自己实现一个Array each方法 能遍历多维数组                var arr = [1,2,3,[4,[5,[6]]]]; // arr.length                    Array.prototype.each = function(fn){                        try{                            //1 目的: 遍历数组的每一项 //计数器 记录当前遍历的元素位置                            this.i || (this.i=0);  //var i = 0 ;                            //2 严谨的判断什么时候去走each核心方法                            // 当数组的长度大于0的时候 && 传递的参数必须为函数                            if(this.length >0 && fn.constructor == Function){                                // 循环遍历数组的每一项                                while(this.i < this.length){    //while循环的范围                                     //获取数组的每一项                                    var e = this[this.i];                                    //如果当前元素获取到了 并且当前元素是一个数组                                    if(e && e.constructor == Array){                                        // 直接做递归操作                                        e.each(fn);                                    } else {                                        //如果不是数组 (那就是一个单个元素)                                        // 这的目的就是为了把数组的当前元素传递给fn函数 并让函数执行                                        //fn.apply(e,[e]);                                        fn.call(e,e);                                    }                                    this.i++ ;                                }                                this.i = null ; // 释放内存 垃圾回收机制回收变量                            }                        } catch(ex){                            // do something                         }                        return this ;                    }                    arr.each(function(item){                        alert(item);                    });        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >                //简单原型                /*                 function Person(){                }                Person.prototype = {                    //constructor : Person, //必须得表示原型对象的构造器                    name : 'z3' ,                    age : 20 ,                    job : '程序员' ,                    say : function(){                        alert(this.name + ":" + this.age + ":" + this.job);                    }                };                //ECMA5 给原型对象重新设置构造器的方法 Object.define                Object.defineProperty(Person.prototype,'constructor',{                    enumerabl : false,                    value : Person                });                var p1 = new Person();                p1.say();                for(attr in p1){                    alert(attr);                }                */                //原型的动态特性                function Person(){                }                Person.prototype.say = function(){                    alert('我是方法!');                }                //注意 简单原型使用的顺序                var p1 = new Person();                p1.say();        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >            //原型的概念:原型对象里的所有属性和方法 被所有构造函数实例化出来的对象所共享            /*function Person(){            }            Person.prototype = {                constructor:Person,                name:'z3',                age: '20',                job:'程序员',                friends : ['李四','王五'],                sayName : function(){                    alert('我的名字!');                }            }            var p1 = new Person();            var p2 = new Person();            p1.friends.push('赵六');            alert(p1.friends);            alert(p2.friends);            //原型里的属性和方法 被所有对象所共享:static            */            //组合使用原型和构造函数式(定义一个类 开发时常用的方式)            /*function Person(name,age,friends,job){                this.name = name;                this.age = age;                this.friends = friends;                this.job = job;            }            Person.prototype = {                constructor:Person,                sayName : function(){                    alert(this.name);                }            }            var p1 = new Person('z3',20,['王五','赵六','技术总监']);            var p2 = new Person('李四',25,['王五','赵六','赵七']);            */            //动态原型模式:            /*function Person(name,age,friends,job){                this.name = name;                this.age = age;                this.friends = friends;                this.job = job;                //动态原型方法:                if(typeof this.sayName != 'function')                {                    Person.prototype.sayName = function(){                        alert(this.name);                    }                }            }*/            //稳妥构造函数式:durable object(稳妥对象)            //1.没有公共属性,2 不能使用this对象            function Person(name,age,job){                //创建一个要返回的对象                var obj = new Object();                //可以定义一下私有的变量和函数//              var sex = '男';//              var saySex = function(){}                //添加一个对外的方法                var name = name;                obj.sayName = function(){                    alert(name);                }                return obj;            }            var p1 = new Person('z3');            p1.sayName();        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >            //js中怎么去实现继承:采用原型链的概念            //构造函数 原型对象 实例对象            //1.构造函数.prototype=原型对象            //2.原型对象.constructor=构造函数            //3.原型对象.isPrototypeOf(实例对象)            //4.构造函数 实例对象(类和实例)            //父类构造函数sup            function Sup(name){                this.name = name;            }            //父类原型对象            Sup.prototype={                constructor:Sup,                sayName:function(){                    alert(this.name);                }            };            //子类构造函数            function Sub(age){                this.age = age;            }            //如果我们让原型对象等于另一个类型的实例,结果会怎么样呢?            Sub.prototype = new Sup('张三');            var sub1 = new Sub();            alert(sub1.name);        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >            //原型继承            //父类            function Person(name,age){                this.name=name;                this.aeg = age;            }            Person.prototype.id = 10;//父类的原型对象属性            //子类            function Boy(name,age,sex){                //ca appy                Person.call(this,name,age);                this.sex = sex;            }            //继承已已经实现了            Boy.prototype = new Person('z3',20,'nan');            var b = new Boy();            alert(b.name);            alert(b.id);            //原型继承的特点,即继承了父类的模板,又继承了 父类的原型对象        </script>    </head>    <body>    </body></html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <title>Untitled Document</title>        <script type="text/javascript" charset="UTF-8" >            function extend(sub,sup){                var F = new Function();                F.prototype = sup.prototype;//父类                sub.prototype = new F();                sub.prototype.constructor = sub;                //保存一下父类的原型对象 方便解耦                sub.superClass = sup.prototype;                if(sup.prototype.constructor == Object.prototype.constructor)                {                    sup.prototype.constructor = sup;                }            }            //混合继承:原型继承和借用构造函数继承            function Person(name,age){                this.name = name;                this.age = age;            }            Person.prototype = {                constructor:Person,                sayHello:function(){                    alert('hello world');                }            };            function Boy(name,age,sex){                //call绑定你类的模版函数 实现 借用构造函数继承 只复制了父类的模板                Person.superClass.constructor.call(this,name,age);                this.sex = sex;            }            //原型继承的方式:即继承了模版 又继承了父类的原型对象            //Boy.prototype = new Person();            extend(Boy,Person);            //给子类加了一个 原型对象方法            Boy.prototype.sayHello = function(){                alert("hi javascript");            }            var b = new Boy('张三',20,'男');            alert(b.name);            //b.sayHello();            Boy.superClass.sayHello.call(b);        </script>    </head>    <body>    </body></html>
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 做完痔疮手术后大便困难怎么办 20岁长痔疮了怎么办 孕妇痔疮痒的难受怎么办 痔疮术后伤口不愈合怎么办 剖腹产液化伤口长的慢怎么办 内痔斑痕怎么办了能消化 油条面和稀了怎么办 解脲支原体感染怀孕怎么办 怀孕了检查出解脲支原体感染怎么办 大便是黑色的要怎么办 大人直肠给药不好意思怎么办 肛周脓肿长肉芽怎么办 二岁宝宝有直肠息肉怎么办 87岁老人得直肠息肉怎么办 做b超查出囊肿怎么办 解大便时肛门痒怎么办 生完孩子肛门痒怎么办 把达克宁软膏摸到肛门怎么办 痔疮手术后肛门痒怎么办 便秘拉完屁股疼怎么办 屁股拉屎拉破了怎么办 6岁小朋友屁眼痒怎么办 孩子屁屁偶尔痒怎么办 1岁半宝宝屁眼痒怎么办 3岁宝宝肛门痒怎么办 得痔疮发烧了怎么办啊 痔疮手术后肚子胀气怎么办 乙肝引起的发烧头痛怎么办 肠癌手术后吃了会胃疼怎么办 来月经肛门坠痛怎么办 总想排便还有血怎么办 闻了别人的口臭怎么办 有内痔肛门经常不舒服怎么办 做完肠镜肛门疼怎么办 3周宝宝得皮彦怎么办 痔疮有蚕豆大了怎么办 顺生肛门坠胀怎么办 生孩子痔疮脱出不能回纳怎么办 痔疮犯了屁眼疼怎么办 孕晚期得痔疮了怎么办 孕39周痔疮严重怎么办