zoukankan      html  css  js  c++  java
  • javascript面向对象编程(OOP)——汇总

    目录

    • 一、JS的解析与执行过程

      • 预处理阶段
      • 执行阶段
    • 二、作用域

      • 块作用域
      • 函数作用域
      • 动态作用域
      • 词法作用域
    • 三、闭包

      • 什么是闭包
      • 闭包的好处
    • 四、函数与对象

      • 对象
      • 函数

      •  

        原型(prototype)

      •  

        this

      •  

        new的理解

    • 五、封装

    • 六、继承

    • 七、多态

    • 八、项目实战minijQuery

    一、JS的解析与执行过程

    1.1、预处理阶段

    注意:js预处理阶段会扫描所有var声明的变量,把var声明的变量或函数存放到词法作用域里,如果是变量初始值为“undefined”,如果是函数则指向函数;

    全局(window)

      词法作用域(Lexical Environment)顶级的Lexical Environment是window;

      1、先扫描函数声明后扫描变量(var声明);

      2、处理函数声明有冲突,会覆盖;处理变量声明时有冲突,会忽略。

    函数

      词法作用域(Lexical Environment):每调用一次,产生一个Lexical Environment;

      1、先函数的参数:比如arguments(函数内部对象,代表函数实参,可通过下标获取调用函数时传的实参)

      2、先扫描函数声明后扫描变量(var声明);

      3、处理函数声明有冲突,会覆盖;处理变量声明时有冲突,会忽略。

    1.2、执行阶段

      1、给预处理阶段的成员赋值

      2、如果没有用var声明的变量,会成为最外部LexicalEnvironment的成员(即window对象的变量)

    函数内部对象:arguments

    <script>
        /*提示:*/
        // arguments是每一个函数内部的一个对象
        // 可以访问实际传递给函数的参数的信息。
        // 声明的时候参数的个数与实际调用时无关
        
        function add(a,b){
        console.log(add.length);// 形参的个数
        console.log(arguments.length);// 实际传过来的参数
        var total = 0;
        for(var i = 0;i< arguments.length;i++){
            total += arguments[i];
        }
        return total;// 返回实参的总和
        }
        
        // 调用时传的实参
        var result = add(1,2,3,4,5);
        var result2 = add(1,2);
        
        console.log(result);// 15
        console.log(result2);// 3
    </script>
    View Code

    二、作用域

    提示:js的作用域不是块级别的;js的作用域是函数级别的。

    2.1、块作用域

    2.2、函数作用域

    2.3、动态作用域

    2.4、词法作用域

    代码示例:

    <script>
                //js作用域
                // 定义:用来查找变量的值的规则集;决定一个变量的范围
                // 提示:js的作用域不是块级别的;js的作用域是函数级别的。
                // javascript使用的是词法作用域,它的最重要的特征是它的定义过程发生在代码的书写阶段
                
                /*以下js代码用立即调用写法(私有化),避免变量冲突*/
                
                //1、块作用域:代码在花括号里面有效(js没有块作用域)
                (function(){
                    for(var i=0;i<5;i++){
                        var a = i ;
                    }
                    // 在花括号外面可以访问到i,a
                    console.log(i);// 5
                    console.log(a);// 4
                })();
                
                
                //2、函数作用域:代码在function()函数的花括号里面有效
                (function(){
                    var message = "函数外部的";
                    function fn(){
                        var message = "函数内部的";
                        console.log(message);// 函数内部的
                    }
                    console.log(message);// 函数外部的
                })();
                
                
                //3、动态作用域:在运行时决定(是this指向的表现;谁调用,this指向谁);动态作用域其实是指this的词法作用域
                    // 动态作用域并不关心函数和作用域是如何声明以及在任何处声明的,只关心它们从何处调用。
                    // 换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套
                (function(){
                    var a = 2;
                    function foo() {
                        console.log( a );
                    }
                    function bar() {
                        var a = 3;
                        foo();// 此时this===window
                    }
                    bar();// 2
                })();
                /*
                var a = 2;
                bar = {
                    a:3,
                    foo:function(){
                        console.log(this.a);
                    }
                }
                bar.foo();//3
                */
                
    
                //4、词法作用域:词法作用域(也称为静态作用域或闭包)
                    // js的作用域解析,用new Function创建函数
                (function(){
                    // 闭包
                    var a = 2;
                    function bar() {
                        var a = 3;
                        return function(){
                            console.log(a);// 此时捕获a=3
                        };
                    }
                    var foo = bar();
                    foo();// 3
                })();
                
                
                
                // 如果处于词法作用域,也就是现在的javascript环境。变量a首先在foo()函数中查找,没有找到。于是顺着作用域链到全局作用域中查找,找到并赋值为2。所以控制台输出2
              // 如果处于动态作用域,同样地,变量a首先在foo()中查找,没有找到。这里会顺着调用栈在调用foo()函数的地方,也就是bar()函数中查找,找到并赋值为3。所以控制台输出3
                
                //小结:两种作用域的区别,简而言之,词法作用域是在定义时确定的,而动态作用域是在运行时确定的
                
            </script>
    View Code

    三、闭包(Closure)

    3.1、什么是闭包

    由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数,内部函数并访问父函数的局部变量”。

    理解闭包:

      1、闭包可以理解为一个对象,里面包含函数以及被函数捕获的变量 , 一个圈里包含函数与捕获的变量 

      2、也可以只把函数捕获的变量称之为闭包。 

    <script>
        //如何写会产生闭包
        function P(){
        var a = 5;
        var b = 6;
        return function C(){
            console.log(b);//此时捕获变量b,值为6
        }
            
        }
        var result = P();
        result();// 6
    </script>

    产生闭包的条件:

      1、函数内部包含子函数;

      2、子函数访问父函数的变量;

    3.2、闭包的好处

      用途:一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

    <script>
        // 闭包实例
        function Person(){
            var age = 1;
            this.getAge = function(){
                return age ;
            }
            
            this.setAge = function(val){
                   age = val;
            }
        }
        var p = new Person();
        p.setAge(20);
        console.log(p.getAge());
    </script>

    代码示例:

    <script type="text/javascript">
        /*闭包--理解*/
        // 提示:this由运行时决定!
    
        // 题目一:理解r1与r2的输出
        function addFactory(){
            var adder = 5;
            return function(data){
                adder += data;// 此时adder变量是闭包捕获到的值
                return adder;
            }
        }
        var adder1 = addFactory();
        var r1 = adder1(1);//6
        r1 = adder1(1);//7
        
        var adder2 = addFactory();
        var r2 = adder2(2);//7
        r2 = adder2(2);//9
        
        
        // 题目二:下面的代码输出什么
         var name = "The Window";
      var object = {
        name : "My Object",
        getNameFunc : function(){
          return function(){
            return this.name;// 输出"The Window";this = window;
                    //return object.name;// 输出"My object"
          };
        }
      };
      //alert(object.getNameFunc()());// The Window
        
        // 理解二:
        var fun = object.getNameFunc();// 返回一个函数,此时函数this指向window;window.fun()
        alert(fun());// 所以,输出是:"The Window"
        
        
        // 题目三:
        var name = "The Window";
      var object = {
        name : "My Object",
        getNameFunc : function(){
          var that = this;//this = object;
          return function(){
            return that.name;//闭包捕获父函数的that,that = object;
          };
        }
      };
      alert(object.getNameFunc()());// My Object
        
        // 理解三:
        // var obj = object.getNameFunc();
        // alert(obj());// 此时函数由于内部的name是object调用
        
    </script>
    View Code

    四、函数与对象

    4.1、对象

    4.2、函数

    4.3、原型(prototype)

     javascript对象部署:

    JavaScript是一种通过原型实现继承的语言;在JavaScript中所有都是对象,原型(prototype)也是一个对象,通过原型可以实现对象的属性继承;

       prototype:在js中是函数特有的属性;指向该函数的原型(this.prototype)

      __proto__:在js中是所有对象都有的属性;指向此对象的构造器(函数)的原型对象(prototype)

    <!-- 
        对象都有这属性(找对象的父类对象):__proto__;
        只有函数有的属性(找函数的原型,是个对象):prototype;
        对象(或函数)的构造器(顶级构造器时Function()):constructor;
     -->
    <script>
        function Aaa(){}
        //undefined
        var aaa = new Aaa();
        //undefined
        aaa.__proto__;
        //{constructor: ƒ}
        Aaa.prototype;
        //{constructor: ƒ}
        aaa.__proto__ === Aaa.prototype;
        //true
        aaa.constructor;
        //ƒ Aaa(){}
        Aaa.constructor;
        //ƒ Function() { [native code] }
        aaa.constructor.constructor
        //ƒ Function() { [native code] }
        
    </script>

    原型理解:

    1. 函数Foo的__proto的值等于Foo.prototype,对吗?
        错,函数Foo.__proto__===Function.prototype,函数Foo的实例的__proto__属性的值等于函数Foo.prototype
        
    2.Object的prototype可以修改吗?能与不能原因是什么?
        //可以,函数(对象)的原型可以任意修改或继承
        不可以,因为Object.prototype是只读,所以不能赋值;但可以修改或添加
        
    3. 顶级constructor是谁?
        Function()
        
    4.顶级原型对象是谁?
        Object
        
    5.对象的construtor成员是个属性还是个方法?
        可以是属性,也可以是方法(一般不建议这么写,耗资源,在每次new是都要执行很多代码)
        
    6.Function有没有__proto__,为什么?值等于Object.prototype吗?
        1.有(是对象都有),与prototype相等,因为Function是顶级构造器,所以,函数的__proto__属性指向的构造器原型是与Function.prototype相等;
        2.不等于,Function.prototype与Function.__proto__指向function.prototype
    
        
    7.所有的构造器的__proto__都等于其对应的prototype
        错,等于Function.prototype;因为对象的__proto__属性指向的是对象的构造器的prototype(函数的构造器是Function())
        
    8.创建类形式的继承的四部曲是什么?
        1.创建父类
        2.创建子类
        3.确定继承关系:A.prototype = Object.create(B.prototype);
        4.修改构造器(因为继承后的构造器指向是父类的原型指向的构造器,也就是说,子类的原型指向的构造器===父类的原型指向的构造器)
        
    9.Function的constructor于prototype值可以修改吗?
        不可以,Function是顶级构造器,Function.__proto__指向Function.prototype
        
    10.Object.prototype === Object.__proto__吗?
        不相等,Object.prototype是object.prototype;Object.__proto__是function.prototype
        
    11. Function.prototype === Function.__proto__吗?
        相等,(因为Function是顶级构造器,__proto__指向Function.prototype)Function.prototype===Function.__proto__
        
    12. function F(){}; var f1 = new F();
       f1.__proto__ === Object.prototype吗?
       不对,f1.__proto__ === F.prototype;f1.__proto__.__proto__ === Object.prototype;
       
    View Code

    4.5、this

    原则:

      1、this由运行时决定!

      2、函数中 this 到底指向谁 , 由调用此函数时的对象决定 , 而不是由定义函数所在的对象决定。

      在JavaScript中this表示:谁调用它,this就是谁。

     如何改变this指向:

      call:

      apply:

    <script>
        /*
        var data = {};
        Array.prototype.push.call(data,100,200);
        Array.prototype.push.apply(data,[1,2,3,8,10]);
        console.log(data);
        */
    </script>

    4.6、new的理解

      简单的可以理解为:new改变了this指向的对象;

    五、封装

    六、继承

    七、多态

    八、项目实战minijQuery

    <script type="text/javascript">
        /*
            // 提示:
            // 暴露外部使用的一个接口
            var jQuery = window.jQuery = window.$ = function(selector){
                return new jQuery.fn.init(selector); 
            }
            
            // 处理原型对象
            jQuery.fn = jQuery.prototype = {}
            jQuery.fn.init.prototype = jQuery.fn;
            
            // 实现继承,并且只处理只有一个参数,也就是插件的扩展
            jQuery.extend = jQuery.fn.extend = function(){}
            
            // 添加静态方法
            jQuery.extend({});
            
            // 添加实例方法
            jQuery.fn.extend({});
            
            // 1.获取节点对象
            var jq1 = jQuery(".pp");
            或
            var jq1 = jQuery.fn.init(".pp");
        */
        
        // 提供全局访问接口($()、jQuery())
        (function  () {
            /// 暂时把window的全局变量存起来,用做处理变量冲突
            var _$ = window.$;
            var _jQuery = window.jQuery;
            
            //暴露外部使用的一个接口(获取节点对象)
            var jQuery = window.jQuery = window.$ = function(selector){
    
                return new jQuery.fn.init(selector);// init.prototype;
            };
    
        //处理原型对象
            jQuery.fn = jQuery.prototype = {
                init:function(selector){
                    var elements = document.querySelectorAll(selector);
                    Array.prototype.push.apply(this,elements);
                    return this;
                },
                version:"1.0.0",
                length:0,
                size:function(){
                    return this.length;
                }
    
            };
            // jQuery.fn.init.prototype === init.prototype;
            // jQuery.prototype;
            jQuery.fn.init.prototype = jQuery.fn;
        //实现继承,并且只处理只有一个参数,也就是插件的扩展
            jQuery.extend = jQuery.fn.extend = function(){
                var o = arguments[0];
                for(var p in o){
                    this[p] = o[p];
                }
            };
            /// 测试:(继承方法)
                // var obj = {name:"张三三"}
                // var jq = $(".pp");
                // jq.extend(obj);
    
        //添加静态方法
            jQuery.extend({
                trim:function(text){
                    return (text||"").replace(/^s+|s+$/g,"");// 替换text字符串的开头和结尾匹配任何空白字符为空(即,替换开头和结尾的空格字符为空)
                },
                noConflict:function(){
                    window.$ = _$;
                    window.jQuery = _jQuery;
                    return jQuery;
                }
            });
            
            /// 测试:(命名冲突)
                // var jq = jQuery.noConflict();//返回一个jQuery函数,解决与全局的jQuery属性冲突
                // var obj = jq(".pp");
                
            
        //添加实例方法
            jQuery.fn.extend({
                get:function(num){
                    return this[num];
                },
                each:function(fn){
                    for(var i = 0 ;i< this.length; i++){
                        fn(i,this[i]);
                    }
                    return this;
                },
                css:function(){
                    var l = arguments.length;
                    if(l == 1){
                        return this[0].style[arguments[0]];
                    } else {
                        var name = arguments[0];
                        var value = arguments[1];
                        this.each(function(index,ele) {
                            ele.style[name] = value;
    
                        });
                    }
                    return this;
                }
    
            });
    
        })();
    </script>
    View Code
  • 相关阅读:
    Docker可视化管理工具Portainer
    Spring Cloud,Docker书籍资源、优秀博文等记录
    Grafana部署监控docker服务
    Grafana+Prometheus通过node_exporter监控Linux服务器信息
    Prometheus+Grafana+kafka_exporter监控kafka
    k8s gpu 资源设置
    mysql 塞数据
    idea 插件
    ubuntu 升级内核
    清华镜像站安装docker
  • 原文地址:https://www.cnblogs.com/begin-world/p/7902532.html
Copyright © 2011-2022 走看看