【总结】javascript复习2

JavaScript复习2

  • JS-正则表达式
  • JSOOP-高级特征
  • JSOOP-定义类和属性(封装)
  • JSOOP-继承
  • JSOOP-多态
  • 手写Jquery

正则表达式

正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符")。
正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
正则表达式是繁琐的,但它是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。只要认真阅读本教程,加上应用的时候进行一定的参考,掌握正则表达式不是问题。
许多程序设计语言都支持利用正则表达式进行字符串操作。

语法

语法一var zz1=/abc/;
语法二var zz2=new RegExp('abc');

test验证

test(验证的字符串) 返回值 true false

	var zz1=/abc/;
    var zz2=new RegExp('abc');
    console.log(zz1.test('abc'));   //true
    console.log(zz1.test('123abc1234'));   //true
    console.log(zz1.test('123ab123'));   //false
边界符号

^开头 $结尾

	var reg=/^abc/;//以abc开头
    console.log(reg.test('asdabc'));
    var reg2=/abc$/;//以abc结尾
    var reg3=/^abc$/;//以abc开头和结尾
    console.log(reg2.test('abc'));//true
    console.log(reg2.test('123abcsd'));//false
    console.log(reg2.test('abc456'));//false
    console.log(reg2.test('123abc'));//true
集合

[abc]多个里选择一个

	var reg=/[abc]/; //包含abc其中一个
    console.log(reg.test("temo"));//false
    console.log(reg.test("aoduola"));//true
    console.log(reg.test("baowan"));//true

[a-h]abcdefgh

	var reg=/[a-h]$/;   //a~h范围内的结尾
    console.log(reg.test("temo"));//false
    console.log(reg.test("aoduola"));//true
    console.log(reg.test("baowan"));//false

[可以写汉字的范围]

	var hz=/^[\u4e00-\u9fa5]{2,8}$/;//2~8个汉字
   console.log(hz.test('积分'));    //true
   console.log(hz.test('积分分子'));//true
   console.log(hz.test('超级厉害无敌帅气'));//true
   console.log(hz.test('积分123'));//false

[^abc]排除

console.log("------------------------排除");
   var reg=/^[^a-zA-Z0-9_-]$/;//排除这些范围
   console.log(reg.test("a"));  //false
   console.log(reg.test("&"));  //true
量词

*表示0次或多次

 	console.log("----------------------量词");
    var reg=/^a*$/;//*表示0次或多次
    console.log(reg.test('a'));//true
    console.log(reg.test(''));//true

+表示一次或多次

var reg1=/^a+$/;//+表示一次或多次
    console.log(reg1.test('a'));//true
    console.log(reg1.test(''));//false

?表示零次或一次

 var reg3=/^a?$/;//?表示零次或一次
    console.log(reg3.test('a'));//true
    console.log(reg3.test(''));//true
    console.log(reg3.test('aaa'));//false

{n}匹配n次 {n,}至少n次 {n,m}至少n次至多m次

	var reg4=/^bo{2}m$/;//b开头o为两次m结尾
    console.log(reg4.test('bom')); //false
    console.log(reg4.test('boom')); //true
    console.log(reg4.test('booooom'));//false
元字符
常用的元字符
\d代表数字
\D代表非数字
\w匹配字母数字下划线等价于[A-Z0-9a-z]
\W匹配非字母数字下划线等价于[^A-Z0-9a-z]
\t \r \n \f ==\s 任何空白字符,包括空格、换行、换页、回车、制表符
.除\r\n外任何字符
()括起来的代表一个整体
修饰符
修饰符描述
i将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。
g查找所有的匹配项。
m使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾
s默认情况下的圆点 . 是 匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。
正则替换

//replace既支持字符串,也支持正则表达式

 //正则替换
   var t="今天真鸡儿冷...WC";
   var reg=/鸡儿|WC/g;
   var ok=t.replace(reg,"TMD");//replace既支持字符串,也支持正则表达式
   console.log(ok)
正则匹配

match(正则表达式)匹配出对应的字符串以数组的形式打印

