ES next相关

发展历史

脚本语言:

  1. 浏览器脚本:JavaScript作为一个脚本语言出现。
  2. 服务器脚本:PHP / ASP / JSP。

JavaScript相关知识:

  1. ECMAScript是一个标准,JavaScript是标准的实现;
  2. ECMAScript是JavaScript的规格;
  3. JavaScript实际上就是ECMAScript的一个方言,还有其他方言如JScript,ActionScript;
  4. 浏览器端对于语言特性的实现,有一些滞后,即语言方面实现了,浏览器端不一定实现了;
  5. 浏览器在用户端的升级也有一些滞后。
babel

因为浏览器的版本和语言本身有差异,所以要对语言进行编译降级。

babel的编译流程:

  1. parse:把源码转成AST。
  2. transform:应用各种内置的插件对AST的转换。内置插件做的转换包括两部分,一是把不支持的语法转成目标环境支持的语法来实现相同功能,二是不支持的 api 自动引入对应的 polyfill。
  3. generate:把AST转成目标代码,并且生成sourcemap。

babel的编译方式 / 版本:

  1. babel 6:根据ES的标准来做兼容。
    新的语法和 api 进入 es 标准的过程:

    1. stage 0:strawman,只是一个想法。
    2. stage 1:proposal,值得继续的提议。
    3. stage 2:draft,起拟草案。
    4. stage 3:candidate,备选方案。
    5. stage 4:finished,完成筛选,成为标准。

    babel6引入了preset的概念,即plugin的集合。通过选择不同的preset,加上手动引入一些插件,就是所有babel会做的转换。
    babel 6的缺点:ES的标准每年都会变,转换可能编程无用功,还会增加产物提及。polyfill是手动引入的比较麻烦。

  2. babel 7:
    解决babel6的问题:babel 7 废弃了 preset-20xx 和 preset-stage-x 的 preset 包,而换成了 preset-env,preset-env 默认会支持所有 es 标准的特性,如果没进入标准的,不再封装成 preset,需要手动指定 plugin-proposal-xxx。
    根据用户的一些浏览器的特性,在运行时动态引入这些polyfill(垫片),使得打包成的bundle大小最小。
    polyfill其实就是在一个只支持es5的浏览器中去运行es6时需要加的额外的引入的一些东西。

函数解析

new 一个箭头函数会如何?
  1. 会报错,提示内容为:TypeError: function is not a constructor
  2. babel编译时,会把this转成(void 0);,即undefined。
不能使用箭头函数的情况
  1. arguments
const Person = function(age, name) {
	this.age = age;
	this.name = name;
	const obj = {'0': 18, '1': 'lulu', '2': 'teacher', '3': 'esnext'};
	console.log(arguments.callee);
	obj.length = 4;//转成伪数组
	console.log(Array.prototype.slice.call(obj, 2));
}
const p = new Person(18, "lulu");
//['teacher', 'esnext']
//如果上述Person使用的是const Person = (age, name) => {...},则会报TypeError: Person is not a constructor的错误

// arguments / callee / caller
const fibonacci = function(num) {
	if(num <= 2) return 1;
	return arguments.callee.caller(num - 1) + arguments.callee.caller(num - 2);
}
console.log(fibonacci(4));
1. arguments:在函数调用时,会自动在该函数内部生成一个名为arguments的隐藏对象。该对象只是一个伪数组,可以使用arguments[index]获取函数调用时传递的实参。
2. 只有上函数被调用时,arguments对象才会创建,未调用时其值为null。
3. caller:在一个函数调用另一个函数时,被调用函数会自动生成一个caller属性,指向调用它的函数对象。如果该函数当前未被调用,或并非被其他还是调用时,caller为null。
4. callee:当函数被调用时,它的arguments.callee对象就会指向自身,即对自身的一个引用。由于arguments在函数被调用时才有效,因此arguments.callee在函数未调用时是不存在的(即null.callee),且直接引用它会产生异常。**在使用函数递归调用时推荐使用arguments.callee代替函数名本身**。
  1. yield
  2. 构造函数的原型方法上

数组和对象

//数组的细节
// 需要使用 Array.from 或者 .fill(0)
const funcGenerator = (num) => 
	Array.from(new Array(num)).map(
		item => 
			params => console.log(params)
	);
const funcGenerator2 = (num) => 
	new Array(num).fill(0).map(
		item => 
			params => console.log(params)
	);

//对象的细节
console.log(NaN === NaN); //false
console.log(Object.is(NaN, NaN)); //true
//上述为true的原因:ES next 采用了 SameValueZero() 的比较,这是一个引擎内置的比较方式。下述也是,Object的方法基本采用这种方式来比较。
console.log([NaN].indexOf(NaN)); //-1
console.log([NaN].includes(NaN)); //true

Object.assign 是深拷贝还是浅拷贝?

第一层是深拷贝,更深层是浅拷贝。如下:

let dist = { foo: "foo" };
let bar = { bar: { bar: "bar" } };
let baz = { baz: "baz" };
const res = Object.assign(dist, bar, baz);
bar.bar.bar = "newBar";
baz.baz = "newBaz";
console.log(res); 
// { foo: 'foo', bar: { bar: 'newBar' }, baz: 'baz' }
console.log(res === dist); // true

