-
ES6新增
2020-09-24 20:19:02ES6新增 作用域 作用域是变量所作用的区域,也叫执行期上下文 块级作用域 let 声明的变量具有块级作用域,不存在变量提升,不能重复声明,声明之后绑定当前作用域 const 声明定义的是常量,具有let声明的特性; ...ES6新增
作用域
作用域是变量所作用的区域,也叫执行期上下文
块级作用域
let 声明的变量具有块级作用域,不存在变量提升,不能重复声明,声明之后绑定当前作用域
const 声明定义的是常量,具有let声明的特性;
conset声明指向的是内存中的地址,所以它定义的原始值不能改变,引用值可以改变变量的解构赋值
数组的解构赋值 实质是模式匹配
数组解构赋值
//解构成功,左右两边迭代器要相同即两边都是数组或者两边都是对象 let [a,b,c] = [1,2,3]; console.log(a,b,c); //解构失败的情况是没有对相应的值赋值个变量 let [d,e,f] = [1,2]; //let [d,e,f] = [1,2,undefined]; console.log(d,e,f); // 不完全解构,没有变量接收多余的值 let [g,h] = [1,2,3]; console.log(g,h); // 默认值,给变量设置默认值,当有赋值时将值赋给变量,当没有赋值时使用默认值 let [x = 10] = [20]; console.log(x); //let [i = 10, y, z = 5] = [20,10]; console.log(i, y, z); //---> 20 10 5
对象的解构赋值
对象的解构赋值是无序的
let {username, age} = {age : 18, username : 'parker'}; console.log(username,age);//'parker' 18 let {username:newName} = {age : 18, username : 'parker'}; console.log(newName);//'parker'
字符串的扩展
模板字符串
${常量/变量/表达式}
模板字符串可以嵌套模板字符串var str = `hello wor ${username} ${g} + ${h} = ${g + h} my name is: ${getName()} ld`; function getName() { return 'parker'; }
标签模板
实质是函数调用的特殊形式
// 一个重要应用---过滤HTML字符串 防止恶意脚本注入 var name1 = '<script>alter("aaa")<\/script>'; safeHTML `<p>${name1} welcome to park!!!</p>` function safeHTML(data) { var str = data[0]; for (let i = 1; i < arguments.length; i++) { var arg = String(arguments[i]) str += arg.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') str += data[i] } console.log(str); }
函数的扩展
// 函数参数的默认值 function Person (name, age = 18) { console.log(name, age); } Person('parkerWang') Person('parkerWang', 20) Person('parkerWang', null)
扩展运算符 REST参数
var arr = [...1,2,3,4,5]; // 1,2,3,4,5
箭头函数
var fu = num => num; var fun = function(num1, num2) { return num1, num2; } var fu1 = str => () => str.split('') function fn(str) { return function() { return str.split(''); }; }
数组的扩展
扩展运算符
var strArr = [... 'gouzi' ]; console.log(strArr); //Array.from(obj,callback) 把一个类数组转换成数组 function typesOf() { return Array.from(arguments, item => typeof item); } console.log(typesOf('1', false, NaN, null, [])); //Array.of() 将一组数转换为数组 var arr3 = Array.of(6); var arr4 = new Array(6); console.log(arr3, arr4);
数组实例方法
copyWithin
copyWithin(target,start,end)
// 复制数组中start~end的值,从target位覆盖到数组中,会改变原数组。 var arr4 = [1,2,3,4,5,6,7]; var arr5 = arr4.copyWithin(0, 3, 4); console.log(arr4, arr5);
fill()
//数组填充 var arr6 = new Array(6); arr6.fill(5); console.log(arr6);
entries() keys() values()
var arr7 = ['2',2,3,4,5]; var r = arr7.keys() var t = arr7.values() for([item, index]of arr7.entries()) { console.log(item, index); }
includes() find(callback) findIndex(callback)
// find()找到满足条件的第一个数 findIndex()找到满足条件的第一个数的下标 var num12 = arr7.find(item => item > 2); var num13 = arr7.findIndex(item => item > 2); console.log(num12); console.log(num13); var num14 = arr7.includes(3);//有就返回true无就返回false
对象的扩展
属性的可枚举性以及属性的遍历
Object.is(‘item1’,‘item2’) 返回bool值 判断两个值是否绝对等于,可以判断NaN
Object.assign() 将若干个对象的可枚举属性放到一个对象当中var obj1 = {}, obj2 = { name: 'parker' }, obj3 = { age: 18 }, obj4; obj4 = Object.assign(obj1, obj2, obj3); console.log(obj4, obj3, obj2, obj1); // 输出{name: "parker", age: 18} {age: 18} {name: "parker"} {name: "parker", age: 18}
Object.keys() Object.values() Object.entries()
var obj5 = { name: 'parker', age: 18, getMsg() { return this.name + this.age; } } var keys = Object.keys(obj5); var values = Object.values(obj5); var entries = Object.entries(obj5);
class类
class Person1 { // constructor 实例属性 constructor(name = 'parker', age = 18) { this.name = name this.age = age } // 方法 showMsg() { console.log(this.name) } print() { console.log(this.age) } } var newPerson = new Person1(); console.log(newPerson);
class的继承
extends 与 super
子类
__proto__
表示 构造函数的继承
子类__proto__.prototype
表示方法的继承class A { constructor() { this.name = 'xiaoming' } print() { console.log(this.name) } } class B extends A { constructor() { super() this.age = 'B' } } var b = new B('daming');
this指向
// 静态属性静态方法 class Aa { static fn() { console.log('aaaa') } } Aa.fn(); Aa.abc = 123; console.log(Aa.abc);
Promise的含义 基本用法
实例方法
Promise.prototype.then
Promise.all Promise.race
三种状态:
pending
就绪状态resolved
成功状态rejected
失败状态
pending => resolved
或pending => rejected
-
ES6新增方法
2020-08-12 23:48:08ES6新增方法 变量声明 let 1.局部变量,只能在局部调用 2.不能重复声明 3.不会提升变量 console.log(a); let a; const 1.声明一个常量 2.声明必须赋值 3.不能被修改 4.变量名建议大写,如: const PI = 3.14 变量...ES6新增方法
变量声明
let
1.局部变量,只能在局部调用
2.不能重复声明
3.不会提升变量 console.log(a); let a; const
1.声明一个常量
2.声明必须赋值
3.不能被修改
4.变量名建议大写,如: const PI = 3.14变量类型
数据类型
1.数字: number
2.字符串: String
3.布尔类型: true 和 false
4.未定义: undefined 引用类型
1.数组: array
2.对象: object
3.空: null
4.函数 : function
5.集合: Set
6.键值对: Map结构
数组
1默认 [a,b] = [100,900] 2交互变量 [a,b] = [b,a]
3.忽略 [a,b] = [1,3,5]
4.剩余值 [a,…rest] = [4,6,8,10]
5.默认值 [a,b=25] = [8]
6.复制(浅拷贝) var arr = [1,3,5] var arr2 = […arr]对象
顺序结构: var str = {name:‘苏苏未苏苏’,age:18,sex:‘男’} var {name,age}=str
剩余值: {name,…rest} = obj 默认值: {name = ‘哈喽’} = obj 复制: let obj2 =
{…obj}字符串
let [a,b,c,d] = “郑州奇酷” a 郑
数组高阶方法
filter 过滤 返回一个新数组 如果返回true,当前元素被保留, 否则被过滤
forEach 遍历 遍历数组
map 映射
返回和原数据一一对应的新数组 reduce 累计 a,b两个参数,a是上一次返回的结果
every 判断条件,若都满足条件返回true,否者返回false
some 判断条件,若其中之一满足 条件,返回true,否则返回false
重复使用repeat箭头函数
参数 => 函数体 =>前 函数的参数 =>后 函数的执行语句 var arr1 = [‘我’,‘爱’,‘J’,‘S’];
arr1.forEach(item=>console.log(item)); 如果有多个参数,用()包起来 var arr =
[1,2,3,4]; var ret = arr.reduce((a,b)=>a*2+b); console.log(ret);
函数体只有一句,执行的结果就是返回值 多条语句用{}包裹,return返回 如果return对象: return({})
箭头函数的this指向上一层作用域中的 this对象set
new Set([])去重
size 长度
add() 添加
delete() 删除
clear() 清空
for of 变量
has() 检测是否含有 特点,不重复 特点: 1.有序
2.key可以是任意值map
特点:
1.有序
2.key可以是任意值 new Map([k,v],[])
size 长度
set(k,v) 设置
get (k) 获取
has() 检测是否含有
clear() 清除
for of 遍历apply
执行函数,对象冒充,参数数组 function add(x,y){ console.log(this,x+y) }
add.apply({name:“mumu”},[3,7]) {name:“mumu”},10call
执行函数,对象冒充,参数1个 add.apply({name:“mumu”},3,7) {name:“mumu”,10}
bind
创建函数,对象冒充,参数默认值
var nadd = add.bind({name:“zql”},5)
nadd(10)
输出结果:{name:“zql”},15类
定义 class Cat{ constructor(){} }
初始化类 new Cat()
继承 class Cat extends Animal{}
方法 brak(){}
属性 this.name = “西”
访问控制 set Age(val){} get Age(){}
调用父类构造函数 super()
静态方法 static sayLog(){} Cat.sayLog()
静态属性 static num = 0; Cat.num、
、
(未完待续) -
ES6新增整理
2020-08-14 15:08:15ES6简介 什么是ES6? ES6泛指从2015年发布的ES2015,到ES2016、ES2017、ES2018等。 由于部分浏览器未完全支持ES6,所以在使用...ES6新增了字符串模板,在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,能ES6简介
什么是ES6?
ES6泛指从2015年发布的ES2015,到ES2016、ES2017、ES2018等。
由于部分浏览器未完全支持ES6,所以在使用ES6的项目在放到生产环境时需要使用Babel等工具编译以兼容。ES6常用新增
let、const
let 声明的变量拥有自己的块级作用域,且修复了var声明变量带来的变量提升和for循环var变量泄露,变量覆盖等问题。
const 新增了定义常量
str
ES6新增了字符串模板,在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,能保留所有空格和换行,使得字符串拼接看起来更加直观,更加优雅。
ES6在String原型上新增了
includes()
方法,用于取代传统的只能用indexOf查找包含字符的方法let str1 = '我是xxx,我喜欢唱、跳、rap、篮球。'; console.log(str1.includes('我')) //true
此外还新增了
startsWith()
,endsWith()
,padStart()
,padEnd()
,repeat()
等方法,可方便的用于查找,补全字符串。arr
数组解构赋值:
let [a,b,c] = [1,2,3]
,在声明较多变量时,不用再写很多let(var),且映射关系清晰,且支持赋默认值。let [a,b,c] = [1,2,3] console.log(a,b,c); //1 2 3
扩展运算符:
let a = [2,3,4]; let b = [...a]
let a = [{"a":"1"},{"b":"2"},{"c":"3"}]; let b = [...a] console.log(b); //[{"a":"1"},{"b":"2"},{"c":"3"}]
ES6在Array原型上新增了
find()
方法,用于取代传统的只能用indexOf查找包含数组项目的方法,且修复了indexOf
查找不到NaN
的bug([NaN].indexOf(NaN) === -1)
,let arr = [12,23,34,45,56,88,99]; function calc(num){ return num >= 45 } console.log(arr.find(calc)); // 45执行得到true返回结束,不会继续执行
from:
Array.from
方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable
)的对象(包括 ES6 新增的数据结构Set
和Map
)。const items = new Set([1,2,3,4,5,5,5,5,]); let arr = Array.from(items) console.log(arr); //[1, 2, 3, 4, 5] 可用于去重
filter:
filter
用于对数组进行过滤。
它创建一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let res = nums.filter((num) => { return num > 5; }); console.log(res); // [6, 7, 8, 9, 10]
此外还新增了
copyWithin()
,includes()
,fill()
,flat()
等方法,可方便的用于字符串的查找,补全,转换等。obj
1.声明方式:
let [apple, orange] = ['red appe', 'yellow orange']; let myFruits = {apple, orange}; // let myFruits = {apple: 'red appe', orange: 'yellow orange'}; let {keys, values, entries} = Object; let MyOwnMethods = {keys, values, entries}; // let MyOwnMethods = {keys: keys, values: values, entries: entries}
2.扩展运算符
(...)
:let {apple, orange, ...otherFruits} = {apple: 'red apple', orange: 'yellow orange', grape: 'purple grape', peach: 'sweet peach'}; // otherFruits {grape: 'purple grape', peach: 'sweet peach'} // 注意: 对象的扩展运算符用在解构赋值时,扩展运算符只能用在最有一个参数(otherFruits后面不能再跟其他参数) let allFruits = {apple, orange, ...otherFruits}; console.log(allFruits); //{apple: "red apple", orange: "yellow orange", grape: "purple grape", peach: "sweet peach"} let moreFruits = {watermelon: 'nice watermelon'}; console.log(moreFruits); //{watermelon: "nice watermelon"} let allFruits2 = {apple, orange, ...otherFruits, ...moreFruits}; console.log(allFruits2); //{apple: "red apple", orange: "yellow orange", grape: "purple grape", peach: "sweet peach", watermelon: "nice watermelon"}
3.
super
关键字:ES6在Class类里新增了类似this的关键字super
。同this总是指向当前函数所在的对象不同,super
关键字总是指向当前函数所在对象的原型对象。4.ES6在Object原型上新增了
assign()
方法,用于对象新增属性或者多个对象合并。const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; const returnedTarget = Object.assign(target, source1, source2); console.log(returnedTarget)// {a:1, b:2, c:3}
这个属性可用于对象的浅拷贝,只需要跟一个空对象合并,但只能拷贝对象的可枚举属性,所以不能算是深拷贝。
const obj = { a: 1 }; const copy = Object.assign({}, obj); console.log(copy); // { a: 1 }
5.ES6在Object原型上新增了
getOwnPropertyDescriptors()
方法,此方法增强了ES5中getOwnPropertyDescriptor()
方法,可以获取指定对象所有自身属性的描述对象。结合
defineProperties()
方法,可以完美复制对象,包括复制get
和set
属性。
6.ES6在Object原型上新增了getPrototypeOf()和setPrototypeOf()
方法,用来获取或设置当前对象的prototype
对象。这个方法存在的意义在于,ES5中获取设置
prototype
对像是通过__proto__
属性来实现的,然而
__proto__
属性并不是ES规范中的明文规定的属性,只是浏览器各大产商“私自”加上去的属性,只不过因为适用范围广而被默认使用了,再非浏览器环境中并不一定就可以使用,所以为了稳妥起见,获取或设置当前对象的
prototype
对象时,都应该采用ES6新增的标准用法。7.ES6在Object原型上还新增了
Object.keys()
,Object.values()
,Object.entries()
方法,用来获取对象的所有键、所有值和所有键值对数组。function
1.箭头函数:箭头函数是ES6核心的升级项之一,箭头函数里没有自己的this,这改变了以往JS函数中最让人难以理解的this运行机制。
箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象。ES5函数里的this总是指向函数执行时所在的对象,这使得在很多情况下this的指向变得很难理解,尤其是非严格模式情况下,this有时候会指向全局对象,这甚至也可以归结为语言层面的bug之一。
ES6的箭头函数优化了这一点,它的内部没有自己的this,这也就导致了this总是指向上一层的this,如果上一层还是箭头函数,则继续向上指,直到指向到有自己this的函数为止,并作为自己的this;
箭头函数不能用作构造函数,因为它没有自己的this,无法实例化;
也是因为箭头函数没有自己的this,所以箭头函数 内也不存在arguments对象。(可以用扩展运算符代替)
2.函数默认赋值:ES6之前,函数的形参是无法给默认值得,只能在函数内部通过变通方法实现。ES6以更简洁更明确的方式进行函数默认赋值。
function es6Fuc (x, y = 'default') { console.log(x, y); } es6Fuc(4) // 4, default
Symbol
Symbol是ES6引入的第七种数据类型。
所有Symbol()生成的值都是独一无二的,可以从根本上解决对象属性太多导致属性名冲突覆盖的问题。
var str1 = Symbol("a"); var str2 = Symbol("a"); console.log(str1 === str2); //false
Set
Set
是ES6新的数据结构,类似数组,但成员的值是唯一的,没有重复的值。let set= new Set() set.add(1) set.add(2) set.add(2) set.add(3) for(let item of set){ console.log(item) //1,2,3 } let set2 =new Set([1,2,3,3]) [...set2] //1,2,3
在
Set
中,两个NaN
时相等的,会去掉重复的NaN
Map
map()
方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。map()
方法按照原始数组元素顺序依次处理元素。const numbers = [4, 9, 16, 25]; function calcFun(num) { return num.map(Math.sqrt); } console.log(calcFun(numbers))
promise
Promise是ES6引入的一个新的对象,他的主要作用是用来解决JS异步机制里,回调机制产生的“回调地狱”。
new Promise((resolve, reject) =>{ // 一段耗时的异步操作 // resolve('成功') // 数据处理完成 reject('失败') // 数据处理出错 }).then( // .then()的第一个参数是成功(resolve)的回调 (res) => { console.log(res)// 成功 // console.log(res2)// 成功 }, // 第二个参数是失败(reject)的回调 (err) => { console.log(err)// 失败 // console.log(err2)// 失败 } ).catch((err)=>{ console.log(err); })
.then()
是promise的回调,接受两个参数,第一个参数是promise
的resolve
回调,第二个参数是reject
回调;如果不写,只会执行失败回调(reject);另外,它还有另外一个作用:在执行resolve
的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch
方法中。class
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
//定义类 class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } }
上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5的构造函数Point,对应ES6的Point类的构造方法。
构造函数的prototype属性,在ES6的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
class Point { constructor(){ // ... } toString(){ // ... } toValue(){ // ... } } // 等同于 Point.prototype = { toString(){}, toValue(){} };
Object.assign方法可以很方便地一次向类添加多个方法。
class Point { constructor(){ // ... } } Object.assign(Point.prototype, { toString(){}, toValue(){} });
类的内部所有定义的方法,都是不可枚举的
类的属性名,可以采用表达式。
let methodName = "getArea"; class Square{ constructor(length) { // ... } [methodName]() { // ... } }
module、export、import
module、export、import是ES6用来统一前端模块化方案的设计思路和实现方案。
export、import的出现统一了前端模块化的实现方案,整合规范了浏览器/服务端的模块化方法,
之后用来取代传统的AMD/CMD、requireJS、seaJS、commondJS等等一系列前端模块不同的实现方案,使前端模块化更加统一规范,JS也能更加能实现大型的应用程序开发。
import引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)。
import引入export导出的接口值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
先到这,日后更新
-
关于ES6新增的属性
2020-11-10 20:48:50关于ES6新增的属性 1、块级作用域 2、提供了定义类的语法糖 3、新增了一种基本数据类型(Symbol) 4、新增了变量的结构赋值 5、函数参数允许设置默认值,引入rest参数,新增箭头函数 6、数组新增一些API和一些方法 7... -
ES6新增的math,Number方法
2020-08-29 19:10:01ES6新增的math,Number方法,小编觉得非常不错,需要的朋友参考下吧 -
ES6新增语法
2020-04-18 20:46:22ES6新增语法 ES6版本的JavaScript语法,是一个非常重要的版本,对于JavaScript的功能上有一个极大的丰富,让JavaScript从弱类型语言,提升到了半强类型语言 ES6语法新增变量的定义 let 定义变量 特点:1,let定义的... -
ES6 新增语法
2020-02-23 16:57:09ES6 新增语法 块级作用域 ES6 通过{},使用let和const创建变量的块级作用域, ES6之前,JavaScript只有全局作用域和函数作用域。 ES6之前,使用立即调用函数表达式(immediately-invoked function expression,IIFE... -
es6新增及理解
2020-11-10 20:18:04es6新增及理解一、es6新增有哪些?1.块级作用域{}2.声明对象的方法(let,const)3.定义类语法糖Class4.解构赋值5.关于函数a.箭头函数:b.函数默认值:6.模块化(import/export)7.新的基本数据类型symbol8.set,map语法... -
ES6新增的数组知识实例小结
2020-10-15 07:27:45主要介绍了ES6新增的数组知识,结合实例形式分析了ES6的数组新增知识点、使用技巧与相关注意事项,需要的朋友可以参考下 -
06.ES6新增语法&API.doc
2021-02-24 21:04:2606.ES6新增语法&API.doc -
ES6新增语法笔记,方便学习
2020-03-25 23:02:08最新ES6语法整理笔记,内涵各个部分小示例,方便理解和使用,记录了整个ES6新增语法部分,以及与之前版本的比较! -
ES6新增语法简介
2020-04-07 23:02:46ES6新增语法什么是ES6新增关键字let新增关键字const解构赋值箭头函数剩余参数扩展运算符构造函数方法新增实例方法模板字符串数据结构Set 什么是ES6 全称ECMScript,它是由ECMA国际标准化组织制定的一项脚本语言的标准... -
ES6新增声明
2020-03-22 14:10:53ECMAScript 6(简称ES6)是于2015...ES6新增的功能: 1.let声明变量 let声明的变量不会挂在window中,不会造成全局变量的污染, 新增了一个块级作用域{},以前只有函数作用域,全局作用域。let是不允许重复声明它的... -
ES6新增特性
2019-08-02 20:03:12ES6新增特性常用的主要有:let/const,箭头函数,模板字符串,解构赋值,模块的导入(import)和导出(export,default/export),Promise,还有一些数组字符串的新方法。 ... -
ES6 新增特性
2020-10-29 11:51:42ES6新增的一些特性 1、let关键字,用来代替 var的关键字,特点: 1、变量不允许被重复定义 2、不会进行变量声明提升 3、保留块级作用域中i的 2、const定义常量,特点:1、常量值不允许被改变 2、不会进行变量声明... -
ES6新增相关
2019-08-31 17:46:57ES6新增的相关内容 新增的变量声明方式 let: 使用方式:同var 与var区别: ①let无变量提升 ②同一变量不能重复声明 ③let具有块级作用域:花括号{ } //暂时性死区:let之前不能对此对象做任何操作 const:使用... -
简述ES6新增关键字let与var的区别
2020-10-16 13:08:01最近看了很多文章,偶然间看到ES6中新增了一个关键字 let ,它具有与 var 关键字相似的功能。接下来通过本文给大家介绍ES6新增关键字let与var的区别,需要的朋友可以参考下 -
es6新增语法
2020-09-16 14:26:44es6新增语法 1.let 特点: 1.let关键字就是用来声明变量的 2.使用let关键字声明的变量具有块级作用域 if (true) { let a = 10; } console.log(a) // a is not defined 注意:使用let关键字声明的变量才...
-
MD5加密工具类
-
激光海表面反射率的机载实验分析
-
基于java的图形化的小说阅读器
-
css文本格式化标签
-
NFS 网络文件系统
-
i7 9700和i7 9700f有什么区别 i79700和i79700f玩游戏哪个好
-
激光喷丸处理对X70管线钢焊接接头低温冲击断口形貌的影响
-
练习2-18 求组合数 (15 分)
-
2021-02-25
-
性能测试基础--(CPU)
-
Windows系统管理
-
使用 Linux 平台充当 Router 路由器
-
DHCP 动态主机配置服务(在Linux环境下,配置单网段或跨网段提)
-
js: 生成4位数字的验证码
-
用于测量量块尺寸的激光干涉测量方法研究
-
spark大数据分析与实战
-
MySQL你该了解的那些事【服务端篇】
-
一个带下拉刷新列表的日历demo.zip
-
深究字符编码的奥秘,与乱码说再见
-
白话:java从入门到实战