//正则匹配
   var st="中国移动10086 中国电信10000 中国联通10010";
   var mval=st.match(/\d{5}/g);
   console.log(mval);

//获取年月日 ()分组

//获取年月日    ()分组
   var d='2005-10-13';
   var data=d.match(/(\d{4})-(\d{2})-(\d{2})/);
   console.log(data);
   console.log(RegExp.$1);//年
   console.log(RegExp.$2);//月
   console.log(RegExp.$3);//日

JSOOP-高级特征

对象本质可以理解为属性的集合,对象的属性包括数据属性访问器属性

数据属性

数据属性:它包含的是一个数据值的位置,可以对数据值进行读写

四大特征
  1. value值
  2. writable表示是否可写,默认true,如果为false,则表示当前属性只读不可修改
  3. enumerable表示是否可枚举,默认true如果为false,则在for…in中不会被遍历
  4. configurable表示是否为可配置的,默认true,如果为false,则不能删除,而且不能再改回true

obj有两个方法
定义属性状态defineProperty(obj,属性名,{})
获取属性描述对象getOwnPropertyDescriptor(obj,属性名)

获取属性描述对象

语法:Object.getOwnPropertyDescriptor(obj,'属性名');
例如:var p1=Object.getOwnPropertyDescriptor(o1,'name');
这样就得到了name的属性对象

定义属性状态

语法:Object,defineProperty(obj,属性名,{})
例如:

	Object.defineProperty(o1,'name',{
            "writable":false,//name属性不可修改
            "enumerable":false//name属性不可枚举
        })

这样就将name属性设置成不可修改且不可枚举了.

writable实例
	var o1={};
        o1.name="csdn";
        o1.age=18;
        o1.study=function(){
            alert("好好学习 天天向上");
        }
         Object.defineProperty(o1,'name',{
            "writable":false,//name属性不可修改
        })
        //修改属性---修改无效
       o1.name='碰磕'; //在严格模式下报错
enumerable实例
 		Object.defineProperty(o1,'name',{
            "enumerable":false//name属性不可枚举
        })
        for(var at in o1){
            // at为属性名
            console.log(o1[at]);//得到所有属性的值但得不到name的
            //由于name被禁止枚举
        }
configurable实例

当设置为不可配置时之后就不可以改回true了

 	//属性不能删除
        Object.defineProperty(o1,'age',{
            "configurable":false//修改成不可配置
        })
        delete o1.age;//删除无效
        console.log(o1);
         //不可逆的!!!
        Object.defineProperty(o1,'age',{
            "configurable":true//修改成可配置
        })
访问器属性

访问器属性是专门保护数据属性的特殊属性,不实际存储数据
分为gettersetter访问器
get方法负责读取变量值
set方法负责修改变量值

