美文网首页
JavaScript面向对象

JavaScript面向对象

作者: 追逐_e6cf | 来源:发表于2019-02-24 11:25 被阅读0次

    一、面向对象基本特征

    1. 封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
    2. 继承:通过继承创建的新类称为“子类”或“派生类”。继承的过程,就是从一般到特殊的过程。
    3. 多态:对象的多功能,多方法,一个方法多种表现形式。
    4. Javascript是一种基于对象(object-based)的语言。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)—–es6以前是这样的。所以es5只有使用函数模拟的面向对象。

    二、对象实例化方式

    1. 原始模式:这样的写法有两个缺点,一是如果多生成几个(100个!)实例,写起来就非常麻烦;二是实例与原型之间,没有任何办法,可以看出没有什么联系。
    var Car = {
        color: 'red',//车的颜色
        wheel: 4,//车轮数量
    }
    var Car2 = {
        color: 'blue',
        wheel: 4,
    }
    alert(Car.color);//red
    
    1. 原始模式的改进:通过写一个函数,解决代码重复的问题。
    function createCar(color,wheel) {
        return {
            color:color,
            wheel:wheel
        }
    }
    //然后生成实例对象,就等于是在调用函数:
    var cat1 = createCar("红色","4");
    var cat2 = createCar("蓝色","4");
    
    alert(cat1.color);//红色
    
    1. 工厂模式
    function createCar(color,wheel){//createCar工厂
        var obj = new Object;//或obj = {} 原材料阶段
        obj.color = color;//加工
        obj.wheel = wheel;//加工
        return obj;//输出产品
    }
    //实例化
    var cat1 = createCar("红色","4");
    var cat2 = createCar("蓝色","4");
    
    alert(cat1.color);//红色
    
    1. 构造函数模式:为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。 所谓”构造函数”,其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。加new执行的函数构造内部变化:自动生成一个对象,this指向这个新创建的对象,函数自动返回这个新创建的对象
    function CreateCar(color,wheel){//构造函数首字母大写
        //不需要自己创建对象了
        this.color = color;//添加属性,this指向构造函数的实例对象
        this.wheel = wheel;//添加属性
    
        //不需要自己return了
    }
    
    //实例化
    var cat1 = new CreateCar("红色","4");
    var cat2 = new CreateCar("蓝色","4");
    alert(cat1.color);//红色
    

    三、构造函数注意事项

    1. 此时CreateCar称之为构造函数,也可以称之类,构造函数就是类 。
    2. cat1,cat2均为CreateCar的实例对象。
    3. CreateCar构造函数中this指向CreateCar实例对象即 new CreateCar( )出来的对象。
    4. 必须带new 。
    5. 构造函数首字母大写,这是规范,官方都遵循这一个规范,如Number() Array()。
    6. contructor:这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数,即CreateCar。
    alert(cat1.constructor == CreateCar); //true
    alert(cat2.constructor == CreateCar); //true
    
    1. 每定义一个函数,这个函数就有一个 prototype 的属性{},__proto__ 指向被实例化的构造函数的prototype,prototype默认带constructor属性,constructor指向构造函数。
    2. instanceof 运算符:object instanceof constructor运算符,验证构造函数与实例对象之间的关系。
    alert(cat1 instanceof CreateCar ); //true
    alert(cat2 instanceof CreateCar ); //true
    

    四、构造函数的问题

    构造函数方法很好用,但是存在一个浪费内存的问题。如果现在为其再添加一个方法showWheel。那么,CreateCar就变成了下面这样,这样做有一个很大的弊端,对于每一个实例对象,showWheel都是一模一样的内容,每一次生成一个实例,都必须生成重复的内容,多占用一些内存。这样既不环保,也缺乏效率。

    function CreateCar(color,wheel){
    
        this.color = color;
        this.wheel = wheel;
        this.showWheel = function(){//添加一个新方法
            alert(this.wheel);
        }   
    }
    
    //还是采用同样的方法,生成实例:
    var cat1 = new CreateCar("红色","4");
    var cat2 = new CreateCar("蓝色","4");
    
    alert(cat1.showWheel == cat2.showWheel); //false
    

    五、Prototype 原型

    Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。 这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。__proto__是原型链,指向实例化的函数原型。

    function CreateCar(color,wheel){
        //属性写构造函数里面
        this.color = color;
        this.wheel = wheel;
    }
    
    //方法写原型里面
    CreateCar.prototype.showWheel = function(){
        alert(this.wheel);
    }
    CreateCar.prototype.showName = function(){
        alert('车');
    }
    
    //生成实例。
    var cat1 = new CreateCar("红色","4");
    var cat2 = new CreateCar("蓝色","4");
    cat1.showName();//'车'
    
    //这时所有实例的showWheel属性和showName方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。
    alert(cat1.showWheel == cat2.showWheel );//true
    alert(cat1.showName == cat2.showName );//true
    console.log(cat1.__proto__ === CreateCar.prototype); //true
    

    六、对象和函数的关系

    对象是由函数构造出来的。

    1. Object是Function 的一个实例。
    Object.constructor  == Function  //true
    
    1. 函数是Function 的实例,但不是Object 的实例。
    function fn(){}
    fn.constructor  == Function  //true
    fn.constructor  == Object    //false 
    
    1. {} 与 Object 的关系。
    var obj = {};
    obj.constructor  === Object   //true
    

    七、静态方法和静态属性

    只属于类而不属于实例化对象

    function foo(){
        this.show = function(){
            return this;
        }
    }
    
    foo.test = 123; //静态属性
    
    foo.say = function(){
        return this;
    }
    foo.say();
    
    var fn = new foo(); //实例化的新的对象,this指向这个新的对象,不能访问类的静态方法
    fn.say(); //Noname1.html:45 Uncaught TypeError: fn.say is not a function
    console.log(foo.say() == fn.say());
    

    八、对象继承

    1. 利用call()for in继承 。
      给对象的constructor.prototype添加方法属性,对象就会继承,如果要实现一个对象继承其他对象,采用如下方法。
    //人类
    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.run = function(){
        console.log('跑路~')
    };
    Person.prototype.say = function(){
        console.log('说话~')
    };
    
    console.log(Person.prototype);
    
    //男人
    function Man(){
        this.sex = "男";
    }
    
    Man.prototype = Person.prototype;
    
    Man.prototype.yyy = function(){
        console.log('嘤嘤嘤');
    }
    //会发现Person的prototype也改变了,因为复杂对象的赋值操作是引用而不是赋值
    console.log(Person.prototype);
    
    //人类
    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.run = function(){
        console.log('跑路~')
    };
    Person.prototype.say = function(){
        console.log('说话~')
    };
    
    console.log(Person.prototype);
    
    //男人
    function Man(){
        this.sex = "男";
    }
    
    for(var key in Person.prototype){
        Man.prototype[key] = Person.prototype[key];
        console.log(key)
    }
    Man.prototype.yyy = function(){
        console.log('嘤嘤嘤');
    }
    
    console.log(Person.prototype);
    var xm = new Man();
    xm.yyy();
    
    1. 采用中介
    function ClassA(name){
        this.name = name;
    }
    ClassA.prototype.say = function(){
        console.log(666);
    }
    
    //中继来做准备工作
    function Ready(){}//
    Ready.prototype = ClassA.prototype;//引用
    
    //需要来继承ClassA
    function ClassB(){}
    ClassB.prototype = new Ready();//new 返回了一个新对象 __proto__指向被实例化的构造函数的prototype
    ClassB.prototype.constructor = ClassB;
    console.log(ClassB.prototype);
    
    1. 采用中介,使用call改变this指向
    function ClassA(name){
        this.name = name;
    }
    ClassA.prototype.showName = function(){
        console.log(this.name);
    }
    
    //中继来做准备工作
    function Ready(){}//
    Ready.prototype = ClassA.prototype;//引用
    
    //需要来继承ClassA
    function ClassB(name){
        ClassA.call(this,name);
    }
    ClassB.prototype = new Ready();//new 返回了一个新对象 __proto__指向被实例化的构造函数的prototype
    ClassB.prototype.constructor = ClassB;
    console.log(ClassB.prototype);
    var xiaoming = new ClassB('小明');
    xiaoming.showName();
    

    九、多态

    同一个方法,面对不同的对象有不同的表现形式就叫做多态。

    var obj = {
        eat : function(_type){
            if(_type == '猫'){
                console.log('猫粮')
            }else if (_type == "狗") {
                console.log('狗粮')
            }else{
                console.log("吃饭");
            }
        }
    };
    obj.eat("狗");
    

    十、hasOwnProperty

    查看该属性是否在这个对象本身上,只有在自身属性上才会返回真,在原型链上会返回假。

    function ClassA(){}
    ClassA.prototype.test = function(){
        console.log('test')
    }
    
    var a = new ClassA();
    a.test();
    console.log(a.hasOwnProperty('test')); //false
    

    十一、描述符(修饰符)

    描述符是对一个属性的特性的描述,defineProperty设置描述符(修饰符),value设置属性值,configurable是否允许修饰符被改变 默认为false,enumerable 是否可以被枚举 默认为false,writable 是否可以被 = 等号改变 默认为false。

    var obj = {
        a : 1
    };
    var c = 666;
    Object.defineProperty(obj,'c',{
        //value : 233,
        //enumerable : false,
        //writable : true,//他的值能否改变
                
        //设置的时候调用
        set : function(n){
            //n 就是等号的右边的值
            c = c*n;
        },
    
        //获取的时候调用
        get : function(){
            return c;
        },
    
        configurable : true,//是否可以再次修改修饰符
    });
    

    相关文章

      网友评论

          本文标题:JavaScript面向对象

          本文链接:https://www.haomeiwen.com/subject/eglmyqtx.html