ES6&&JavaScript语法笔记(191207更新)

ES6 and JavaScript:

##ES6语法的特性
Js中的then函数和nodejs中的回调能够保证函数的异步和跳过阻塞的部分进行下一步。

  1. 顺序次序不一致但对取值没有影响:

    var{bar,foo}={foo:"aaa",bar:"boo"};
    
  2. 循环的相关的写法:

    for a in obj //非常方便的进行对象的遍历
    for a of array//适合于进行一般的遍历
    arr.forEach(()=>{});//速度接近原始方式进行的速度
    //常用的MAP遍历结构
    for(let [key.value] of map)
    
  3. es7中async / await,为解决function, 事件发布和监听方式模糊了异步方法之间的流程

    可以完全取代promise, generator的应用,但注意async只能够在函数内部进行应用

    • 基本上任何一个函数都可以成为async,使用async则表明这个函数是一个异步函数
    async function foo(){}
    const foo = async funtion(){}
    const foo = async()=>{}//es6的写法
    
    • 在调用 async定义的函数时,使用await,可以简单的理解为函数挂起后等待promis进行返回。

      //async/await相关的代码
      const printData = async function (filepath) {
         let keyword = await readFile(filepath);
         let count = await queryDB(keyword);
         let data = await getData(res.length);
         console.log(data);
      });
      
  4. generator//es6

    function后面加*号函数则函数可以变为generator;执行generator将会返回一个遍历器对象,用于遍历generator内部的状态。

    //生成器的定义generator
    const gen function*()
    {
        yield 1;
        return 3;
    }
    //迭代器的定义iterator,迭代器是生成器的实例化
    let g =gen();
    g.next();
    
    //在异步任务处使用yield关键词,此时generator会将程序执行权交给其他代码,而在异步任务完成后,调用next方法来恢复yield下方代码的执行。
    

    yeild关键字后面需要是function, promise, generator, arrayobject。可以改写文章一开始的例子:

    const co = reuqire('co');
    
    const task = function* (filepath) {
       let keyword = yield readFile(filepath);
       let count = yield queryDB(keyword);
       let data = yield getData(res.length);
       console.log(data);
    });
    
    co(task, './sample.txt');
    
  5. Promise通过进行链接的方式进行改造:

    readFile('./sample.txt').then(content => {
        let keyword = content.substring(0, 5);
        return queryDB(keyword);
    }).then(res => {
        return getData(res.length);
    }).then(data => {
        console.log(data);
    }).catch(err => {
        console.warn(err);
    });
    //通过then连接的链式操作,使代码更加简洁
    

    Promise的相关方法函数:

  6. reduce的相关用法:

    //例子,previousValue初始值0,currentValue初始的值为index[currentValue],初始的值为0,index的初始值也为0,array一直不发生改变
    //previousValue2次以上为上一次执行的值
    [0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
      return previousValue + currentValue;
    }, 10);
    
  7. weakmap是map的弱引用对象,只是相比于map上面少了很多函数方法,set和weakset也是类似的关系。

    • //JS提供5种内置对象之一
      //map的常用方法
      clear()方法, 删除所有的键/值对;
      delete(key), 删除指定的键/值对;
      entries()返回一个迭代器, 迭代器按照对象的插入顺序返回[key, value]forEach(callback , context) 循环执行函数并把键/值对作为参数; context为执行函数的上下文thisget(key) 返回Map对象key相对应的value值;
      has(key) 返回布尔值, 其实就是返回Map对象是否有指定的key;
      keys() 返回一个迭代器,迭代器按照插入的顺序返回每一个key元素;
      set(key, value) 给Map对象设置key/value 键/值对, 返回这个Map对象(相对于Javascript的Set,Set对象添加元素的方法叫做add,而Map对象添加元素的方法为set[@@iterator] 和entrieds()方法一样, 返回一个迭代器, 迭代器按照对象的插入顺序返回[key, value]//weakmap的常用方法
      delete(key) : 删除指定的键/值对;
      get(key) :返回Map对象key相对应的value值;
      has(key) :返回布尔值, 其实就是返回Map对象是否有指定的key;
      set(key):给Map对象设置key/value 键/值对, 返回这个Map对象;
      
  8. JavaScript的继承(JavaScript语言特性决定了,类即函数,函数即类),ES6中出现class使得更加像一个类

    • JavaScript的语法中并没有多继承的存在

    • 实现多继承:通过class里面引用多个function

  9. Reflect的属性:(都是对于Object,JSON里面的方法进行修改)

    Reflect.deleteProperty(queRes[i],'count');//删除指定的json对象属性:
    
    Reflect.apply(target, thisArg, args)//
    Reflect.construct(target, args)//等同于new target(...args)
    Reflect.get(target, name, receiver)//查找并返回target对象的name属性
    Reflect.set(target, name, value, receiver)//设置target对象的name属性
    Reflect.defineProperty(target, name, desc)//等同于Object.defineProperty,用来为对象定义属性
    Reflect.has(target, name)//相当于name in target
    Reflect.ownKeys(target)//返回对象的所有属性,等同Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和
    Reflect.isExtensible(target)//表明当前对象是否可扩展
    Reflect.preventExtensions(target)//阻止该对象进行扩展
    Reflect.getOwnPropertyDescriptor(target, name)
    //等同于Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象,将来会替代掉后者
    Reflect.getPrototypeOf(target)
    //读取对象的__proto__属性,对应Object.getPrototypeOf(obj)
    Reflect.setPrototypeOf(target, prototype)
    //用于设置目标对象的原型(prototype),对应Object.setPrototypeOf(obj, newProto)方法
    
    
  10. JSON是用于TCP,http,websoket的常用数据交互格式,但传入的是JSON字符串

    常用的JSON对象和字符串转换方法:

    • JSON字符串转换为JSON对象

      let obj = eval('(' + str + ')');//1st
      let obj = str.parseJSON();//2nd
      let obj = JSON.parse(str)//3rd
      
    • JSON对象转换为JSON字符串

     let last=obj.toJSONString(); ;//1st
     let JSON.stringify(obj);//2nd
    
  11. 块级作用域:{}将函数进行分开,函数作用域,js中的函数作用域在函数外也是可见的,变量的提升,node在相同命名的情况下会优先执行函数;

  12. 特殊对象 arguments,无需指出参数名字就可以访问,类似的则是数组;Function在某些情况下也可以作为对象,一般使用语句var add = new Function(obj1,obj2)。

  13. 合并两个数组和数组扩展在原JS中用:arr.splice(start,num,value), 新的方法中 let arr=[origin1, insertvalue,origin];
    14.在nodejs中使用import语法:1.使用命令:node --experimental-modules test.mjs,2.在nodejs中package.json里面添加:type:json;https://nodejs.org/api/esm.html#esm_ecmascript_modules

JavaScript tips

##JavaScript组成部分:核心(ECMAScript),文档对象模型DOM,浏览器对象模型BOM

字面量/变量/常量和数据类型

  1. 变量 let /常量 const,ES6之前:var/无声明(全局变量),var和let最大的区别是let的迭代循环不会受闭包影响, js会将函数的变量名提升到普通变量名之前。

  2. 标识符号的命名:必须以字母, , 下 划 线 开 头 , 后 面 内 容 包 含 数 字 , 数 字 不 能 作 为 开 头 . ,下划线 _ 开头,后面内容包含数字,数字不能作为开头. ,线.在JQuery中则代表自身。

  3. 三种基本数据类型( Number,String,Boolean ),两种引用数据类型(Object,array),两种特殊数据类型(undefined,null);

  4. 转换数据类型:JavaScript能识别4种类型的数字字面量:十进制数、二进制数、八进制数和十六进制数

    parseInt("string",进制)//强制转化为整形,不填默认为10进制
    parseFloat("string",进制)//强制转化为浮点型不填,默认为10进制
    Boolean(value)//把给定的值转换成Boolean型;
    Number(value)//把给定的值转换成数字(可以是整数或浮点数);
    String(value)//把给定的值转换成字符串。
    
  5. 特殊字符:

        \n   换行
        \r    回车
        \t    制表符
        \'    单引号
        \"    双引号
        `     重音符(tab键上方的按键)
        \$    美元符
        \\     反斜线
        \uXXX    任意的Unicode码
        \xXX       Latin1字符
    其他常用字符
        \0    NUL字符
        \v    垂直制表符
        \b    退格
        \f     分页
    
  6. 模板字符串:${ } ,如果紧跟 $ 的值被包裹在大括号中,那么该值就会被注入到字符串中

    const message = `The curren temperatrue is ${currentTemp} \u00b0C`;
    

对象- js5种内置对象之一

本质上对象是一个容器,对象的容器可以随着时间推移而改变。

基本语法:let obj={key:value},key必须是字符串或者符号,值可以是任意类型

//for...in是枚举对象属性的传统方式
const SYM =Symbol();
const o={a:1,b:2,c:3,{SYM}:4};
for(let prop in o)
{
    if(!o.hasOwnProperty(prop))continue;
    console.log('${prop}:${o{prop}}');
}

数组处理(Array) - js5种内置对象之一

数组是一种特殊类型的对象。

数组的内容天生具有自然排序特性。键是数字,并且是有序的。它具有强大的传递信息的能力。

数组特性:

  • 数组长度不固定,可以随时添加和删除元素。

  • 数组中元素的类型是多样的,每个元素都可以是任意类型。

  • 数组从下标0开始。

//获取子数组
arr.slice(start);
arr,slice(start,end);
arr.slice(-end);
//从任意位置添加或删除元素
arr.splice(alterPos,count,elem)
//数组内的分割和替换
arr.copyWithin(targetPos,start,end)
//用指定值填充数组
arr.fill(1)//用相应数值填充过来
arr.fill(elem,start,end)
//数组反转和排序
arr.reverse()
arr.sort()
//map&&filter
arr.map(x=>x.name)//可以把json的map转换为数组
arr.filter(condition)
//reduce转化数组,可以将一个数组归纳为一个单独的值
const sum = arr.reduce({a,x}=>a += x,0)//a表示初始值arr[0],x表示第一个元素的值,然后循环运算
//字符串连接
arr.join(elem)

数组内容操作

push;pop//返回新数组的长度
unshift;shift
concat//在数组末尾添加多个元素
slice
splice
copyWithin//剪切并替换数组元素
fill//填充数组
reverse
sort

数组搜索

indexOf(简单的值),findIndex(复杂的值)//查找元素的下标
lastIndexOf(简单值)//查找最后一个元素的下标
find//元素本身
some//数组中符合条件的元素
every//数组中所有元素都符合给定条件

数组转化

map//转化数组中的所有元素
filter//根据给定条件排除数组元素
reduce//把整个数组转化成另一种数组类型
join//把元素转化成字符串合并

日期和时间(Date)- js5种内置对象之一

//moment.js为日期提供支持方法
const m = moment().add(10,'hours').subtract(3,"days").endof('month');
//日期格式化
moment().format('Y-M-D h:m:s')
fromNow()//从现在算起
m为未来10个小时以后的时间点倒退3天后所在月份的月底
//创建当前日期
const now = new Date();

//创建指定日期从0开始,9-10月
const halloweenParty = new Date(2016,9,31,19,0);

//创建指定日期和时间,19:00am = 7:00pm
const halloweenParty = new Date(2016,9,31,19,0)

//一些方法检索Date对象的组件
halloweenParty.getFullYear();
getMonth();getDate();getDay();getHours();getMinutes();getSeconds();getMillseconds();
//上述时间所对应的UTC时间
getUTCFullYear();getUTCMonth();getUTCDate();


正则表达式(RegExp)-js5种内置对象之一

//简单邮件识别器
const email = /\b[a-z0-9._-]+@[a-z_-]+(?:\.[a-z]+)+\b/;

//US手机号码识别器
const phone = /(:?\+1)?(:?\d3\s?|\d{3}[\s-]?)\d{3}[\s-]?\d{4}/;

//基本正则表达式
const re1 = /going/ //可以搜索going的表达式
const re2 =new RegExP('going')//使用对象构造器的等价形式
//一些常用的正则方法
startWith(),endWith(),includes(),indexOf()
match(),search(),input.replace().test()//从字符串开始
re.exec//从正则表达式开始

{n}//精确n次,匹配5位数字
{n,}//至少n次,匹配5位或者5位以上的数字
{n,m}//最少n次,最多m次 /\d{2,5}/
 ?//0或者1,等价于{0,1}/[a-z]\d?/i
*//0次或者多次,匹配跟随了0个或多个数字的字母 /a-z\d*/i 匹配跟随了0个或者多个数字的字母,表示重复
+//1次或者多次 /a-z\d+/i 匹配至少跟随一个数字的字母
\s\S能匹配所有的空格和非空格

函数替换

//保留class,id和href的属性,并删除其他内容
function sanitizeATag//获取标签
    const parts = aTag.match(/<a\s+(.*?)>(.*?)<\/a>/i);
//parts[1]是<a>标签中的属性,parts[2]是<a></a>之间的内容
const attributes = parts[1]
    .split(/\s+/);//接下来将其分割成独立的属性
return '<a'+attributes
    .filter(attr=>/^(?:class|id|href)[\s+]/i.test(attr)) //过滤掉class.id和href之外的属性
    .join('')//将它们用空格连接起来
    +'>'//关闭<a>标签
    +parts[2]//添加内容
    +'</a>'//添加闭合标签
replace函数的接受顺序//整个匹配的字符串(等价$&)>>匹配上的组,有多少组就会有多少参数,原始字符串中的匹配偏移量,原始字符串

描点

//只有两种描点:^和$,类似于标记物之类的
//一般字符串匹配的是整个字符串的开始和末尾,即使字符串中有换行;
//如果把某个字符串当作多行字符串(以换行符分隔来处理,就需要用到m选项)
const input = "One line\nTwo lines\nTree lines\nFour"
const beginners = input.match(/^\w+/mg);//{"One","Two","Three","Four"}
const endings = input.match(/\w+$/mg)

向前查找

//向前查找(?=<subexpression>)
//否定向前查找(?!<subexpression>)
//重要场景:密码验证

动态构造正则

const userRegex= new RegExp('@(?:${user.join('|')})\\b','g');//第一个反斜杆是用来转义第二个反斜杠
text.match(userRegex)

表达式和运算符

  • 算术表达式的优先级:PEMDAS(括指乘除加减)Parentless括号 Exponents指数 Multiplication乘法 Division除法 Addition加法 subtraction减法
  • typeof能够打印运算符,instanceof原型链测试,判断是否在其中,与in比较类似

作用域和严格模式

异步编程

  1. JavaScript对异步编程的支持有三个不同的阶段:回调阶段,promise阶段和生成器阶段

  2. 异步编程的4个主要使用场景:用户输入,网络请求(如Ajax请求),文件系统操作(读/写文件等)刻意的时间延迟(比如警告)

  3. setTimeout,setInterval和clearInterval都定义在全局对象中(在浏览器中是Window,在node中是global)

  4. 错误优先回调

    const fs = require('fs');
    const fname ='may_or_may_not_exist.txt'
    fs.readFile(fname,function(err,data){
        if(err)return console('error reading file ${fname}:${err.message}')
        console.log('${fname}contents:${data'}
    })
    
  5. Promise

    • Promise只会返回两种事情:被满足(success)和被拒绝(failure)里面分别使用resolve(满足)和reject的回调

    • resolve和reject可以被多次调用,但只有一次会起作用,且并没有终止函数执行,只是修改promise的状态

    • 事件:EvenEmitter

    • promise链:

      function launch(){
          return new Promise((resolve,reject)=>{
              console.log("on")
              setTimeout(function(){
                  resolve("In orbit");
              },2*1000)
          })
      }
      
      const c = new Countdown(5)
          .on('tick',i=>console.log(i+'...'));
      c.go()
       .then(launch)
          .then(msg=>{
          console.log(msg);
      })
          .catch(err=>{
          console.error("Houston, we have a problem....")
      })
      //开发人员不应该编写自己的生成器运行器,应该使用co或者koa
      

DOM和JQuery以及Node

  1. 文档对象的基本模型

    <html>
        <head>
            <title></title>
            <js></js>
            <style></style>
        </head>
        <body>
            <h1></h1>
            <div>
                <h1></h1> text node
                <p></p> text node
            </div>
        </body>
        </body>
    </html>
    
  2. 对话框 alert() prompt() confirm()显示带有一段消息以及确认按钮的对话

    页面加载事件 onload onunload

    定时器 setTimeout,clearTimeout 指定时间后执行,setInterval 指定时间后反复执行 clearInternal

  3. Dom操作:

    • 父节点:parentNode;

    • 兄弟节点:nextSibling, nextElementSibling, previousSibling, previousElementSbling;

    • 子节点firstChild, firstElementChild, lastChild, lastElementChild,

    • 所有子节点:ChildNotes 标准属性, children 非标准属性

      改变Html的输出流:document.write(),改变html的内容 document.getElementById("p1").innerHTML = "Hello 实验楼";
      
      改变HTML的属性:document90.getElementById(id).attribute = new value;
      
      Dom能够改变HTML元素的格式
      
      document.getElementById(id).style.property=new style; style为html相应元素的属性
      
      
      #创建节点:createElement("p")创建元素节点,createAttriute()创建属性节点,createTextNode()创建文本节点
      
      #插入子节点:appendChild()方法向节点添加最后一个子节点,insertBefore在指定子节点插入新的子节点,
      
      #删除节点:removeChild()
      
      #替换子节点:replaceChild()
      
      #设置节点的属性:getAttribute(名称)获取,setAttribute(名称,值)设置,removeAttribute(名称)删除
      
  4. 事件捕获与事件冒泡:三件事情来影响其他处理器的调用

    • 第一种最常见的,即已经见过的preventDefault,它可以取消地址;事件会继续传播,但是defaultPrevented会被置成true
    • 第二种是调用stopPropagation,时间传播到当前元素之后,将不会继续传播(所有绑定到当前元素上的处理器都会被调用,但绑定到其他元素上的处理器不会被调用)
    • 最后一件事,调用stopImmediatePropagation会阻止所有还未调用的处理器被调用(即使这些处理器被绑定在当前的元素上)
  5. 在JQuery的事件监听器中,直接在处理器中返回false与调用stopPropagation是等价的,这是Jquery的约定,但不能在DOM API中进行使用。

  6. 事件的种类

    • 拖拽事件(Drag events):实现了拖放事件的接口,比如drag start,drag, dragend,drop。

    • 焦点事件(Focus events):用户与可编辑的元素交互时执行的一些操作。当用户“进入一个字段”会触发focus事件,用户离开时会触发blur事件,当用户修改字段时则会触发change事件。onclick,onblclick

    • 表单事件(Form events):当用户提交一个表单(由submit或者对应的地方敲击回车),会触发表单上的submit事件。onsubmit,onreset

    • 输入设备事件(Input device events):常见的触摸事件有鼠标触摸事件(mousedown,move,mouseup,mouseenter,mouseleave,mouseover,mousewheel)和键盘事件(keydown,keypress,keyup)

    • 媒体事件(media events):用于追踪用户与html5中的视频,音频播放器的交互

    • 进度事件(Progress events):通知浏览器加载网页的速度,最常用的是load

    • 触摸事件(Touch events):触摸事件为可触摸设备提供了高级支持

    • 一系列实现的例子:

      <!DOCTYPE html>
      <html lang="en">
      
          <head>
              <meta charset="UTF-8">
              <title>Title</title>
              <style>
                  #list li {
                      list-style-type: none;
                      width: 100px;
                      height: 50px;
                      line-height: 50px;
                      background-color: beige;
                      text-align: center;
                      float: left;
                  }
      
                  #list li.current {
                      background-color: red;
                  }
      
                  #list li a {
                      text-decoration: none;
                  }
              </style>
      
          </head>
      
          <body>
              <div id="menu">
                  <ul id="list">
                      <li class="current">
                          <a href="javascript:void(0)">首页</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">HTML</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">CSS</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">JavaScript</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">关于</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">帮助</a>
                      </li>
                  </ul>
              </div>
      
              <script>
                  //获取所有的li标签,
                  var liObjs = document.getElementById("list").getElementsByTagName("li");
                  //循环遍历,找到每个li中的a,注册点击事件
                  for(var i = 0; i < liObjs.length; i++) {
                      //每个li中的a
                      var aObj = liObjs[i].firstElementChild;
      
                      aObj.onclick = function() {
                          //把这个a所在的li的所有的兄弟元素的类样式全部移除
                          for(var j = 0; j < liObjs.length; j++) {
                              liObjs[j].removeAttribute("class");
                          }
                          //当前点击的a的父级元素li(点击的这个a所在的父级元素li),设置背景颜色
                          this.parentNode.className = "current";
                      };
                  }
              </script>
      
          </body>
      
      </html>
      
  7. JQuery提供的text和html方法分别等于对DOM元素的textContent和innerHTML属性进行赋值

    //jQuery的基本实例
    //方法1
    $(document).ready(function(){
       // 开始写 jQuery 代码...
    });
    
    //方法2
    $(function(){
       // 开始写 jQuery 代码...
    });
    
    //一个简单的例子
    $('p')
        .after('<hr>')
        .append('<sup>*</sup>')
        .filter(':odd')
        .css('margin-left','20px')
    
  8. Ajax:在相应元素定义触发事件,能够在文件中定义触发的函数

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <script>
    function loadXMLDoc()
    {
        var xmlhttp;
        if (window.XMLHttpRequest)
        {
            //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
            xmlhttp=new XMLHttpRequest();
        }
        else
        {
            // IE6, IE5 浏览器执行代码
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
            }
        }
        xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);
        xmlhttp.send();
    }
    </script>
    </head>
    <body>
    <div id="myDiv"><h2>使用 AJAX 修改该文本内容</h2></div>
    <button type="button" onclick="loadXMLDoc()">修改内容</button>
    </body>
    
  9. Node相关的操作

    • exports有快捷语法和moudle.exports两种表达方式,实际情况下多用第二个方法

      //方法1,exports导出的这个对象名字仍然叫function
      exports.function=function((err,a)={
          return a;
      })
      //方法2,app.js module.exports对象导出时可用文件名作为对象app
      //index.get=function((err,a)={
          //return a;
      //})
      class index{
       
      }
      module.exports = index;
      
      
    • 核心模块,文件模块,npm模块,自定义函数模块

      核心模块//不需要用显示声明,可以进行直接使用
      文件模块//自己定义的模块,需要用require(./)进行使用
      npm模块//通过npm导入,需要用require进行定义
      自定义函数模块 //const debug = require('debug')('main') 直接将文件所包含的函数
      
    • 文件,进程,操作系统,流

      //文件系统
      fs.writeFile();fs.readFile();fs.writeFileSync();fs.readFileSync();
      //进程 process
      //子进程的模块对外主要是三个函数:exec,exeecFile和fork 并且有其自身的同步函数
      //流 const ws = fs.createWriteStream('streaming.txt',{encoding:'utf-8'});
      //操作系统os
      
    • web服务

      const http = require('http')
      
      const server = http.createServer((req,res)={
          console.log('${req.method} ${req.url}');
          res.end('hi')
      })
      const port = 8080
      server.listen(port,()={
          console.log('server started on port ${port}')
      })
      

[1].(美)鲍尔斯. JavaScript学习指南(第三版)[M].北京:人民邮电出版社

[2]. 《JavaScript基础》实验楼课程 https://www.shiyanlou.com/courses/1238

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值