接着上篇继续写。
不定参数
转载请注明来源: http://blog.csdn.net/caoshiying非法转载或抄袭将委托CSDN追究法律责任。
不定参数是在函数中使用命名参数同时接收不定数量的未命名参数。这只是一种语法糖,在以前的JavaScript代码中我们可以通过arguments变量来达到这一目的。不定参数的格式是三个句点后跟代表所有不定参数的变量名。比如下面这个例子中,…x代表了所有传入add函数的参数。
function add(...x){
return x.reduce((m,n)=>m+n);
}
console.log(add(1,2,3));
console.log(add(1,3,4,5));
拓展参数
拓展参数则是另一种形式的语法糖,它允许传递数组或者类数组直接做为函数的参数而不用通过apply。
var peoples=['Wayou','John','Sherlock'];
function printPeoples(people1,people2,people3){
console.log(`Hello ${people1},${people2},${people3}`);
}
printPeoples (...people);
printPeoples.apply(null,peoples);
let与const 关键字
可以把let看成var,只是它定义的变量被限定在了特定范围内才能使用,而离开这个范围则无效。const则很直观,用来定义常量,即无法被更改值的变量。
for (let i=0;i<2;i++){
console.log(i);
}
console.log(i);//输出:undefined,严格模式下会报错
for of 值遍历
我们都知道for in 循环用于遍历数组,类数组或对象,ES6中新引入的for of循环功能相似,不同的是每次循环它提供的不是序号而是值。示例工程:E10。
var arrays=['李婷',22,"羽毛球"];
for(let v of arrays){
printVariables(v);
}
for(let v in arrays){
printVariables(arrays[v]);
}
function printVariables(v) {
document.write(v);
document.write("<br/>");
}
生成器函数(Generator Function)
生成器函数与普通函数的语法区别很小,只是函数名称前面增加一个星号*。生成器函数不立即执行函数体,而是返回一个迭代器(iterator),等待用户调用迭代器的next方法。在迭代器函数内部可以应用yield等关键字。
生成器函数的行为与普通函数并不相同,表现为如下3点:
1. 通过new运算符或函数调用的形式调用生成器函数,均会返回一个生成器实例;
2. 通过new运算符或函数调用的形式调用生成器函数,均不会马上执行函数体的代码;
3. 必须调用生成器实例的next方法才会执行生成器函数体的代码。
这个特性单独应用的意义不大。
iterator是一个特殊对象,拥有一个next方法,这个方法返回一个对象{done,value},这个对象包含两个属性,一个布尔类型的done和包含任意值的value。iterable是一个特殊对象,拥有一个obj[@@iterator]方法,这个方法返回一个iterator。
generator是一种特殊的iterator。反的next方法可以接收一个参数并且返回值取决与它的构造函数(generator function)。generator同时拥有一个throw方法。生成器函数函数即generator的构造函数。此函数内可以使用yield关键字。在yield出现的地方可以通过generator的next或throw方法向外界传递值。
yield 关键字:它可以暂停函数的执行,随后可以再次进入函数继续执行。
示例工程:E11。
function writeMessage(msg) {
document.write(msg);
document.write("<br/>");
}
function *enumerable(msg) {
writeMessage(msg);
var msg1 = yield msg + " after ";
writeMessage(msg1);
var msg2 = yield msg1 + " after ";
writeMessage(msg2);
try {
var msg3 = yield msg2 + " after ";
writeMessage("OK");
} catch (e) {
writeMessage(e);
}
writeMessage(msg2 + " over ");
}
(function () {
var iterator=enumerable("hello");
var ret=iterator.next();
ret=iterator.next("world");
ret=iterator.next("game");
ret=iterator.throw(new Error("test"));
iterator=enumerable("hello");
for(ret of iterator){
writeMessage(JSON.stringify(ret));
}
})();
模块
在ES6标准中,JavaScript原生支持module了。这种将JS代码分割成不同功能的小块进行模块化的概念是在一些三方规范中流行起来的,比如CommonJS和AMD模式。
将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用。示例工程:E12。
module people from "/people.js";
import People from "people";
class Student extends People{
constructor(name,age,hobby){
super(name,age);
this.hobby=hobby;
}
printSelf(){
document.write(this.name);
document.write("<br/>");
document.write(this.age);
document.write("<br/>");
document.write(this.hobby);
document.write("<br/>");
}
}
(function () {
var student=new Student("李婷","羽毛球");
student.printSelf();
})();
以下是people.js的代码。
moudle "people"{
export class People{
constructor(name,age){
this.name=name;
this.age=age;
}
get name(){
return this._name;
}
get age(){
return this._age;
}
set name(name){
this._name=name;
}
set age(age){
this._age=age;
}
}
}
Map、Set
这些是新加的集合类型,提供了更加方便的获取属性值的方法,不用像以前一样用hasOwnProperty来检查某个属性是属于原型链上的呢还是当前对象的。同时,在进行属性值添加与获取时有专门的get,set 方法。示例工程:E13。这个工程是Node.js工程。
(function () {
var s=new Set();
s.add("hello world!").add("你好,世界!").add("hola mundo!");
console.log("集合中的元素个数是2吗?\t"+s.size===2);
console.log("集合中有\"hello world!\"这个关键词吗?\t"+s.has("hello world!"));
var m=new Map();
m.set("hello",Math.random());
m.set(s,Math.random());
console.log(m.get(s));
})();
WeakMap、WeakSet
有时候我们会把对象作为一个对象的键用来存放属性值,普通集合类型比如简单对象会阻止垃圾回收器对这些作为属性键存在的对象的回收,有造成内存泄漏的危险。而WeakMap,WeakSet则更加安全些,这些作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉,具体还看下面的例子。示例工程:E14。
(function () {
var ws=new WeakSet();
var wm=new WeakMap();
var student={
name:"李婷",age:22
};
ws.add(student);
wm.set(student,Math.random());
console.log("因为添加到ws的这个临时对象没有其他变量引用它,所以ws不会保存它的值,也就是说这次添加其实没有意思。");
console.log(wm.get(student));
console.log(ws.size==undefined);
console.log(wm.size==undefined);
})();
Proxy
Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。一下子让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处。
(function () {
var student={
name:"李婷",mark:60
};
var interceptor={
set(receiver,property,value) {
console.log(property+ "属性的值变成了"+value);
receiver[property]=value;
}
};
student=new Proxy(student,interceptor);
student.mark=100;
student.name="你好!";
})();
上面代码我已加了注释,这里进一步解释。对于处理程序,是在被侦听的对象身上发生了相应事件之后,处理程序里面的方法就会被调用,上面例子中我们设置了set的处理函数,表明,如果我们侦听的对象的属性被更改,也就是被set了,那这个处理程序就会被调用,同时通过参数能够得知是哪个属性被更改,更改为了什么值。
覆盖
ES6仍然不支持类的重载与多态。子类的成员函数如果与父类成员函数相同则造成覆盖的现象。父类的方法并没消息,可通过super关键字调用。示例工程:E16。
class People{
constructor(name,age){
this.name=name;
this.age=age;
}
printSelf(){
console.log("姓名:"+this.name);
console.log("年龄:"+this.age);
}
}
class Student extends People{
constructor(name,age);
this.hobby=hobby;
}
printSelf(){
super.printSelf();
console.log("爱好:"+this.hobby);
}
}
(function () {
var student=new Student("李婷","羽毛球");
student.printSelf();
})();
Symbols
我们知道对象其实是键值对的集合,而键通常来说是字符串。而现在除了字符串外,我们还可以用symbol这种值来做为对象的键。Symbol是一种基本类型,像数字,字符串还有布尔一样,它不是一个对象。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。之后就可以用这个返回值做为对象的键了。Symbol还可以用来创建私有属性,外部无法直接访问由symbol做为键的属性值。示例工程:E17。
(function () {
var key=Symbol("key");
function StudentClass(name) {
this[key]=name;
}
StudentClass.prototype={
doStuff () {
console.log(this[key]);
}
};
var student=new StudentClass("李婷");
console.log(student["key"]);
student.doStuff();
})();
Math,Number,String,Object 的新API
对Math、Number、String还有Object等添加了许多新的API。对这些新API进行了简单展示。
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false
Math.acosh(3) // 1.762747174039086
Math.hypot(3,4) // 5
Math.imul(Math.pow(2,32) - 1,Math.pow(2,32) - 2) // 2
"abcde".contains("cd") // true
"abc".repeat(3) // "abcabcabc"
Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1,3) // Similar to new Array(...),but without special one-arg behavior
[0,0,0].fill(7,1) // [0,7,7]
[1,3].findIndex(x => x == 2) // 1
["a","b","c"].entries() // iterator [0,"a"],[1,"b"],[2,"c"]
["a","c"].keys() // iterator 0,1,2
["a","c"].values() // iterator "a","b","c"
Object.assign(Point,{ origin: new Point(0,0) })
Promises
Promises是处理异步操作的一种模式,之前在很多三方库中有实现,比如jQuery的deferred 对象。当你发起一个异步请求,并绑定了.when(),.done()等事件处理程序时,其实就是在应用promise模式。HTML5的Web Worker异曲同工,详情请看MDN。示例工程:E18。
/** * 目的:一个HTTP请求网络客户端 * 展示箭头函数、加强型对象字面量、类、内部类、回调、WeakMap等ES6特性的应用 * 展示NodeJS http模块、jsdom模块的应用 * 作者:岬淢箫声 * 邮箱:jiayuxiaosheng@foxmail.com * 日期:2016-10-15 */
var HttpClient = (function () {
var weakMap=new WeakMap();
var that={};
class InnerHttpClient{
constructor(url="www.epsg.org",userName="zhuangtaiqiusi@126.com",password="p.123456"){
this.url=url;
this.userName=userName;
this.password=password;
var privateProperties={
compress:"unknown",onSuccess(){},onFault(){},chunks:[],statusCode:100
};
weakMap.set(this,privateProperties);
that=this;//Promise、NodeJS的http模块中的类等等都会改变上下文环境(Context),在Promise启动后用到本类方法时需要记住this
}
/** * 两个参数是回调函数,回调函数各都有1个参数 */
loadHTML(onSuccess,onFault){
weakMap.get(that).onSuccess=onSuccess;
weakMap.get(that).onFault=onFault;
var http = require('http');
var authorization = "Basic" + new Buffer(that.userName + ":" + that.password).toString("base64");
var options = {
host: that.url,port: 80,path: "/",method: "GET",headers: {
"accept": "*/*",'content-type': "application/atom+xml",'accept-encoding': 'gzip,deflate','accept-language': 'en-US,en;q=0.9','authorization': authorization,'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/54.0.2840.59 Safari/537.36'
}
};
var request = http.request(options,that.onRequest);
request.on("error",that.onError);
request.end();
}
onError(error){
weakMap.get(that).onFault(error);
}
/** * this是ClientRequest * @param response 远端服务器响应的消息体 */
onRequest(response){
var equal = require('assert').equal;
weakMap.get(that).statusCode=response.statusCode;
console.log("状态码:" + response.statusCode);//响应消息头是一次性发送来的
equal(response.statusCode,200);
console.log("消息头:"+JSON.stringify(response.headers));
weakMap.get(that).compress=response.headers["content-encoding"];
response.on("data",that.onData);
response.on("end",that.onEnd);
}
/** * this是IncomingMessage * @param chunk 用gzip压缩后的二进制流 */
onData(chunk){
weakMap.get(that).chunks.push(chunk);//响应消息体可能是分批发送的。
}
/** * this是IncomingMessage */
onEnd(){
var zlib = require('zlib');
var buffer=Buffer.concat(weakMap.get(that).chunks);
var compress=weakMap.get(that).compress;
switch(compress){
case "gzip":
zlib.gunzip(buffer,(err,decode)=>{
that.resolveHTML(decode.toString());
});
break;
case "deflate":
zlib.inflate(buffer,decode)=>{
that.resolveHTML(decode.toString());
});
break;
default:
that.resolveHTML(buffer.toString());
break;
}
weakMap.get(that).onSuccess(weakMap.get(that).statusCode);
}
resolveHTML(html){
var jsdom=require('jsdom');
console.log("正在解析网页中的所有锚链接。。。")
jsdom.env(html,[],function (domerr,window) {
var doms=window.document.getElementsByTagName("a");
for(var i=0;i<doms.length;i++){
var innerHTML=doms[i].innerHTML.toString().trim();
if(!(innerHTML.contains("<")||innerHTML.contains("&"))){
if(doms[i].href==undefined){
console.log(innerHTML+"\t");
}else{
console.log(innerHTML+"\t"+doms[i].href);
}
}
}
});
}
start(){
var promise = new Promise(this.loadHTML);
promise.then(result => {
console.log("成功了,代码是:" + result);
},err=> {
console.log("失败了,原因是:" + err);
});
console.log("任务进行中,请稍等。");
}
}
return InnerHttpClient;
})();
(function () {
String.prototype.contains = function (search) {
return this.indexOf(search) != -1;
};
var client = new HttpClient();
client.start();
})();
转载请注明来源: http://blog.csdn.net/caoshiying非法转载或抄袭将委托CSDN追究法律责任。