zoukankan      html  css  js  c++  java
  • 收藏的js学习小例子

    1.js模拟java里的Map

                function Map(){
                        var obj = {} ;
                        this.put = function(key , value){
                                obj[key] = value ;        
                        }
                        this.size = function(){
                                var count = 0 ; 
                                for(var attr in obj){
                                    count++;
                                }
                                return count ; 
                        }
    
                        this.get = function(key){
                            if(obj[key] || obj[key] === 0 || obj[key] === false){
                                return obj[key];
                            } else {
                                return null;
                            }
                        }
    
                        this.remove = function(key){
                            if(obj[key] || obj[key] === 0 || obj[key] === false){
                                delete obj[key];                        
                            }
                        }
                        
                        this.eachMap = function(fn){
                                for(var attr in obj){
                                    fn(attr, obj[attr]);
                                }
                        }
                        
                        
                    }
                
                
                    var m = new  Map();
                    m.put('01' , 'abc');
                    m.put('02' , false) ;
                    m.put('03' , true);
                    m.put('04' , new Date());
    
                    m.eachMap(function(key , value){
                         alert(key +" :"+ value);
                    });
    js模拟java里的Map

    2.去除数组重复项

                var arr = [2,1,2,10,2,3,5,5,1,10,13];    
                
                // js对象的特性 : 在js对象中 key 是永远不会重复的 
    
                // 1 把数组转成一个js的对象
                // 2 把数组中的值,变成js对象当中的key
                // 3 把这个对象 再还原成数组
                
                // 把数组转成对象
                function toObject(arr){
                    var obj = {} ; // 私有的对象
                    var j ;
                    for(var i=0 , j= arr.length ; i<j; i++){
                            obj[arr[i]] = true ;
                    }
                    return obj ;
                }
                
                // 把这个对象转成数组
                function keys(obj){
                    var arr = [] ; // 私有对象
                    for(var attr in obj){
                        if(obj.hasOwnProperty(attr)){         
                            arr.push(attr);
                        }
                    }
                    return arr ;
                }
                
                //综合的方法 去掉数组中的重复项
                function uniq(newarr){
                    return keys(toObject(newarr));
                }
                
                alert(uniq(arr));
    去除数组重复项

    3.继承案例

            <script type=text/javascript>
            
                
                var __extends = this.__extends || function (sub, sup) {
                    for (var p in sup) if (sup.hasOwnProperty(p)) sub[p] = sup[p];//继承父类自身属性
                    function __() { this.constructor = sub; } 
                    __.prototype = sup.prototype;
                    sub.prototype = new __();
                    
                    alert(sub.prototype.constructor);
                };
                
                function extend(sub,sup){
                    var F=new Function();//创建一个空函数
                    F.prototype=sup.prototype;//空函数原型指向父类原型
                    sub.prototype=new F();
                    sub.prototype.constructor = sub;
                    sub.superClass =sup.prototype;//保持父类原型
                    //判断父类原型对象的构造器
                    if(sup.prototype.constructor==Object.prototype.constructor){
                        //如果简单原型覆盖 则手动添加
                        sup.prototype.constructor=sup;
                    }
                }
                
                
                function Person(name,age){
                    this.name=name;
                    this.age=age;    
                }
                Person.ff='sssc';
                
                Person.prototype={
                    sayName : function(){
                        alert("对对")    
                    }             
                }
                            
                function Boy(name ,age,sex){
                    //或者 Boy.superClass.constructor.call(this,name,age)
                    Person.call(this,name,age);
                    this.sex=sex;
                }
                //Boy.prototype=new Person();
                __extends(Boy,Person);//继承
                var b=new Boy('对对',23,'男');
                alert(b.name);
                alert(b.age);
                alert(b.sex);            
                b.sayName();
                
                
               alert(Boy.prototype.constructor.ff);//输出父类自身属性
                
                
            </script>
    继承案例

    4.链式编程

            /***
             * //简单的链式编程
             *     var person={
                        run:function(){
                            alert("跑");
                            return this;            
                        },
                        jump:function(){
                            alert("跳");    
                            return this;
                            
                        },
                        sleep:function(){
                            alert("睡");
                            return this;
                        }                                            
                }
                        
                person.run().jump().sleep();
             */    
            
            
            
            (function(window,undefined){
                //定义私有_$方法
                function _$(arguments){
                    //正则表达式匹配id选择器
                    var idselector=/^#w+$/;
                    this.dom //此属性接收所得到的元素.
                    if(idselector.test(arguments[0])){
                        this.dom=document.getElementById(arguments[0].substring(1));
                    }else{
                        throw Error (' arguments is error');
                    }
                    
                    
                };    
                
                //在Function上扩展一个可以实现链式编程的方法
                Function.prototype.method=function(methodName,fn){
                    this.prototype[methodName]=fn;
                    return this;
                    
                };
                
                _$.prototype={
                    constructor:_$,
                    addEvent:function(type,fn){
                        if (window.addEventListener) { //ff
                            this.dom.addEventListener(type, fn);
                        }
                        else if (window.attachEvent) {//ie
                            this.dom.attachEvent("on"+type,fn);
                            
                        }
                        return this;
                    },
                    setStyle:function(property,val){
                             this.dom.style[property]=val;
                            return this;
                    }
                    
                };
                
                
                window.$=_$;    
                _$.onReady=function(fn){
                    //1.实例化出来_$对象 真正的注册到window上
                    window.$=function (){
                            return new _$(arguments);
                        
                    } ;
                    //2.执行代码
                    fn();
                    //3.实现链式编程
                    _$.method('addEvent',function(){
                        alert('111');
                        return this;
                    }).method('setStyle',function(){                    
                        alert('222');
                        return this;
                    });
                    
                    _$.prototype.addEvent().setStyle();
                 
                    
                }    
                
            })(window) ;
            
            
             $.onReady(function(){
                 $("#inp").addEvent("dblclick",function(){
                    alert("双击");
                }).setStyle("backgroundColor","red"); 
               
             });
            </script>
    js链式编程

    5.组合模式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>组合模式</title>
            <script type=text/javascript>
                /***
                 * 
                 * 公司-
                 *         部门1
                 *             人员1
                 *             人员2
                 *             人员3
                 *         部门2
                 *             人员4
                 *             人员5
                 *             人员6
                 */
                
                
                
                /***
                 * 
                 * 普通方式实现
                 */
                 var Org =function(name){
                     this.name=name;
                    this.depts=[];                
                 }
                 Org.prototype={
                     constructor:Org,
                    addDepts:function(child){
                        this.depts.push(child);
                        return this;                    
                    },
                    getDepts:function(){
                        return this.depts;                     
                    }
                 }
                 
                 var Dept=function(name){
                     this.name=name;
                    this.persons=[];
                 };             
                 Dept.prototype={
                     constructor:Dept,
                    addPersons:function(child){
                        this.persons.push(child);
                        return this;                    
                    },
                    getPersons:function(){
                        return this.persons;
                        
                    }                
                 };
                 
                 var Person=function(name){
                     this.name=name;                
                 }
                 
                 Person.prototype={
                     constructor:Person,
                    work:function(){
                        document.write(this.name+'工作,');                    
                    }                
                 }
     
                 var p1=new Person('人员1')
                var p2=new Person('人员2')
                var p3=new Person('人员3')
                var p4=new Person('人员4')
                var p5=new Person('人员5')
                var p6=new Person('人员6')
                
                var dept1=new Dept('部门1');
                dept1.addPersons(p1).addPersons(p2).addPersons(p3);
                var dept2=new Dept('部门2');
                 dept2.addPersons(p4).addPersons(p5).addPersons(p6);
                
                
                var org =new Org('yjq');
                org.addDepts(dept1).addDepts(dept2);
                
                //循环工作
                for(var i=0,depts= org.getDepts();i<depts.length;i++){
                    var dept=depts[i]; 
                    for(var j=0,persons=dept.getPersons();j<persons.length;j++){
                        if(persons[j].name ==='人员4'){
                            //persons[j].work();                        
                        }
                    }
                }            
                //可维护性差
                
                
                
                /***
                 * 组合模式方式实现
                 * 
                 * 场景:
                 * 1.存在一批组织成某种层次体系的对象
                 * 2.希望对这批对象或其中的一部分对象实施一个操作
                 * 
                 * 特点:
                 * 1.组合模式中只有两种类型对象:组合对象,叶子对象
                 * 2.这两中类型都实现同一批接口
                 * 3.一般我们会在组合对象中调用其他方法并隐式调用'下级对象'的方法(递归)
                 */
                
                var Composite=function(name){
                    this.name=name;
                    this.type='Composite';//说明对象类型
                    this.children=[];
                };
              Composite.prototype={
                    constructor:Composite,
                    addChild:function(child){
                        this.children.push(child);
                        return this;
                    },
                    getChild:function(name){
                        //接收叶子对象
                        var elements=[];
                     
                      //判断对象是否为Leaf类型的,是则添加到数组,否则继续递归
                        var pushLeaf=function(item){
                            if(item.type=='Composite'){
                                item.children.forEach(arguments.callee);
                            }else if(item.type==='Leaf'){
                                elements.push(item);
                            }
                        };
                        //根据name 让指定name下所有的类型为Leaf的对象执行
                        if(name&& this.name!==name){
                             this.children.forEach(function(item){
                                 
                                 //如果传递的name是2级节点名称
                                if(item.name===name&&item.type==='Composite'){
                                    item.children.forEach(pushLeaf);
                                }
                                //如果name是3级,4级.....节点
                                if(item.name!==name&&item.type==='Composite'){
                                    item.children.forEach(arguments.callee);
                                }
                                
                                //如果传递的name是叶子节点的时候
                                if(item.name===name&&item.type==='Leaf'){
                                    elements.push(item);
                                }
                             });
                            
                        }else{//不传递name 则是整个公司leaf
                              this.children.forEach(pushLeaf);         
                        } 
                         
                    
                        
                        //返回
                        return  elements;
                        
                    },
                    work:function(name){
                        //获取leaf类型对象节点
                        var leafObjects=this.getChild(name);
                        for(var i=0;i<leafObjects.length;i++){
                            leafObjects[i].work();
                        }
                    }                
                }
                
                var Leaf=function(name){
                    this.name=name;
                    this.type='Leaf';//说明对象类型
                }
                 
                   Leaf.prototype={
                    constructor:Leaf,
                    addChild:function(child){
                        throw new Error('error');
                    },
                    getChild:function(name){
                        if(this.name=name){
                            return this;
                        }
                        return null;
                    },
                    work:function(){
                        document.write(this.name+'工作,');         
                    }                
                }
                
                var _p1=new Leaf('人员1');
                var _p2=new Leaf('人员2');
                var _p3=new Leaf('人员3');
                var _p4=new Leaf('人员4');
                var _p5=new Leaf('人员5');
                var _p6=new Leaf('人员6');
                var _p7=new Leaf('人员7');
                var _p8=new Leaf('人员8');
                var _p9=new Leaf('人员9');
                var _p10=new Leaf('人员10');
                var _p11=new Leaf('人员11');
                var _p12=new Leaf('人员12');
                
                var _dept1=new Composite('部门1');
                _dept1.addChild(_p1).addChild(_p2).addChild(_p3);
                var _dept2=new Composite('部门2');
                 _dept2.addChild(_p4).addChild(_p5).addChild(_p6);
                    
                var _dept3=new Composite('部门3');
                _dept3.addChild(_p7).addChild(_p8).addChild(_p9);
                var _dept4=new Composite('部门4');
                 _dept4.addChild(_p10).addChild(_p11).addChild(_p12);
                
                
                var org1 =new Composite('公司1');
                org1.addChild(_dept1).addChild(_dept2);
                var org2 =new Composite('公司2');
                org2.addChild(_dept3).addChild(_dept4);
                
                
                var org =new Composite('公司');
                org.addChild(org1).addChild(org2);
                org.work('公司1');
            </script>
        </head>
        <body>
        </body>
    </html>
    js组合模式

    6.装饰者模式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>装饰者模式</title>        
            <script type=text/javascript>
                /***
                 * 装饰者(decorator)模式
                 * 作用:为对象添加新特性;
                 * 实现:
                 * 1.实现同样的接口(具有相同的方法)
                 * 2.需要有子类
                 * 3.子类需要接收父类的的引用
                 * 简单的说就是:需要装饰的类(父类)把它的引用传递给装饰类(子类)让装饰类装饰
                 */
                 var Car =function(car){
                     //为了让子类继承(让子类多一个父类的引用)
                     this.car=car;                 
                 };
                 Car.prototype={
                     constructor:Car,
                    getPrice:function(){
                        return  1000;
                    },
                    assemble:function(){
                        alert('car');
                    }
                 };
                 
                 //新需求:加车灯 需要加钱(方法改变)
                 
                 var LightDecorator=function(car){ //原始对象
                     Car.call(this,car);//借用构造函数继承
                 }     
                 LightDecorator.prototype=new Car();//原型继承
                 
                 LightDecorator.prototype={
                     constructor:LightDecorator,
                    //重写父类方法
                    getPrice:function(){
                        return this.car.getPrice()+11; //继承过来的car 有父类的引用  加钱11
                    },
                    assemble:function(){
                        alert('LightCar');
                    }
                 }
                 
                 //需要加其他的
                 var OtherDecorator=function(car){ //原始对象
                     Car.call(this,car);//借用构造函数继承
                 }     
                 OtherDecorator.prototype=new Car();//原型继承
                 
                 OtherDecorator.prototype={
                     constructor:OtherDecorator,
                    //重写父类方法
                    getPrice:function(){
                        return this.car.getPrice()+1; //继承过来的car 有父类的引用  加钱1
                    },
                    assemble:function(){
                        alert('OtherCat');
                    }
                 }
                 
                 var car =new Car();
                 alert(car.getPrice());
                 car.assemble();
                 
                 car =new LightDecorator(car);
                 alert(car.getPrice());
                 car.assemble();
                 
                 
                 car =new OtherDecorator(car);
                 alert(car.getPrice());
                 car.assemble();
                 
                 
                 
                 //返回一个当前时间的字符串表示形式
                 function getDate() {
                     return new Date().toString();
                 }
                 
                 function upperCaseDecorator(fn){
                     return function(){
                            return fn.apply(this,arguments).toUpperCase();
                    }
                 }
                 
                 alert(getDate());
                 alert(upperCaseDecorator(getDate)());
            </script>
        </head>
        <body>
        </body>
    </html>
    js装饰者模式

    7.桥接模式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>桥接模式</title>
            <script type="text/javascript">
                /**
                 * 桥接模式:主要是把抽象和实现分离,使它们完全独立
                 */
            var PublicClass= function(){
                //私有化变量
                var privateMethod =function(){                
                    alert('do something....');
                }
                
                //可单元测试
                privateMethod();
                
                //通过特权函数去访问这个私有的独立单元
                this.bridgeMethod=function(){                
                    return privateMethod();
                }            
            };
            
            var p = new PublicClass();
            p.bridgeMethod();
                
            </script>
        </head>
        <body>
        </body>
    </html>
    js桥接模式

    8.观察者模式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>观察者模式</title>
            <script type=text/javascript>
                /**
                 * 观察者模式:对程序中的某一个对象的进行实时的观察,当该对象状态发生改变的时候 进行通知
                 * 观察者、被观察者
                 * 案例:订报纸 (报社:发布者、订阅者)
                 */
                //发布者(被观察者)
                var Publish=function(name){
                    this.name=name;
                    this.subscribers=[];//接受所以的订阅者(每一个元素是函数的类型fn)数组
                };
                
                //Publish类的实例对象去发布消息的方法
                Publish.prototype.deliver=function(news){
                    var publish=this;
                    this.subscribers.forEach(function(fn){
                        fn(news,publish);//把消息发给一个订阅者
                    });
                    return this;//链式编程
                }
                
                
                //具体的一个订阅者去订阅报纸的方法
                Function.prototype.subscribe=function(publish){
                    var sub =this;//取得具体订阅者这个人
                    //some方法:循环遍历数组的每一个元素,执行一个函数,如果其中有一个返回true,那么整天返回true
                    var alreadyExists =publish.subscribers.some(function(item){
                        return item===sub;
                    });
                    //如果当前出版社里不存在这个人,则将其加入其中
                    if(!alreadyExists){
                        publish.subscribers.push(this);
                    }
                    return this;//链式编程
                }
                
                //具体的一个订阅者去取消订阅报纸的方法
                Function.prototype.unsubscribe=function(publish){
                    var sub=this;//具体的这个人
                    //filter:过滤函数,循环遍历数组的每一个元素,执行一个函数如果不匹配,则删除该元素
                    publish.subscribers=publish.subscribers.filter(function(itme){
                        return item!==sub;
                    });
                    return this;//链式编程
                } 
                
                
                window.onload=function(){
                    //实例化发布者对象(报社对象、被观察者)
                    var pub1=new Publish('报社1');
                    var pub2=new Publish('报社2');    
                    var pub3=new Publish('报社3');            
                    
                    //观察者(订阅者)
                    var sub1 = function(news){
                        document.getElementById('sub1').innerHTML+=arguments[1].name+':'+news+'/n';
                    };
                    var sub2 = function(news){
                        document.getElementById('sub2').innerHTML+=arguments[1].name+':'+news+'/n';
                    };
                    
                    //执行订阅的方法
                    sub1.subscribe(pub1).subscribe(pub2).subscribe(pub3);
                    sub2.subscribe(pub1).subscribe(pub2);
                    
                    //事件绑定
                    YJQ.EventHelper.addHandler(document.getElementById('pub1'),'click',function(){
                        pub1.deliver(document.getElementById('text1').value);
                    });
                    YJQ.EventHelper.addHandler(document.getElementById('pub2'),'click',function(){
                        pub2.deliver(document.getElementById('text2').value);
                    });
                    YJQ.EventHelper.addHandler(document.getElementById('pub3'),'click',function(){
                        pub3.deliver(document.getElementById('text3').value);
                    });
                    
                }
            </script>
        </head>
        <body>
            <input id="pub1" type="button" value="报社1"/><input id="text1" value=""/><br/>
            <input id="pub2" type="button" value="报社2"/><input id="text2" value=""/><br/>
            <input id="pub3" type="button" value="报社3"/><input id="text3" value=""/><br/>
            
            <textarea id="sub1" rows="5" cols="30"></textarea>
            <textarea id="sub2" rows="5" cols="30"></textarea>
        </body>
        <script type=text/javascript>
            var YJQ={};
            YJQ.EventHelper={
                addHandler:function(element,type,handler){
                    if(element.addEventListener){  //FF
                        element.addEventListener(type,handler,false);
                    }else if(element.attachEvent){//IE
                        element.attachEvent('on'+type,handler);
                    }
                },
                removeHandler:function(element,type,handler){
                    if(element.addEventListener){  //FF
                        element.removeEventListener(type,handler,false);
                    }else if(element.attachEvent){//IE
                        element.detachEvent('on'+type,handler);
                    }
                }
                
            }
            
        </script>
    </html>
    js观察者模式

    9.代理模式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>代理模式</title>
            <script type=text/javascript>
                /**
                 * 代理模式(proxy):代理也是对象,它的目的就是为了节制(控制)对本体对象的访问
                 * 代理对象和另一个对象(实体对象)实现的是同样的接口,实际上工作还是实体在做
                 */
                
                var Book=function(id,title,author){
                    this.id=id;
                    this.title=title;
                    this.author=author;                
                };
                //图书馆(本体对象,实例化图书馆需要消耗很多的资源)
                var Library=function(books){
                    this.books=books;
                }
                Library.prototype={
                    constructor:Library,
                    addbook:function(book){
                        this.books[book.id]=book;
                    },
                    findbook:function(id){
                        if(this.books[id]){
                            return this.books[id];
                        }
                        return null;
                    },
                    checkoutbook:function(id){
                        return this.findbook(id);
                    },
                    returnbook:function(book){
                        this.books[book.id]=book;
                    } 
                }
                
               //图书馆的代理对象
                var LibraryProxy=function(books){
                    this.books=books;
                    this.libray=null;//定义一个空对象
                }
                LibraryProxy.prototype={
                    constructor:LibraryProxy,
                    
                    //初始化Library
                    initializeLibrary:function(){
                        if(this.libray==null){
                            this.libray=new Library(this.books);
                        }
                    },                
                    addbook:function(book){
                        this.initializeLibrary();
                        this.libray.books[book.id]=book;
                    },
                    findbook:function(id){
                        this.initializeLibrary();
                        if(this.libray.books[id]){
                            return this.libray.books[id];
                        }
                        return null;
                    },
                    checkoutbook:function(id){
                        this.initializeLibrary();
                        return this.libray.findbook(id);
                    },
                    returnbook:function(book){
                        this.initializeLibrary();
                        this.libray.books[book.id]=book;
                    } 
                }
             
                var proxy=new LibraryProxy({
                    '1':new Book('1','c#','y'),
                    '2':new Book('2','js','z'),
                });
                alert(proxy.findbook('1').title);//c#
            </script>
        </head>
        <body>
        </body>
    </html>
    js代理模式

    10.单例模式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>单例模式</title>
            <script type=text/javascript>
            //单例模式(singliton)    
            //1.简单单例
            var Singliton={
                name:'yjq',
                age:'23',
                sayHello:function(){
                    alert('hello');
                }
            };
            alert(Singliton.name);
            Singliton.sayHello();    
            //另一个作用 :划分命令空间
            
            //2.借用闭包创建单例:闭包主要的目的 保护数据
            //命名空间
            var YJQ ={};
            YJQ.Singleton=(function(){
                //添加自己的私有成员
                var name = 'yjq';
                var age ='23';
                
                //把块级作用域里的执行结果赋值给单体对象
                return {
                    name:name,
                    age:age,
                    sayHello:function(){
                        alert('hello');
                    }
                };
            })();
            alert(YJQ.Singleton.name);
            YJQ.Singleton.sayHello();
            
            //3.惰性单例(常用)
            var Ext={};
            Ext.Base=(function(){
                //私有变量 控制返回的单例对象
                var uniqInstance; //undefined
                
                //需要一个构造器 init初始化单例对象的方法
                function init(){
                    //私有成员变量
                    var name = 'yjq';
                    var age = '23';
                    var sayHello = function(){
                        alert('hello');
                    }
                    
                    return {
                        name: name,
                        age: age,
                        sayHello: sayHello
                    }
                }
    
                 return {
                    getInstance :function(){
                        if(!uniqInstance){//如果不存在 创建单例对象
                             uniqInstance = init();
                        }
                        return uniqInstance;
                    }
                };
            })();
            Ext.Base.getInstance().sayHello();
            
            
            
            //4.分支单例(判断程序的分支)(常用)
               var def =true; 
                Ext.More =(function(){
                   var objA ={}; //ff
                var objB ={}; //ie
                return (def)?ojbA:ojbB;
               })();
            </script>
        </head>
        <body>
        </body>
    </html>
    js单例模式
  • 相关阅读:
    双链表( 初始化,建立,插入,查找,删除 )
    单链表(程序员宝典)
    单链表(建立、插入、删除、打印)
    Hive- 表
    Spark- 性能优化
    Spark- Checkpoint原理剖析
    Spark- 优化后的 shuffle 操作原理剖析
    Spark- Spark普通Shuffle操作的原理剖析
    Spark- Spark内核架构原理和Spark架构深度剖析
    Spark- Spark基本工作原理
  • 原文地址:https://www.cnblogs.com/yangjingqi/p/4309719.html
Copyright © 2011-2022 走看看