JavaScript - 面向对象与面向对象的发展过程

一、面向对象与面向过程

面向过程 c注重问题的解决
面向对象 JAVA完成对真实世界的模拟,把一个对象的共同特点抽离出现,有了所有的’属性’和’方法’ class

js并不是一个真正的面向对象的语言 , js在模拟面向对象
对象的特点:属性 + 方法
对象在js里面是由构造函数new出来的

这里我们举个例子~:
问题1:有一只两岁的柯基

        // 面向过程
        const dog = '柯基' ;
        const age = 2 ;

        // 面向对象
        const obj = {
            dog : '柯基'  ,
            age : 2
        } 

问题2:又来了一只3岁的二哈

        // 封装函数
        function dog(type, age) {
            console.log('有一只' + age + '岁的' + type);
        }
        dog('二哈', 3) //有一只3岁的二哈


        // 面向对象
        function Dog(type, age) {
            const obj = {
                dog: type,
                age,
                say: function() {
                    console.log('有一只' + this.age + '岁的' + this.dog);
                }
            }
            return obj;
        }

        const d = Dog('二哈', 3);
        console.log(d); //{dog: '二哈', age: 3, say: ƒ}
        d.say() //有一只3岁的二哈

        // 不会共享内存
        console.log(d1.say === d2.say); //false

        // d1也不是Dog生的
        console.log(d1.constructor); //Object

二、其他对象

  • 所有实例化的对象都共享方法
        var arr1 = new Array();
        var arr2 = new Array();

        console.log(arr1.forEach == arr2.forEach); //true

        //arr1与Array是母子关系 ,arr1是由Array生出来的
        console.log(arr1.constructor); //ƒ Array() { [native code] }

三、JavaScript面向对象的发展过程

1.工厂模式:

定义:创建一个对象,给对象加工(添加属性和方法),返回这个对象
缺点:创建出来的对象跟函数没有任何关系;创建出来的对象之间的方法不共享

        // 工厂模式
        function dog(type , age) {  
            // 原材料 : 创建一个对象
            const obj = {} ;
            // 加工
            obj.type = type ;
            obj.age = age ;
            obj.say = function () {  
                console.log('有一只' + obj.age + '岁的' + obj.type);
            }
            // 出厂:返回这个对象
            return obj
        }
        
        const dog1 = dog('柯基' , 3) ;
2.构造函数模式
  • 任何一个函数都有可能成为一个构造函数,只要有new就可以

构造函数模式与工厂模式有什么不同:
1.为了区分普通函数和构造函数,JavaScript建议构造函数使用大驼峰命名
2.没有显示的创建对象,最后也没有return语句:new操作符帮你创建对象并返回。
3.直接将属性和方法赋给了 this 对象:new操作符帮你把this指向创建的对象。
4.创建实例的时候需要用new操作符来调用构造函数。
5.可以用instanceof判断创建出的对象的类型。

        function fn() {
            console.log(this);
            console.log(666);
        }

        var res = fn(); //this指向window
        console.log(res); // 函数没有返回值 undefined

        var res2 = new fn(); // this指向了对象
        console.log(res2); // 返回了这个对象
  • 总结 new的贡献
    1.创建了一个对象
    2.this指向了这个对象
    3.把这个对象的原型指向了构造函数的原型对象
    4.返回了这个对象
  • 构造函数虽然解决了关系问题,但是方法依然不共享。也就是说通过构造函数创建的每个实例对象里的属性都是独立的,包括一些本可以被共用的属性和方法。
  • dog1和dog2的say方法虽然内容是一样的,却各自在内存里开辟了新的空间来存放两个内容一样的方法,造成了内存的浪费。这就违背了函数的复用原则。
        function Dog(type, age) {
            this.type = type;
            this.age = age;
            this.say = function() {
                console.log('有一只' + this.age + '岁的' + this.type);
            }
        }

        const dog1 = new Dog('柯基', 3);
        const dog2 = new Dog('二哈', 4);
        
        console.log(dog1.say == dog2.say); //输出:false  说明dog1和dog2方法不共享
3.原型模式
  • prototype原型对象:提供共享的属性和方法
  • 每个函数都有一个prototype属性,prototype的值指向其相对应的原型对象。而原型对象正是被设计来存放类的公有属性和方法的,它除了自带一个不可枚举的constructor属性指向函数本身外,和其他空对象并无不同。你可以把原型对象理解为一个共享仓库。

原型:任何一个对象都有原型 proto , 也就是这个构造函数
原型对象:任何一个函数都有原型对象 prototype 。作用:给所有的实例化对象提供共有的属性和方法

        function Fn(type) {
            this.type = type;
            this.age = '1';
        }

        //prototype 原型对象:提供共享的属性和方法
        Fn.prototype.species = '狗';
        Fn.prototype.say = function() {
            console.log('汪');
        }

        var dog1 = new Fn('二哈');
        var dog2 = new Fn('柯基');

        // 每一个实例化对象都共享say方法
        console.log(dog1.say == dog2.say); //true

        console.log(dog1.__proto__); //指向这个构造函数

        console.log(dog1.constructor); //Fn

那原型对象是怎么做到被所有实例共享的呢?前面提到了new这个操作符,在js中new操作符其实也是个语法糖,那它在背后替我们做了什么呢?

        //new到底做了什么
        function _new(fn) {
            return function() {
                //1.创建一个对象
                var obj = new Object;
                //2.把创建的对象的原型(__proto__)指向构造函数的原型对象
                obj.__proto__ = fn.prototype;
                //3.使this指向该对象
                var result = fn.apply(o, arguments);
                //4.检测构造函数有无返回值,如有,则返回构造函数的返回值。否则返回创建的对象
                if (result && (typeof result === 'object' || typeof result === 'function')) {
                    return result;
                } else {
                    return obj;
                }

            }
        }