Open LiuL0703 opened 6 years ago
箭头函数使用注意点
function Timer(){
this.seconds = 0;
setInterval(()=>this.seconds++,1000)
}
var timer = new Timer();
setTimeout(()=>console.log(timer.seconds),3000)
// 3
上面代码中,Timer函数内部的setInterval调用了this.seconds属性,通过箭头函数将_this绑定在Timer的实例对象。否则,输出结果是0,而不是3。
function Timer () {
this.seconds = 0
setInterval(function(){ this.seconds++}, 1000)
}
var timer = new Timer()
setTimeout(function(){ console.log(timer.seconds)}, 3000)
// 0
includes():返回布尔值 表示是否找到参数字符串 startsWith():返回布尔值 表示参数字符串是否在源字符串的头部 endsWith():返回布尔值 表示参数字符串是否在源字符串的尾部
var s = "Hello World!";
s.includes("l"); // true
s.startsWith("Hello") //true
s.endsWith("!") // true
同时这三个方法都支持第二个参数 表示搜索位置
var s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。
返回一个新的字符串表示原字符串重复n次
x.repeat(3) // "xxx"
"Hello".repeat(2) //"HellloHello"
"na".repeat(0) // ""
参数为小数则会被向下取整 如果repeat的参数是负数或者Infinity,会报错。 但是,如果参数是0到-1之间的小数,则等同于0,这是因为会先进行取整运算。0到-1之间的小数,取整以后等于-0,repeat视同为0。 如果repeat的参数是字符串,则会先转换成数字。
"n".repeat(2.9) // "nn"
'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError
'na'.repeat(-0.9) // ""
'na'.repeat(NaN) // ""
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"
Math.trunc()::去除一个数的小数部分 返回正数部分 (对空值和无法截取的值 返回NaN)
Math.tranc(1.1) // 1
Math.tranc(-1.1) // 1
Math.sign: 判断一个数到底是正数 复数 还是0 正数返回1 负数返回-1 为0 返回0 为-0 返回-0 其他值返回 NaN
Math.sign(-5) // -1
Math.sign(5) // +1
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign('hubwiz'); // NaN
Math.cbrt:计算一个数的立方根。
Math.cbrt(-1); // -1
Math.cbrt(0); // 0
Math.cbrt(2); // 1.2599210498948732
Math.fround:返回一个数的单精度浮点数形式。
Math.fround(0); // 0
Math.fround(1.337); // 1.3370000123977661
Math.fround(NaN); // NaN
Math.hypot:返回所有参数的平方和的平方根。
Math.hypot(3, 4); // 5
Math.hypot(3, 4, 5); // 7.0710678118654755
Math.hypot(); // 0
Math.hypot(NaN); // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot(3, 4, '5'); // 7.0710678118654755
Math.hypot(-3); // 3
如果参数不是数值,Math.hypot方法会将其转为数值。只要有一个参数无法转为数值,就会返回NaN。
ES6引入的一种新的原始数据类型 表示独一无二的值 是JavaScript的第七种数据结构 (undefined, null,Boolean,String,Number,Object,Symbol) Symbol通过Symbol函数生成 凡是属性名属于Symbol类型 就是独一无二的 可以保证不与其他属性名冲突
let s = Symbol();
typeof s
// "symbol"
var s1 = Symbol("foo");
var s2 = Symbol("foo");
console.log(s1===s2); // false;
做属性名的Symbol三种写法
var mySymbol = Symbol();
//First
var a = {};
a[mySymbol] = "Hello";
// Second
var a = {
[mySymbol]:"Hello"
};
// Third
var a = {};
Object.defineProperty(a,mySymbol,{value:"Hello"})
// 上面所以写法都会得到相同的结果
console.log(a[mySymbol]); // "Hello"
注意:
Symbol作为属性名,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有Symbol属性名。 Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的Symbol值。
var obj = {};
var a = Symbol("a");
var b = Symbol("b");
obj[a] = "Hello";
obj[b] = "World";
obj["c"] = "Wow";
var objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols); // [Symbol(a),Symbol(b)]
使用给定的key搜索现有符号 如果有找到则返回 否则新创建一个 有时,我们希望重新使用同一个Symbol值,Symbol.for方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。 Symbol.for()与Symbol()这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的Symbol类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat") 30次,每次都会返回同一个Symbol值,但是调用Symbol("cat") 30次,会返回30个不同的Symbol值。
Symbol.for("bar")===Symbol.for("bar");
// true;
Symbol("bar")===Symbol("bar")
// false;
为给定的符号从全局符号注册表中索检一个共享符号键 Symbol.keyFor方法返回一个已经登记的Symbol类型的值key
var s1 = Symbol.for("foo");
Symbol.For(s1); // "foo"
var s2 = Symbol("bar");
Symbol.For(s2); // undefined
Promise 对象用于异步计算。一个 Promise 表示一个现在或将来可用,亦或永远不可用的值。 Promise 对象 两个特点
var promise = new Promise(function(resolve,reject){
// some code
if(/* 异步操作成功*/){
resolve(value);
}else{
reject(error);
}
});
Promise构造函数接受一个函数作为参数 该函数 提供两个参数分别是resolve和reject 这两个函数又JavaScript引擎提供 不用自己实现 其中resolve函数的作用是将Promise对象的状态从"未完成"=>"成功"(即从Pending=>Resolved)在异步操作成功时调用 并将异步操作结果 作为参数传递出去; reject函数则用来将Promise对象的状态从Pending=>"Rejected"在异步操作失败时调用 将一步操作报出的错误作为参数 传递出去 Promise实例生成后可以用then 方法分别指定Resolved状态和Reject状态的回调函数
promise.then(function(value){
// success
},function(value){
// failure
});
then 方法可以接受两个回调函数作为参数第一个回调函数是Promise对象的状态变为Resolved时调用 第二个回调函数是Promise对象状态变为Reject时调用 其中第二个参数可选 这两个函数都接受Promise对象传出的值作为参数
then() 方法返回一个Promise 有两个参数 分别为Promise在 success和failure情况下的回调函数
p.then(onFulfilled,onRejected);
p.then(function(value){
// success
},function(reason){
// failure
})
var p2 = new Promise(function(resolve,reject){
resolve(1);
});
p2.then(function(value){
console.log(value); // 1
return value+1;
}).then(function(value){
console.log(value); // 2
});
catch() 方法只处理Promise被拒绝的情况 并返回一个Promise 该方法的行为和调用Promise.prototype.then(undefined,onRejected)相同
p.catch(onRejected);
p.catch(function(reason){
// rejected
})
示例:
var p1 = new Promise(function(value){
resolve("Success");
});
p1.then(function(value){
console.log(value); // "Success"
throw "Wrong";
}).catch(function(e){
console.log(e); // "Wrong"
});
.catch()方法主要用于处理promise组合
Promise.all()方法用于将多个Promise实例 包装成一个新的Promise实例
var p = new Promise([p1,p2,p3]);
Promise.all()接受一个数组作为参数 p1,p2,p3都是Promise 对象的实例 如果不是就会调用Promise。resolve方法 将参数转化为Promise实例在处理 p的状态由p1 p2 p3 决定 只有p1,p2,p3状态都为fullfilled p的状态才会是fullfilled 只要其中之一是rejected p 的状态就变为rejected 同时返回第一个被rejected的实例
var p = Promise.resolve(3);
Promise.all([true,p,]).then(value=>{
console.log(value) // [true,3]
})
race函数返回一个Promise 这个Promise根据传入的Promis中的第一个状态确定
var p1 = new Promise(function(resolve,reject){
setTimeout(resolve,500,"one");
})
var p2 = new Promise(function(resolve,reject){
setTimeout(resolve,100,"two");
})
Promise.race([p1,p2]).then(value=>{
console.log(value); // "two"
})
Promise.reject()方法会返回一个新的实例 该实例状态为rejected
Promise.reject("Testing Static reject").then(function(reason){
// 未被调用
},function(reason){
console.log(reason); // "Testing Static reject"
});
Promise.reject(new Error("faill")).then(function(error){
// 未被调用
},function(err){
console.log(err); // [Error:fail]
})
该方法返回一以给定值resolve掉的Promise对象 如果这个值是thenable 返回的Promise会继续这个thenable的对象接收到它的最终状态 否则这个被返回的promise对象会以这个值被fullfilled
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);
value用来resolve待返回的promise对象的参数。既可以是一个Promise对象也可以是一个thenable。 使用静态方法Promise.resolve
Promise.resolve("Success").then(function(val){
console.log(value); // "Success"
},function(val){
// not found
});
以数组resolve
varv p = new Promise.resolve([1,2,3]);
p.then(function(v){
console.log(v[0]); // 1
});
resolve另一个Promise对象
var o = Promise.resolve(true);
varv cast = Promise.resolve(o);
cast.then(v=>{
console.log(v) //true
})
生成器对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。从语法上可以理解为Generator函数是一个状态机 封装多个内部状态 执行Generator函数返回一个遍历对象 可以依次遍历Generator函数内部的每一个状态 Generator函数有两个特征
function* helloWorldGenerator(){
yield"hello";
yield"world";
return "ending";
}
var hw = helloWorldGenerator();
### next方法
调用next方法 使指针移向下一个状态 也就是说 每次调用next方法 内部指针就从函数头部或上一次停下来的地方开始执行 直到遇到下一个yield语句 为止 换言之 Generator函数是分段执行的 yield语句是暂停执行的标记 而next方法可以恢复执行
```js
hw.next();
// { value: 'hello', done: false }
hw.next();
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
用来在一个Generator函数里面执行另一个Generator函数 如果yield命令后面跟的是一个遍历器对象 需要在以yield命令后加* 号 表明返回的是一个遍历器对象
function* anotherGeneator(i){
yield i+1;
yield i+2;
yield i+3;
}
function *generator(i){
yield i;
yield* anotherGenerator();
yield i+10;
}
var gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
let
因为JavaScript中没有块级作用域这一概念 而使用let 则可以达到这一效果 let允许把变量作用域限制在块级域中 与var不同的是:var申明要么是全局的 要么是函数级的 而 无法是块级作用域
let vs var
let作用域 是 块级 var 作用域是函数
关于let 声明提升
其他: let 声明会提升到块顶部 ,从块顶部到该变量的初始化语句,这块区域叫做 TDZ(临时死区) 如果你在 TDZ 内使用该变量,JS 就会报错
块级作用域
很多语言中都有块级作用域 JavaScript中使用var 声明变量 以function来划分作用域 用大括号 "{}" 无法限制var的作用域 使用var声明的变量据欧变量提升(declaration hoisting)的效果 ES6中增加的let 在 {} ,if for 里声明 用法与var 相同 但是作用域限定在块级 let声明变量不存在变量提升
const
const 用来声明和创建一个常量
类声明和类表达式
类声明
类声明式定义类的一种方式 使用class关键字后跟一个类名就可以定义一个类
变量提升
类声明与函数声明不同的一点是 函数声明存在变量提升现象 而类声明不存在 也就是说 必须先声明类 才能使用 否则会抛出异常
类表达式
类表达式是另外一种方式 就像函数表达式一样 在类表达式中 类名是可有可无的 如果定义了类名 则该类名只有在类体中才可以访问到
构造函数
类成员包括类构造器和类方法(包括静态方法和实例方法) class 根据constructor方法来创建和初始化对象 constructor方法是类的默认方法 通过new 命令生成对象实例时 自动调用该方法 一个类只能有一个constructor方法 如果没有显示定义就会被隐式添加
constructor默认返回实例对象(即this)完全可以指定返回另一个对象
constructor 方法是一个特殊的类方法 它既不是静态方法也不是实例方法 它仅会在实例化一个类的时候被调用 一个类只能有一个名为constructor属性的方法 否则 会抛出SyntaxError异常
静态方法
static关键字定义两个类的静态方法 静态方法被称为无需实例化类也可以当类被实例化 静态方法通常用于为应用程序创建实用函数
extend 关键字 创建子类
extends 关键字可以用来创建继承于某个类的子类
栗子:根据Animal 类创建一个Dog类
Map
map对象是一个简单的键值 任何值(包括对象和原始值)都可以作为一个键或者一个值
上面代码使用set方法 将对象o作为m的一个键 Map也接受一个数组作为参数 该数组的成员是一个个表示键值对的数组
注意Map的键实际上是和内存地址绑定的 知道内存地址不一样就视为两个键
myMap.get(NaN); // "not a number"
var otherNaN = Number("foo"); myMap.get(otherNaN); // "not a number"
set方法返回的是Map本身 因此可以采用链式写法
map 遍历方法
for(var key of myMap.keys()){ console.log(key); } // 0 1 2
for(var item of myMap.entries()){ console.log(item); }
// [0, "zero"] [1, "one"] [2, "two"]
myMap.forEach(function(val,key){ console.log(key+ "="+val); },myMap)
// 0=zero 1=one 2=two
WeakMap的设计目的在于,键名是对象的弱引用(垃圾回收机制不将该引用考虑在内),所以其所对应的对象可能会被自动回收。当对象被回收后,WeakMap自动移除对应的键值对。 典型应用是,一个对应DOM元素的WeakMap结构,当某个DOM元素被清除,其所对应的WeakMap记录就会自动被移除。基本上,WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。WeakMap结构有助于防止内存泄漏。 WeakMap与Map在API上的区别主要是两个,一是没有遍历操作(即没有key()、values()和entries()方法),也没有size属性;二是无法清空,即不支持clear方法。这与WeakMap的键不被计入引用、被垃圾回收机制忽略有关。