zoukankan      html  css  js  c++  java
  • js的面向对象

    1.面向对象语言都有一个标志,那就是类的概念。通过类可以创建任意多个具有相同属性的方法的对象。但是在ECMAScript中

    没有相关类的概念。但是我们可以通过其他方式来模拟面向对象中的类。

      -工厂模式:不细说

      -构造函数模式:比如像ECMAScript中的Array,Object,Date等都是通过构造函数来创建的。

      -动态原型模式

      -寄生构造函数模式

      -稳妥构造函数模式

    <script type="text/javascript" charset="utf-8">
                
                var obj = new Object();
                obj.name = 'zs';
                obj.sex = 'male';
                obj.sayName = function() {
                    alert('my name is zs');
                };
                
                // 类的概念
                // 第一种形式  工厂模型  通过这个方法用来创建实例
                function createPerson(name, sex, age) {
                    var obj = new Object();
                    obj.name = name;
                    obj.sex = sex;
                    obj.age = age;
                    obj.sayName = function(){
                        alert(this.name);
                    };
                    return obj;    
                }
                
                var p1 = createPerson(ls, male, 24);
                
                
                // 第二种形式,构造函数式, 函数的第一个字母大写,约定俗成的表示为一个类的模板
                function Person(name, age, sex) {
                    this.name = name;
                    this.age = age;
                    this.sex = sex;
                    this.sayName = function() {
                        alert(this.name);
                    };
                }
                // 构造一个对象,一般使用new 关键字,并且传递参数 执行模板代码 返回对象
                var p2 = new Person('ww', 'famale', 20);
                alert(p2.constructor == Person);  // 返回结果为true
                alert(p2 instanceof Person);    // 返回结果为true
                alert(p1 instanceof Object);    // 返回结果为true
                
                // 创建对象的方式
                // 1.当做构造函数去使用  即new的方式
                var p3 = new Person('w1', 'male', 10);
                // 2.作为普通函数去调用    //在全局环境里定义属性并复制 直接定义在window上
                var p4 = Person('w2', 'famale', 30);
                // 3.在另一个对象的作用域中调用
                var o = new Object();
                Person.call(o, '11', 'male', 30);
            </script>

    2.原型   

      -我们创建的每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途包含可以由特定类型

    的所有实例共享的属性和方法。

      -原型对象实际就是一个构造函数的实例对象,与普通的实例对象没有什么本质上的区别,js中每一个对象都有一个原型对象。不过

    它比较特殊,该对象所包含的所有属性和方法能够供构造函数的所有实例共享,也就是其他编程语言所说的继承,而js通过原型对象来

    继承,简称原型继承。静态原型继承:Object.prototype.[method field];

      -简单实现Array中的push,pop方法。

    <script type="text/javascript" charset="utf-8">
                
                
                // 原型   prototype
                // 构造函数方式
                function Person(name, age){
                    this.name = name;
                    this.age = age;
                    this.sayName = function() {
                        alert('i am name');
                    };
                }
                
                function sayName() {
                    alert(this.name);
                }
                
                var p1 = new Person('zs', 20);
                var p2 = new Person('ls', 21);
                alert(p1.sayName == p2.sayName);    //返回结果为false
                alert(p1.name == p2.name);    //false
                p1.sayName();
                alert(p1.sayName == p2.sayName);     // 将Person中的sayName方法去掉之后,返回结果为true
                
                // 但是定义过多的全局变量 显然是不好的,于是我们采用下面的方法。
                // 创建每一个函数的时候 都有一个Prototype属性,这个属性其实是一个指针。而这个指针总是指向一个对象。
                // (这个对象的用途就是将特定的属性和方法 包含在内,起到一个所有实例所共享的作用)
                
                function Person1() {
                    
                }
                var obj = Person1.prototype;
                alert(obj.constructor);    // 返回值为function Person(){}
                obj.name = 'zs';
                obj.age = 20;
                obj.sayName = function() {
                    alert(this.name);
                };
                var p3 = new Person();
                var p4 = new Person();
                alert(p3.name);    //zs
                alert(p4.name);    //zs
                alert(p3.age);    // 20
                alert(p4.age);    // 20
                
                // 构造函数  原型对象  实例对象
                // 构造函数.prototype = 原型对象
                // 原型对象.constructor = 构造函数
                // 实例对象.prototype = 原型对象
                obj.isPrototypeOf(p3);    // 结果为true
                
            </script>

     3.原型的详细方法

      

    <script type="text/javascript" charset="utf-8">
                
                // isPrototypeOf()  判断原型的方法
                
                // Object.getPrototypeOf();根据实例对象获得原型对象
                function Person() {
                    
                }
                Person.prototype.name = 'zs';
                Person.prototype.age = 20;
                Person.prototype.sayName = function() {
                    alert('我是原型对象的方法');
                };
                
                var p1 = new Person();
                var prototypeObj = Object.getPrototypeOf(p1); // 得到原型对象
                
                
                var p2 = new Person();
                p2.name = 'w5';
                // 每次代码读取一个对象的属性的时候,会先进行一次搜索,搜索实例对象。如果没有,再去实例所对应的原型对象里搜索。
                alert(p2.name);    // 返回值为w5
                // 如果非要获得原型对象中的属性,可以将实例中的属性删除掉。
                delete p2.name;
                
                // 判断一个对象是原型属性还是实例属性
                var p3 = new Person();
                p3.hasOwnproperty('name');    //返回false 因为是原型属性
                
                // in操作符:for-in
                // in操作符是判断属性是否存在于实例对象和原型对象中。如果有一个存在,则返回true,如果都不存在,才返回false
                var p5 = new Person();
                alert('name' in p5); // 返回true 证明在p5对象中有name属性
                var p6 = new Person();
                p6.name = 'w3';
                alert('name' in p6);     //返回true
                
                // 判断一个属性是否存在原型中。第一个参数是当前对象,第二个参数是要判断的属性
                function hasPrototypeProperty(object, name) {
                    return !object.hasOwnProperty('name') && name in object;
                }
                
                // ECMA5新特性 Object.keys
                  // 可以将对象中所有的属性找到,并返回一个数组
                  var m1 = new Person();
                  m1.name = 'zs';
                  m1.age = 20;
                  var attribute = Object.keys(m1);
                  alert(arrtibute);    // 返回name和age
                  
                  var attribute = Object.keys(Person.prototype); //返回 name age sayName
                  
                  // ECMA5中 constructor属性 不可以被枚举
                  // Object.getOwnPropertyNames  方法的作用是 枚举出对象的全部属性,无论该属性能否被枚举
                  alert(Object.getOwnPropertyNames(m1));// constructor name age sayName
                  
                  
            </script>

     4.模拟each方法

    <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 arr1 = [1,2,3,[4,[5,[6]]]];
                Array.prototype.each = function(fn){
                    try{
                        // 1.目的,遍历数组的每一项
                        // 计数器,记录当前遍历的元素位置
                        this.i || (this.i = 0);
                        if (this.length > 0 && fn.constructor == Function) {
                            // 循环遍历
                            while(this.i < this.length){
                                // 获取数组的每一项元素
                                var e = this[this.i];
                                // 如果当前元素获取到了,并且是一个数组
                                if (e && e.constructor == Array) {
                                    // 递归
                                    e.each(fn);
                                } else {
                                    fn.call(e, [e]);
                                }
                                this.i++;
                            }
                            // 释放内存,垃圾回收
                            this.i = null;
                        }
                        
                        
                    }catch(ex){
                        // do something
                    }
                    return this;
                };
                
                arr1.each(function(item){
                    alert(item);
                });
            </script>

    5.简单原型的使用
      直接通过对象字面来重写整个对象(会改变原型对象的构造器)。

      ECMA5中的Object.defineProperty()方法可以为原型对象重新加入构造器。

      原型的动态性(注意原型和创建实例的先后顺序)

    <script type="text/javascript" charset="utf-8">
                // 简单原型
                function Person() {
                    
                }
                
                Person.prototype = {
                    name : 'zs',
                    age : 18,
                    job : 'doctor',
                    say: function(){
                        alert('aa');
                    }
                };
                
                var p1 = new Person();
                alert(p1.name);
                p1.say();
                
                alert(Person.prototype.constructor);    //不加constructor : Person这句话,Object的构造函数,加上之后可以枚举(这样不对)
                // ECMA5给远行对象重新设置构造器方法
                // 3个参数  参数1:重设构造器的对象  参数2:设置什么属性  参数3:option配置项
                Object.defineProperty(Person.prototype, 'constructor', {
                    enumerable : false,
                    value : Person
                });
                
                // 原型动态特性
                function A() {
                    
                }
                var a = new A();
                A.prototype.say = function(){
                    alert('bbb');
                };
                
                a.say();//返回bbb 没有问题
                
                
                
                function B() {
                    
                }
                var b = new B();
                B.prototype = {
                    name : 'zs',
                    age : 18,
                    job : 'doctor',
                    say: function(){
                        alert('aa');
                    }
                };
                   b.say(); // say is not a function 必须把var b = new B(); 拿到后面去写(实例对象必须在原型对象之后创建)
                   
            </script>

     6.原型对象存在的问题

      -原型对象虽然可以对所有实例的属性和方法共享,但是他的局限性也是很明显的。正因为共享的特性,也导致了原型存在

    的最大问题。

      -我们一般组合使用构造函数式和原型模式,在实际开发中,这种模式也是应用的最稳广泛。

      -动态原型模式:就是把信息都封装到函数中,这样体现了封装的概念。

      -稳妥构造函数式:所谓稳妥模式就是没有公共属性,而且其他方法也不引用this对象。稳妥模式最适合在安全的环境中

    使用。如果你的程序对于安全性要求很高,那么非常适合这种模式。

    <script type="text/javascript" charset="utf-8">
                
                // 原型概念:原型对象里的所有属性和方法,被所有构造函数实例化出来的对象所共享
                function Person(){
                    
                }
                Person.prototype = {
                    constructor:Person,
                    name:'zs',
                    age:20,
                    job:'doctor',
                    friends:['ls', 'ww'],
                    sayName:function(){
                        alert('my name!');
                    }
                };
                
                var p1 = new Person();
                var p2 = new Person();
                p1.friends.push('zl');
                // p1增加friend之后,由于共享性,p2的friend也增加了,这样会存在问题。
                alert(p1.friends);
                alert(p2.friends);
                
                // 组合使用原型和构造函数式(开发常用定义类的方式)
                function Person1(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);
                    }
                };
                
                // 动态原型模式:(让代码 所有属性和方法都封装到一起)
                function Person2(name, age, friends, job) {
                    this.name = name;
                    this.age = age;
                    this.friends = friends;
                    this.job = job;
                    
                    if(typeof sayName != 'function'){
                        Person.prototype.sayName = function() {
                            alert(this.name);
                        };
                    }
                }
                
                
                // 稳妥构造函数式:durable object(稳妥对象)
                // 1.没有公共属性
                // 2.不能使用this
                function Person3(name, age, job) {
                    // 创建一个要返回的对象
                    var obj = new Object();
                    var name = name;
                    
                    obj.sayName = function(){
                        alert(name);
                    };
                    return obj;
                }
            </script>

    7.继承
      - 我们都知道构造函数,原型和实例的关系,如果我们让原型对象等于另一个类的实例,此时的原型对象将

    包含一个指向另一个原型的指针,相应的另一个原型也包含着一个指向另一个构造函数的指针。

      -原型链:利用原型让一个引用类型来继承另一个引用类型的属性和方法。

      -简单继承

      -类继承(模板继承或者借用构造函数继承)

      -混合使用继承

    <script type="text/javascript" charset="utf-8">
                // js中如何实现继承 采用原型链的概念
                
                // 构造函数 原型对象  实例对象
                // 构造函数 .prototype = 原型对象
                // 原型对象.constructor = 构造函数模板
                // 原型对象.isprototypeOf(实例对象)  判断实例对象原型是否是该原型对象
                
                
                // 如果我们让原型对象等于另一个类的实例
                function Super(name) {
                    this.name = name;
                }
                Super.prototype = {
                    constructor : Sup,
                    sayName : function() {
                        alert(this.name);    
                    }
                };
                function Sub(age){
                    this.age = age;
                }
                // 子类原型对象 等于父类的实例
                // 子类的原型对象的构造器  变成了父类的构造器
                Sub.prototype = new Sup();
            </script>
    <script type="text/javascript" charset="utf-8">
                function Person(name, age){
                    this.name = name;
                    this.age = age;
                }
                Person.prototype.id = 10;
                
                function Boy(sex){
                    this.sex = sex;
                }
                
                Boy.prototype = new Person('zs');
                var b = new Boy();
                alert(b.name);
                alert(b.id);
                
                
                // 类继承,只继承模板,不继承原型(借用构造函数方式继承)
                function Person1(name, age){
                    this.name = name;
                    this.age = age;
                }
                Person1.prototype.id = 10;
                
                function Boy1(name, age, sex) {
                    // call apply
                    Person1.call(this, name, age);
                    this.sex = sex;
                } 
                
                var b1 = new Boy1('zs', 20, 'male');
                alert(b1.name);
                alert(b1.id);    // undefined 父类的原型对象并没有继承,这就是类继承的缺点
                
                
                // 混合继承 通过原型继承 借用构造函数继承  = 混合继承
                // 类继承,只继承模板,不继承原型(借用构造函数方式继承)
                function Person2(name, age){
                    this.name = name;
                    this.age = age;
                }
                Person2.prototype.id = 10;
                Person2.prototype.sayName = function(){alert(this.name);};
                
                function Boy2(name, age, sex) {
                    // call apply
                    Person2.call(this, name, age);
                    this.sex = sex;
                }
                // 不传参数 ,父类的实例和子类的原型对象的关联
                // 目的只是为了继承父类的原型对象
                Boy2.prototype = new Person2();
            </script>

     8.模拟extjs底层继承方式

    <script type="text/javascript" charset="utf-8">
                // 混合继承:原型继承和借用构造函数继承
                function Person(name, age){
                    this.name = name;
                    this.age = age;
                }
                Person.prototype = {
                    constructor : Person,
                    sayHello : function(){alert('hello world');}
                };
                function Boy(name, age, sex) {
                    Person.call(this, name, age);        // 也可以写成Boy.superclass.constructor.call(this, name, age);
                    this.sex = sex;
                }
                Boy.prototype = new Person();//这里其实也继承了父类的模板,而且继承了父类的原型对象。
                
                // 混合继承  做了3件事, 继承了两次父类模板,继承了一次原型对象。
                // 混合模板的缺点,如果父类的属性特别多,这样很不方便
                
                
                // 继承一次父类模板,继承一次父类原型对象,这样是最好的,我们自己写一个extend方法
                function extend(sub, super){
                    // 目的:只继承父类的原型对象
                    // 1.用一个空函数进行中转
                    var F = new Function();
                    // 2.空函数的原型对象和父类的原型对象转换
                    f.prototype = super.prototype;
                    // 3.将空函数的原型对象,给子类的原型对象
                    sub.prototype = new F();
                    // 4.还原子类的构造器
                    sub.prototype.constructor = sub;
                    // 5.保存父类的原型对象  原因:方便解耦     方便获得父类的原型对象
                    sub.superclass = sup.prototype;// 利用子类的静态属性,存储父类的原型对象 
                    // 判断父类的原型对象的构造器
                    if (sup.prototype.constructor == Object.prototype.constructor) {
                        sup.prototype.constructor = sup;
                    }
                }
                
                // 给子类加一个原型对象方法
                Boy.prototype.sayHello = function(){
                    alert('hello sub!!');
                };
                b.sayHello(); //返回值为hello sub
                // 为了想要使用父类的sayHello方法
                Boy.superclass.sayHello.call(b);  // 这样就没问题了
                
            </script>
  • 相关阅读:
    sort()函数与qsort()函数
    个人作业——软件工程实践总结作业
    个人作业——软件评测
    软件工程实践2019第五次作业
    软件工程实践2019第四次作业
    软件工程实践2019第三次作业
    软件工程实践2019第二次作业
    期末大作业
    第7次实践作业
    第6次实践作业
  • 原文地址:https://www.cnblogs.com/yangfanasp/p/7082435.html
Copyright © 2011-2022 走看看