四大特征
  1. [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性、或者能否把属性修改为数据属性。默认值是true。
  2. [[Enumerable]]:表示能否通过for-in循环返回属性。默认值是true。
  3. [[Get]]:在读取属性时调用的函数。默认值是undefined。
  4. [[Set]]:在写入属性时调用的函数。默认值是undefined。
实例
 /*
         *访问器属性
        */
        var stu={
            id:1,
            name:'碰磕',
            salary:8000
        };
        Object.defineProperty(stu,'bank',{
            get:function(){
                console.log("get方法获取");
                return this.salary;
            },
            set:function(val){
                console.log("给stu赋值");
                this.salary+=val;   
            }
        })
        //测试
        stu.bank=1000;//自动调用set方法
        console.log(stu.bank);//自动调用get方法
严格模式
  1. 不可使用with
  2. 变量必须声明
  3. this默认是undefined而不是window
  4. 为只读变量和不可扩展对象赋值会报错
  5. 函数的形参不可以同名
  6. 不可以使用caller和arguments的属性,会报错

语法:'use strict';
代码示例:

'use strict';
var o1={};
        o1.name="csdn";
        o1.age=18;
        o1.study=function(){
            alert("好好学习 天天向上");
        }
        //with
        with(o1){   //严格模式下不可使用会报错
            console.log(name);
            console.log(age);
        }
        //形参不同名,this是值谁
         //方法this是谁???window undefined
        function test(a,a){//严格模式下形参不可同名
            console.log(this);//严格模式下是undefined
            console.log(a+a);
        }
        test(1,2);//报错
         // arguments的使用
        //没写参数
        //arguments.callee==函数本身
        function mylist(){
         console.log(arguments.callee);//等于函数本身,严格模式下不可使用(报错)
            
            let n=arguments.length;//得到参数的个数
            for(var i=0;i<n;i++){
            console.log(arguments[i]);
            }
            
        }
        mylist('参数一号','参数二号','参数三号')
        //caller的使用指向函数的调用者
        function china(){
            hunan()
        }
        function hunan(){
            console.log("我代表湖南");
            console.log("调用者:"+hunan.caller);
        }
        china()  // 严格模式下报错caller
总结
  • 通过修改属性的四大特征来保护属性
  • 数据属性可以控制对象属性的只读,遍历或删除特征
  • 访问器属性可以通过自定义逻辑来设置和获取变量的值

JSOOP-定义类和属性(封装)

类似于java中的
private私有属性 public公有属性 protected受保护的属性
static静态属性

定义类var Animal=function(name,type){}
私有属性方法
 var Animal=function(name,type){
        //private私有属性
        var _type=type;
        //private私有方法
        var isAnimal=function(){
            console.log("私有方法"+_type);
        }
        isAnimal();
    }
受保护属性方法

在类中添加

 //protected受保护的属性
        var _age=0;
        //访问器
        Object.defineProperty(this,"age",{
            get: function(){
                console.log("查看年龄...");
                return this._age;
            },
            set: function(val){
                //保护
                if(val>100){
                    this._age=20;
                }else{
                    this._age=val;
                }
            }
        });
公有属性方法

在类中添加

//公有属性和方法
        this.type=type;
        this.sayhello=function(){
            console.log("Hello JSOOP");
        }
静态属性方法
 //静态属性static
    Animal.number=90;
    Animal.count=function(){
        console.log("静态方法动物总数"+Animal.number);
    }
    console.log(Animal.number);
    Animal.count();
    //对象不能用静态属性

直接通过类名.属性或者方法名调用
对象不能用静态属性

添加原型的两种方式

方式一1、Animal.prototype.属性名="值"; 2、Animal.prototype.方法名=function(){}
方式二:Animal.prototype={属性名:值,方法名:函数}

JSOOP-继承

继承父类的方法属性,在java中用到关键词extends

方案一:拷贝继承

通俗易懂(效率低)

给object编写一个copy方法
相对于将把b对象的所有值复制给a对象 b—>a

	Object.copy=function(a,b){
        for(var attr in b){
            a[attr]=b[attr]; //a.name=a[name]
        }
        return a;
   }

再编写一个继承方法

 //继承方法
   Object.prototype.extends=function(o){
        return Object.copy(this,o);    //当前对象继承o
   }
示例1
var temo={
       name:"temo",
       age:18,
       fun:function(){
           console.log("方法");
       }
   };
   var dema={};
    dema.extends(temo);//继承
   console.log(temo);
   console.log(dema);
   dema.fun()

继承成功并且可调用fun方法

示例2
 //形状类(继承示例2)
    var Shape=function(){
        this.draw=function(){
            //调用下方空方法
            this._draw();
        }
        //空方法
        this._draw=function(){}
   }
   //矩形
   var Rect=function(){};
//    var xz=new Shape();//父类对象
   Rect.prototype=(new Shape()).extends({
       width:100,
       height:200,
       _draw:function(){
           console.log("画个矩形");
       }
   });
   var rec=new Rect();
   rec._draw();//打印出两个矩形

继承并且添加两个属性以及重写_draw方法…ok

方案二:原型链继承

简便快捷(不支持多重继承)

//定义一个动物类
    function Animal(name){
        //属性
        this.name=name||'Animal';
        //实例方法
        this.sleep=function(){
            console.log(this.name+"正在睡觉!");
        }
    }
    //原型方法
    Animal.prototype.eat=function(food){
        console.log(this.name+'正在吃:'+food);
    };
    //--------------上面是父类------------------
    // 原型链继承
    function Cat(){}
    Cat.prototype=new Animal('加菲猫');
示例
	cat.eat("🐟")
    cat.sleep()
    console.log(cat instanceof Animal);//true
    console.log(cat instanceof Cat);//true
方案三:构造继承

调用父类的构造方法(支持多重继承)
只能执行实例函数,原型函数执行不了

	function Ufo(){
        this.lay=function(){
            console.log("反重力飞行");
        }
    }
	function Cat(name){
        Animal.call(this);//调用父类的构造方法
        Ufo.call(this);//多重继承
        this.name=name||'小白';
    }
    var cat=new Cat('波斯猫')
    cat.sleep()
    cat.lay()
    console.log(cat instanceof Animal);//false
    console.log(cat instanceof Ufo);//false
    console.log(cat instanceof Cat);//true
方案四:实例继承

类中new父类返回父类

function Cat(name){
        var obj=new Animal();
        obj.name=name||"阿里巴巴";
        return obj;
    }
    var cat=new Cat();
    cat.eat("🐟");
    cat.sleep();
    console.log(cat instanceof Animal);//true
    console.log(cat instanceof Cat);//false
方案五:组合继承(原型链+构造函数方式)

解决了构造函数中不可调用原型函数的缺点
并且可以多重继承
缺点:调用了两次构造方法

	function Cat(name){
        Animal.call(this);
        this.name=name||'组合';
    }
    Cat.prototype=new Animal();
    var cat=new Cat("小白");
    cat.sleep();
    cat.eat("饭");
    console.log(cat instanceof Animal);//true
    console.log(cat instanceof Cat);//true
方案六:寄生继承(力荐)

包含了组合继承的所有优点且解决了它的缺点

function Cat(name){
        Animal.call(this);
        this.name=name||'终极组合';
    }
    (function(){
        var Super=function(){};
        Super.prototype=Animal.prototype;
        Cat.prototype=new Super();
    })();
  
    var cat=new Cat("小红");
    cat.sleep();
    cat.eat("喝粥");
    console.log(cat instanceof Animal);//true
    console.log(cat instanceof Cat);//true
    //--------------上面是寄生继承(原型链+构造函数方式[超推荐解决了组合继承的缺点])------------------

JSOOP-多态

同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。 简单的说:就是用基类的引用指向子类的对象。

	var Rect=function(){
        this.draw=function(){
            console.log("画个矩形");
        }
    }
    var Circle=function(){
        this.draw=function(){
            console.log("画个圆形");
        }
    }
    //模拟多态
    function test(obj){
        obj.draw();
    }
    test(new Circle())

手写Jquery

Jquery写法$("")
$是什么?? 函数
$() 返回值? 对象

手写jq实现 $(“h1”).css(“color”,“red”);

对象与数组合并Array.prototype.push.apply(stu,arr1);//(对象,数组)

(function(){
        //主方法返回对象
        var Jquery=function(selector){
            return new Jquery.prototype.Init(selector);
        }
        //给原型加载Init
        Jquery.prototype={
            Init:function(selector){
                console.log("选择器"+selector);
                //找到多个dom 例如class、标签查找
                var sz=document.querySelectorAll(selector);
                Array.prototype.push.apply(this,sz);//将得到的dom节点放入this中
                return this;//Init
            },
            css:function(attr,val){
                console.log("属性"+attr);
                console.log("值"+val);
                for(var i=0;i<this.length;i++){ //this.length==Init.length
                    if(val==undefined){
                    return this[i].style[attr];
                    }else{
                        this[i].style[attr]=val;
                    }
                }
                //实现链式
                return this;
            }
        }
        //将Jquery的原型赋值给init;
        Jquery.prototype.Init.prototype=Jquery.prototype;
        //挂载到window对象上
        window.$=Jquery;
    })();
    $(".lang").css("color","pink").css("fontSize","50px")//xxx.style[color]="red"--->js

Init:得到dom点的方法
将Jquery挂载到window对象上,这样在外边就能调用
将Jquery的原型赋值给init这样Jquery的css方法Init也能调用
css:传一个属性得到该属性值,传两个则修改,支持链式

取出选择器找到的第n个元素eq

		eq:function(n){
              this[0]=this[n];
              this.length=1;
              return this;
         },

html未传值则得到html文本信息,传值则修改html文本信息

html:function(val){
                for(var i=0;i<this.length;i++){
                    if(val==undefined){
                        return this[i].innerHTML;
                    }else{
                        this[i].innerHTML=val;
                    }
                }
                return this;
            }

attr实现得到属性值,改变属性值[可链式操作]
并且可以传入对象进行赋值

//实现jquery中的attr方法,要求可以做链式操作。
            attr:function(attr,val){
                // console.log(typeof attr);
                if(typeof attr =="object"){
                    for(let j in attr){
                        // console.log("j="+j+"attr="+attr[j]);
                        for(var i=0;i<this.length;i++){
                            this[i].setAttribute(j,attr[j]);
                        }
                    }
                }else{  //参数是string型
                for(var i=0;i<this.length;i++){
                    if(val==undefined){
                        return this[0].getAttribute(attr);
                    }else{
                        this[i].setAttribute(attr,val);
                    }
                }
                }
                return this;
                
            }

each遍历

	each:function(fn){   //参数是个函数
                for(var i=0;i<this.length;i++){
                    fn(i,this[i]);//调用函数
                }
       }

//each遍历
    $("p").each(function(index,item){
        console.log(index + "----" + item.innerHTML);
    });

给自己写的jq添加继承功能使得别人可以add功能
trim去除字符串空格

//可拓展方法
        Jquery.extends=function(obj){
            for(var attr in obj){
                this[attr]=obj[attr];
            }
            return this;
        }
        //给自己写的jq加功能
    $.extends({
       //去除两端空格
       trim:function(str){
            return str.replace(/^\s+|\s+$/g,'');//(正则,替换字符)
       } 
    });
    //示例
    var t='  hello   world  ';
    console.log(t+"---"+t.length);
    var ok=$.trim(t);
    console.log(ok+"---"+ok.length);//去除空格后长度

测试成功,ojbk------------>>>

练习

正则表达式练习

//手机号
//账号是否合法(字母开头,允许5~16字节,允许字母数字下划线)
//密码(长度在6~18之间,只能包含字母、数字、下划线)
//qq号

//练习
//手机号
var tel=/^[13|15|18|14][0-9][0-9]{4}[0-9]{4}/;
console.log(tel.test('15770623252'));
//账号是否合法(字母开头,允许5~16字节,允许字母数字下划线)
var user=/^[a-z|A-Z][a-z|A-Z|0-9|_]{4,15}/;
console.log(user.test('A_13'));
//密码(长度在6~18之间,只能包含字母、数字、下划线)
var pwd=/^[a-z|A-Z|0-9|_]{6,18}/;
console.log(pwd.test('Aaa_13'));
//qq号
var qq=/^[1-9][0-9]{4,}/;
console.log(qq.test('3038324746'));
匹配图片路径
var html = `
    <li class="list-item"><div class="equipment-item"><div class="prop-box"><img src="https://game.gtimg.cn/images/lol/act/img/item/1033.png" alt="抗魔斗篷"></div> <p class="prop-name">抗魔斗篷</p> <div class="price"><i class="icon-gold"></i> <span>450</span></div></div></li>
    <li class="list-item"><div class="equipment-item"><div class="prop-box"><img src="https://game.gtimg.cn/images/lol/act/img/item/1037.png" alt="十字镐"></div> <p class="prop-name">十字镐</p> <div class="price"><i class="icon-gold"></i> <span>875</span></div></div></li>
    `
    var pic=/https:\/\/.*\.png|jpg$/g;
    var src=html.match(pic);
    console.log(src);
高级特性练习
  • 创建一个猫对象,通过defineProperty给它定义name数据属性,值为大黄,不可修改,可枚举可配置,
    color数据属性,值为黄色,可修改可枚举可配置,weight访问器属性,可枚举可配置。
  • 创建一个学生stu对象,通过defineProperty定义一个score访问器属性,
    当运行stu.score = 5;时打印出’成绩进步了5分’,当运行var s = stu.score;时打印出‘成绩是95分’
  • 创建一个car对象,通过defineProperty定义一个price访问器属性,
    当运行car.price = 9;时打印出’售车打9折’,当运行var p = car.price;时打印出‘价格是999999元’

第一题猫对象

//1
       var cat={
           "name":"大黄",
           "color":"黄色",
           "tz":10
       };
       Object.defineProperty(cat,'name',{
            "writable":false,//name属性不可修改
       })
       Object.defineProperty(cat,'weight',{
           get:function(){
                return this.tz;
           },
           set:function(val){
                return this.tz+=val;
           }
       })
       cat.weight=20;
       console.log(cat.weight);

第二题stu对象

//2
       var stus={};
       let grads=90;
       Object.defineProperty(stus,'score',{
           get:function(){
               console.log("成绩是"+grads+"分");
                return grads;
           },
           set:function(val){
            console.log("成绩进步了"+val+"分");
            return grads+=val;
           }
       })
       stus.score=6;
       stus.score;

第三题car对象

//3
       var car={};
       let qian=1111110;
       Object.defineProperty(car,'price',{
            get:function(){
                console.log("价格是"+qian+"元");
                return qian;
            },
            set:function(val){
                console.log("售车打"+val+"折");
                return qian=qian*(val/10);
            }
       })
       car.price = 9;
       car.price;
继承、封装、多态练习

创建一个Person类,包含name公开的属性,age受保护的属性,这个值只能是数字,私有的属性account。

var Person=function(name){   
    this.name=name;//公开的属性
    var account="私房钱";//私有属性
    var _age=0;//受保护的
    var num=/\d/;
    Object.defineProperty(this,"age",{
        get:function(){
            return _age;
        },
        set:function(val){
            if(num.test(val)){
                _age=val;
            }else{
                console.log("age只能是数字");
            }
        }
    })
   }

创建一个showMoney私有的方法,在这个方法中打印出account的值。

var showMoney=function(){   //私有方法showMoney
        console.log("account的值:"+account);
    }

创建一个showMsg公开的方法,在这个方法中打印出name和age,并且调用showMoney方法。

this.showMsg=function(){    //公有方法showMsg()
        console.log("name:"+this.name+";age:"+this.age);
        showMoney();//调用
    }

创建一个交通类Trafic和它的两个子类Car和Bike,通过多态实现每种交通工具的run方法。

Object.copy=function(a,b){
       for(var attr in b){
           a[attr]=b[attr];
       }
       return a;
   }
   Object.prototype.extends=function(o){
       return Object.copy(this,o)
   }
   var ren1=new Person("肖");
   ren1.age="2";
   ren1.showMsg();
   //继承
   var Trafic=function(){
        this._run=function(){
            //调用下方空方法
            this.run();
        }
        //空方法
        this.run=function(){}
   }
   var Car=function(){}
   var Bike=function(){}
   Car.prototype=(new Trafic()).extends({
       run :function(){
        console.log("汽车动起来.....");
       }
   });
   Bike.prototype=(new Trafic()).extends({
       run :function(){
        console.log("自行车GoGoGo.....");
       }
   });
   var car1=new Car();
   var bike1=new Bike();
   car1.run()
   bike1.run()
   //多态
   var Trafic1=function(obj){
            obj.runn();
        }
        var Car1=function(){};
        Car1.prototype.runn=function(){
            console.log("开车回家!");
        }
        Trafic1(new Car1());

        var Bike1=function(){};
        Bike1.prototype.runn=function(){
            console.log("骑自行车回家!");
        }
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

碰磕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值