Proxy

const xiaohong = {
	age: 34
}
const xhProxy = new Proxy(xiaohong, {
	get: function(target, propKey, receiver) {
		console.log('Get:', target, propKey);
		return Reflect.get(target, propKey, receiver);
	},
	set: function(target, propKey, value, receiver) {
		console.log('Set:', target, propKey, value);
		return Reflect.set(target, propKey, value, receiver);
	}
});
console.log(xhProxy.age = 35);
get / set 拦截代理
class Person {
    constructor() {

    }
    _age = "";
    get age() {
        console.log(`actually I am ${this._age} years old~`)
        return "17"
    }

    set age(val) {
        console.log(" It is useless to set my age, I am 17!");
        this._age = val;
    }
}

// const luyi = new Person();
// luyi.age = "35";
// console.log("luyi is", luyi.age);
如何实现断言函数
const assert = new Proxy({}, {
	set(target, warning, value) {
		if(!value) {
			console.error(warning);	
		}
	}
});
const teacher = 'luyi';
// 如果断言的内容是假的,就打印
assert['The teacher is luyi'] = (teacher === 'yunyin');
receiver

receiver指向原始的读操作时所在的那个对象,一般情况下指的是Proxy的实例。

const luyi = { age: 35 };
const luyiProxy = new Proxy(luyi, {
	get: function(target, propKey, receiver) {
		return receiver;
	},
	set: function(target, propKey, value, receiver) {
		console.log('set:', target, propKey, value);
		return Reflect.set(target, propKey, value, receiver);
	}
});
console.log(luyiProxy.age === luyiProxy) // true
Reflect
  1. 将Object上一些明显属于语言内部的方法放到Reflect对象上,实现Object和Reflect一同部署。
  2. 修改某些Object方法的返回结果,让其更合理。
const teacher = {
	age: 18,
	name: 'luyi',
};
Reflect.defineProperty(teacher, 'lessions', {
	writable: false,
	enumberable: false,
	configurable: false,
	value: 'vue'
});
const res = Reflect.defineProperty(teacher, 'lessions', {
    writable: true,
    enumerable: true,
    configurable: true,
    value: ['es6', 'esnext']
})
console.log(res);//false
//如果使用Object.defineProperty则会直接报错TypeError: Cannot redefine property: lessions
//Reflect.defineProperty的返回值为true/false

Map、Set、WeakMap、WeakSet

  1. Weak-表示作为唯一的部分必须是一个对象,即key必须是一个对象。
  2. Weak-是一个弱引用,不用考虑GC(垃圾回收)。
const foos = new WeakSet();
class Foo {
	constructor() {
		foos.add(this);
	}
	method() {
		if(!foos.has(this)) {
			throw new TypeError("Foo.prototype.method只能在实例上调用");
		}else {
			console.log("using methods");
		}
	}
};
let f = new Foo();
let b = {};
Foo.prototype.method.call(b);
//TypeError: Foo.prototype.method只能在实例上调用

迭代器,Iterator

迭代器是一个接口,为各种不同的数据提供统一的访问机制。任何数据结构只要部署了 Iterator 接口,就可以完成遍历操作。
本质:指针。
主要供给for...of进行消费。
原生具备 Iterator 的数据结构有:Array、Map、Set、String、TypedArray、arguments、NodeList

let m = new Map();
m.set('a', 'foo');
m.set('b', 'bar');
m.set('c', 'baz');
let k = m.keys();
console.log(k.next());
console.log(k.next());
console.log(k.next());

let arr = [1, 2, 3, 4, 5];
let k = arr[Symbol.iterator]();
console.log(k.next());
console.log(k.next());
console.log(k.next());
console.log(k.next());
console.log(k.next());
console.log(k.next());

Object.entries

const obj = { a: 11, b: 22, c: 33 }
console.log(Object.entries(obj)); // [ [ 'a', 11 ], [ 'b', 22 ], [ 'c', 33 ] ]
console.log(Object.keys(obj)); // [ 'a', 'b', 'c' ]
console.log(Object.values(obj)); // [ 11, 22, 33 ]

// 非 generator 的方法
function entries(obj) {
    let arr = [];
    for (let key of Object.keys(obj)) {
        arr.push([key, obj[key]])
    }
    return arr;
}

// generator 的方法
function* entires(obj) {
    for (let key of Object.keys(obj)) {
        yield [key, obj[key]];
    }
}

const k = entries(obj);
//console.log(k.next())
//console.log(k.next())
for (let item of k) {
    console.log(item)
}

实现Promise.allSettled

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。当有多个彼此不依赖的异步任务成功完成时,或者总是想知道每个promise的结果时,通常使用它。
相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个reject时立即结束

function allSettled(array) {
	return new Promise((resolve, reject) => {
		if(!(array instanceof Array))
			return reject(new Error('not array'));
		const res = [];
		let count = 0;
		array.forEach((func, index) => {
			Promise.resolve(func).then(value => {
				res[index] = {
					status: 'fulfilled',
					value
				}
			}, reason => {
				res[index] = {
					status: 'rejected',
					reason
				}
			}).fianlly(() => {
				++count === array.length && resolve(res);
			})
		})
	})
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值