全局作用域
函数作用域( 局部作用域 )
块级作用域
动态作用域
全局作用域引申:
var abc = '2016011172'; // 真全局变量,不可被delete。
abcd = '石路'; // 伪全局变量,可被delete。被挂载到window上,作为属性
// 闭包
var decLive = (function () {
var live = 30;
// 拿不到b
function decline(count) {
var b = 2;
// 此处能向上查找,拿到live
live = live - count
return live > 0 ? live : '没命了';
}
return decline;
})();
PowerShell 中 new-item xxx.js 即可
1、原型链的方式做继承:
Persons.prototype.say = function() { console.log('我是人类') };
2、类的静态方法拿不到实例对象的信息。
场景一:u前u后
var s = ''; // utf16编码字符 表示 4个字节的字符
var s2 = '\uD842\uDFB7'; // utf16编码 4个字节
console.log(/^\ud842/.test(s2)); // true ×
console.log(/^\ud842/u.test(s2)); // false √ 符合逻辑
正则默认只匹配 两个字节 的字符,而’’ 是 四个字节 的字符
如果不加u修饰,则就当常规匹配,匹配英文等(2个字节的字符)。
加了u修饰符,则可以会严格按照unicode码匹配(大于2个字节的字符),而 ‘\uD842\uDFB7’ 是4字节,是一个汉字。故\ud842 2字节是不匹配的。
场景二: 通过码点判断字符(任意字节)
/\u{61}/u.test('a'); // true a的码点:61
\u{20BB7}/u.test(''); // true 的码点: 20BB7
// 注: \u {} u修饰符 三者缺一不可
场景三: 量词
/{2}/.test(''); // false 因为该汉字为4字节,需要u修饰符,进行unicode多字节匹配。
/{2}/u.test(''); // true
/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true 212A是大写K的码点
总结: 到了es6,匹配字符,加个u 绝对没毛病,如果不加可能出现匹配异常。
模板字符串 可以配合函数。
function price(string, ...args) {
console.log(string); // ["您此次的", "字符串2", "字符串3", raw: Array(3)]
console.log(args); // ["rabbit", "1"]
return (string + args);
}
let txt = price`您此次的${'rabbit'}字符串2${'1'}字符串3`;
console.log(txt); // 您此次的,字符串2,字符串3rabbit,1
const price = 13.8;
// es5 apply 非反射
const rs1 = Math.floor.apply(null, [price]); // 编译阶段已指定方法
// es6 Reflect.apply 反射
const rs2 = Reflect.apply(price > 100 ? Math.floor : Math.ceil, null, [price]) // 在执行阶段指定方法
console.log(rs1, rs2); // 13 14
const c1 = Reflect.construct(String, ['shoushou']);
console.log(c1); // String {"shoushou"}
使用方式和效果和Object.defineProperty基本一样,仅返回值不同。
var obj = {a:1,b:2};
var arr = [2020,888];
Reflect.get(obj,'b') // 2
Reflect.get(arr,0) // 2020
// 见console.log(Reflect)
// 查看对象的所有属性的描述(enumerable,configurable,writable,…)
// 对象是否拥有某属性
// 对象是否可扩展(有没有被freeze)
Reflect.getOwnPropertyDescriptor(obj, 'name');
// {value: "die", writable: true, enumerable: true, configurable: true}
const obj = {
name: '欢乐家园A栋501',
price: 190
};
const p = new Proxy(obj, {
get(target, key) {// target: 代理的对象,key: 读操作时的键值
if (key === 'price') {
return target[key] + 30;
} else {
return target[key];
}
}
});
console.log(p.name); // 欢乐家园A栋501
console.log(p.price); // 220
1、数据只读化
const obj = {
name: '欢乐家园A栋501',
price: 190
};
const p = new Proxy(obj, {
// ... get
set(target, key, value) {
return false; // ++
}
});
p.name = '卖nima的房子';
console.log(p.name); // 欢乐家园A栋501 // 中介已无权修改
obj.name = '卖nima的房子';
console.log(p.name); // 卖nima的房子 // 卖家自身可以修改
注: 虽然中介即遍历p,是只读的。但是obj自身还是可修改的。
这点和Object.freeze 不一样,后者是完全锁死,不能修改。
2、校验
// 即使用set进行if else逻辑处理。
3、监控(下述)
前言: 比如验证逻辑,我们应该解耦,尽量使函数满足多场景,强复用。而不是对每一个参数进行验证或者写重复逻辑。故,可以监控参数是否异常,进行异常的触发,然后交由某个收集者(如EventListener)进行汇总以及上报。
// 绑定监听器
window.addEventListener('error', (e) => {
console.log('监控到错误: ', e.message);
}, true);
const obj = {
name: '石路',
age: 24
};
const p = new Proxy(obj, {
set(target, key, value) {
if (key === 'age') {
if (value > 100) {
throw new TypeError('age is exceed')
} else {
target[key] = value;
}
} else {
return false;
}
}
});
p.age = 250;
console.log(obj); // 因触发Error 故,代码已被强行终止,log不会执行
Math.random().toString(36).slice(-8) // "wy1lb7en"
1、yield * (带星号):跟上 可迭代的对象 | generator实例
2、高级用法,next传参
function* gen() {
// next内的值,每次都替换上一次的 yield部分。
// 而第一次没有yield可以替换。
// 当next第二次传入后,开始替换 ,即20 + 7 = 27
let val = (yield [1, 3, 5]) + 7;
console.log(val);
}
let fn = gen();
console.log(fn.next(10)); // {value: Array(3), done: false}
console.log(fn.next(20)); // 27 \n {value: undefined, done: true}
3、l.throw()外部抛出异常,内部try catch捕获
function* gen() {
while (true) {
try {
yield 1;
} catch (e) {
console.log(e.message);
}
}
}
let g = gen();
console.log(g.next());
g.throw(new Error('nmb'));
console.log(g.next());
小结:
1、l.next() 会返回yield 携带的参数或generator实例
2、若next传入的参数会覆盖上一次yield返回值,控制下一次运行结果。
3、若next不传参数,上一次yield的返回值回undefined
authors[Symbol.iterator] = function () { // Symbol.iterator 可迭代协议
// ... Symbol.iterator function
return {
next() {
// 具有next方法 并返回指定结构
}
}
let authors = {
allAuthors: {
science: ['Ben', 'Kitty', 'Alice'],
kartoon: ['AuToMan', 'FlashMan'],
fantasy: ['SuperMan', 'SpiderMan', 'IronMan']
},
address: []
}
// 1、迭代器协议 正常代码逻辑
authors[Symbol.iterator] = function () { // Symbol.iterator 可迭代协议
let allAuthors = this.allAuthors;
let keys = Reflect.ownKeys(allAuthors);
let currentKey = '';
let currentVal = '';
return {
next() {
if (!currentVal.length) {
if (keys.length) {
currentKey = keys.shift();
currentVal = allAuthors[currentKey];
}
}
return {
value: currentVal.shift(),
done: !keys.length && !currentVal.length
}
}
}
};
for (let key of authors) {
console.log(key);
}
// 2、迭代器协议 与 生成器的混合使用
authors[Symbol.iterator] = function* () {
let allAuthors = this.allAuthors;
let keys = Reflect.ownKeys(allAuthors);
let currentKey = '';
let currentVal = '';
while (true) {
if (!currentVal.length) {
if (keys.length) {
currentKey = keys.shift();
currentVal = allAuthors[currentKey];
} else {
break;
}
yield currentVal.shift();
} else {
yield currentVal.shift();
}
}
};
for (let key of authors) {
console.log(key);
}
两种迭代器方法都是为了个性化提取数据,而第二种显得更为优雅。
注意点:
1、默认导出和花括号连用
// module.js
class Dog {
say() {
console.log('dog身体健康');
}
}
class Cat {
say() {
console.log('cat身体健康');
}
}
export default class People {
say() {
console.log('people身体健康');
}
}
export {
Dog,
Cat
}
// enter.js
import P, { Dog, Cat } from './lesson2-14-mod';
2、星号导出(不能再括号导出)
import * as Mod from '1.js' // *即将模块全部导入在Mod对象下
3、没有解构赋值,仅有 as 别名 // named Module