面向对象(OOP)和NEW的实现原理

别等时光非礼了梦想. 提交于 2020-02-20 17:31:12

面向对象编程(OOP):
OOP-Object Oriented Programring:面向对象程序设计
POP-Procedure Oriented:面向过程程序设计

面向过程:C语言
面向对象:JS JAVA PHP C# (.net)Python Ruby go …

什么是面向对象,要正确区分对象,类和实例:
对象: 万物皆对象
类:对象的细分
实例:类中具体的事物

JS也是面向对象编程:类、实例
1 => Number
‘A’=> Srting
true => Boolean -都属于大类Object
null => Null
undefined => Undefined
[] => Array
/^$/ => RegExp
function(){} => Function
{} => Object

每一个实例可以调用所属类(整条链)中的属性和方法。
所以学习JS时,按照面向对象的思维去考虑事情。
在开发中,遇到实例,要可以研究它的子类,父类,基类。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>面向对象</title>
</head>

<body>
    <!-- 
        每一个元素标签(元素对象)都有一个自己所属的大类。
        div -> HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget -> Object
        每一个实例可以调用所属类(整条链)中的属性和方法
        子类不属于父类的实例,实例是具体的东西,所以在学习JS时,要按照面向对象的思维去考虑事情
    -->
    <!-- 打开页面,在控制台输入dir(box) => 可以看到它的类__proto__: HTMLDivElement -> __proto__: HTMLElement -> __proto__: Element -> __proto__: Node(元素节点) -> __proto__: EventTarget(事件目标类)-> __proto__: Object  -->

    <div id="box"></div>

    <script>

        /*
        *   JS中已经有一些内置的类,但在开发中,只有这一些是不够的,所以会需要自定义类。
        *       => 创建一个函数(Function类的实例),直接执行就是普通函数,但是“new执行”,它则被称为一个自定义的类
        *       NEW函数执行:
        *           形成一个全新的执行上下文EC
        *           形成一个变量对象AO
        *               ARGUMENTS
        *               形参赋值
        *          // 声明其THIS指向(普通函数执行,new出来的实例指向不同)
        *           初始化作用域链
        *           【新】默认创建一个对象,而这个对象就是当前类的实例
        *           【新】声明其THIS指向,让其指向这个新创建的实例
        *           代码执行
        *           【新】不论其是否写RETURN,都会把新创建的实例返回(特殊点)
        *
        */
        //  new函数执行,既包含了普通函数应该办的事,也包含了new时所有的特殊的处理
        /*
        function func() {
            // let obj = {}; //=> 这个对象就是实例对象
            //this -> obj
            let x = 100;
            this.num = x + 100; //=> 相当于给创建的实例对象新增一个num的属性
            //obj.num = 200; (因为具备普通函数执行的一面,所以只有this.XXX=xxx才和创建的实例有关系,此案例中的x只是AO中的私有变量)
            //return obj; 用户自己返回内容,如果返回的是一个引用类型值,则会把默认返回的实例给覆盖掉(此时返回的值就不再是类的实例了)。比如return {x:3000},输出的就是x:3000,基本类型的值没有影响。
        }
        let f = new func();
        console.log(f); //=> f是func这个类的实例
        // let f2 = new func();
        // console.log(f2);
        // console.log(f === f2); //false =>因为每一次new出来的都是一个新的实例对象,(一个新的堆内存),所以是不相等的
        // func(); //=> this:window 变量对象AO(FUNC): {x:100} ...普通函数执行
        console.log(f instanceof func);//TRUE ;instanceof 用来检测某一个实例是否属于这个类 在此即代表f是否是func的实例
        */
    </script>

    <script>
        function Dog(name) {
            this.name = name;
        }
        Dog.prototype.bark = function () {
            console.log('wangwang');
        }
        Dog.prototype.sayName = function () {
            console.log('my name is' + this.name);
        }
        /*
        使用new可以实现
        let sanmao = new Dog('三毛');
        sanmao.sayName();
        sanmao.bark();
        */
        /*
        *内置NEW的实现原理
        *   @params:
        *       Func:操作的那个类
        *       ARGS:NEW类的时候传递的实参集合
        *   @return:
        *       实例或者自己返回的对象
        */
        function _new(Func, ...args) {
            // =>在此是执行的过程
            // 默认创建一个实例对象(而且是属于当前这个类的一个实例)
            // let obj = {};
            // 若想要obj指向Dog的原型,需要以下代码
            // obj.__proto__ = Func.prototype; //=> IE大部分浏览器中不允许我们直接操作__proto__,所以可以直接将lei obj = {}和obj.__proto__ = Func.prorotype合并为下边的一步:
            let obj = Object.create(Func.prototype);


            // 也会把类当做普通函数执行
            // 执行的时候要保证函数中的THIS指向创建的实例
            let result = Func.call(obj, ...args);//当做普通函数执行,传参数...args,要把this指向当前的实例,使用call转换this
            // 若客户自己返回引用值,则以自己返回的为主,否则返回创建的实例
            if ((result != null && typeof result === "object") || (typeof result === "function")) {
                return result
            }
            return obj;
        }
        let sanmao = _new(Dog, '三毛');
        console.log(sanmao); //name: "三毛" 原型指向object __proto__: Object ,是没有指向Dog.protoType的,sanmao.bark()会报错,Uncaught TypeError: sanmao.bark is not a function,因为原型没有指对
        /*
        若使用new,在控制台中输入 sanmao = new Dog();原型指向Dog.prototype,结果是这样的:sanmao= new Dog('三毛');
        Dog {name: "三毛"}
            name: "三毛"
            __proto__: Object
                bark: ƒ ()
                sayName: ƒ ()
                constructor: ƒ Dog(name)
                __proto__: Object
        */
        sanmao.bark(); //=>'wangwang' 
        sanmao.sayName();//=>"my name is 三毛"l
        console.log(sanmao instanceof Dog); //=>true
    </script>
</body>

</html>

内置NEW的实现原理
@params:
Func:操作的那个类
ARGS:NEW类的时候传递的实参集合
@return:
实例或者自己返回的对象
function new(Func, …args) {
// =>在此是执行的过程
// 默认创建一个实例对象(而且是属于当前这个类的一个实例)
// let obj = {};
// 若想要obj指向Dog的原型,需要以下代码
// obj.proto = Func.prototype; //=> IE大部分浏览器中不允许我们直接操作__proto
_,所以可以直接将lei obj = {}和obj.proto = Func.prorotype合并为下边的一步:
//create方法,可见https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
let obj = Object.create(Func.prototype);

        // 也会把类当做普通函数执行
        // 执行的时候要保证函数中的THIS指向创建的实例
        let result = Func.call(obj, ...args);//当做普通函数执行,传参数...args,要把this指向当前的实例,使用call转换this
        // 若客户自己返回引用值,则以自己返回的为主,否则返回创建的实例
        if ((result != null && typeof result === "object") || (typeof result === "function")) {
            return result
        }
        return obj;
    }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!