/*
* es6中模块和类整个属于严格模式
*
*
* 总结:
* 1.私有属性,
* 2.私有方法, --> es6并未提供,添加私有属性或私有方法的三种方式
* 1.通过符号标识
* 2.通过把类中引用的私有方法拉出
* 3.通过Symbol的唯一性进行处理
* 3.静态属性,通过Class.call = 'zhangsan'设置
* 4.静态方法,static call () {} 为类的方法
* 5.set和get关键字,
* 与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为
* es类定义的方法皆为不可枚举
* 6.新建对象时,必须加new(可使用new.target进行判断是否加了new,不加new,此时的new.target为undefined,加了后则指向构造函数)
* 7.不进行变量提升 --> 考虑到父类可能用let进行表达式方式定义
* 8.this的指向
* 类的this指向一般为新建的实例,但当类中的函数通过别的方式被复制后结果未必,如
* {
class Parent {
constructor (name, age) {
this.name = name;
this.age = age;
}
tell () {//函数在执行的时候再去找调用其的对象,把this指向它
console.log(`我叫${this.name}, 今年${this.age}岁了`);
}
}
let parent = new Parent('zhangsan', 20);
let tell = parent.tell;
//tell();//此时报错
}
{
class Parent {
constructor (name, age) {
this.name = name;
this.age = age;
// this.tellSelf = this.tell.bind(this);//提前把this指向给Parent
this.tellSelf = () => {this.tell()};//此时的this也已经被指向了Parent
}
tell () {
console.dir(this);
console.log(`我叫${this.name}, 今年${this.age}岁了`);
}
}
let parent = new Parent('zhangsan', 20);
let tell = parent.tellSelf;
console.dir(tell);
tell();//正常
}
{
console.log('==============')
//Proxy:在目标对象前架设一层拦截,通过其对对象进行增删改查,并自定义设置增删改查的行为
class Parent {
constructor (name, age) {
this.name = name;
this.age = age;
}
tell () {
console.log(`我叫${this.name}, 今年${this.age}岁了`);
}
}
//封装一个返回Proxy实例的函数
function getProxy (target) {
const cache = new WeakMap();//此处实现了闭包,所以此cache就有了实际的意义
let handler = {
get (target, key) {
const value = Reflect.get(target, key);
if (typeof value !== "function") {
return value;
}
if (!cache.has(value)) {
//cache.set(value, value);
cache.set(value, value.bind(target));//此处把所有方法的this都指向了target
}
return cache.get(value);
}
};
return new Proxy(target, handler);
}
let parentProxy = getProxy(new Parent('zhangsan', 30));
let tell = parentProxy.tell;
tell();
}
*
*
*
*
* 9.遍历器属性的添加(Symbol.iterator或者Generator函数)
* 想使生成的实例能够使用for...of方法或...real,在prototype上设置 Symbol.iterator属性 或 Generator函数
* {
class Parent {
constructor (...arg) {
this.arg = arg;
}
*[Symbol.iterator] () {//Generator函数通过为prototype添加Symbol.iterator属性
for (let i of this.arg) {
yield '哈哈' + i;
}
}
}
let parent = new Parent(1, 2, 3, 4);
for (let i of parent) {
console.log(i);
}
}
*
*
*
* 10.类的继承:
* > 在构造函数中必须执行super函数,因为ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
* > es5和es6实现this的方式不同,导致对于原生构造函数属性的继承和扩展出现根本的不同,如下代码:原因是原生构造函数内部属性不能被子类的this拿去
* {
class MyArray extends Array {
constructor (...arg) {//此处...arg为把传入的实参转化为数组arg
super(...arg);//此处...arg则是把数组拆开
}
}
let array = new MyArray(1, 2, 3, 4);
console.dir(array);//此时等同于对Array的复制
}
{
function MyArray (...arg) {
Array.apply(this, arg)
}
//实现了父级的prototype的实例为子级函数的protype
MyArray.prototype = Object.create(Array.prototype, {
constructor: {
value: MyArray,//显示的值
configurable: true,//
enumerable: true,//可枚举性
writable: true //可修改
}
});//Object.create(A, B);把A复制给B的__proto__,返回
let array = new MyArray(1, 2, 3, 4);
console.dir(array);//此处1,2,3,4不能显示
array[0] = 1;
console.log(array[0]);//1
console.log(array.length);//0
}
*
*
*
* > super的指向问题
* 1)在构造函数中可以做为函数执行
* 2)作为对象执行时必须带有属性,此时指向this(狭隘的理解为等同于this)
* 3)只有这两种用法,其他方式报错
* > prototype和__proto__指向
* 1)子类的prototype指向父类原型的实例,和es5一致
* 2)子类的__proto__指向为父类构造函数而es5中子类的__proto__指向为unction的实例
* > 可以通过Reflect.getPrototypeOf(A)或Object.getPrototypeOf(A)获取A的父类
* function getPrototypeOf(A) {
* let B = A.__proto__;
* return B;
* }
*
*
* 11. new.target指向的是正在执行的构造函数
* 在子类执行函数时,父类构造函数中的new.target指向的为子类的构造函数,且this为new.target的实例
*
* 12.mixins混合
* {
//Mixin模式实现
function mixin(...mixins) {
class Mix {}
for (let mixin of mixins) {
copyProperties(Mix, mixin);
copyProperties(Mix.prototype, mixin.prototype);
}
return Mix;
}
function copyProperties (target, source) {
for (let key of Reflect.ownKeys(source)) {
//属性的复制,不仅仅是value的复制,还有enumerable,configurable,writable
if (key !== 'constructor' && key !== 'name' && key !== 'prototype') {
let desc = Reflect.getOwnPropertyDescriptor(source, key);
Reflect.defineProperty(target, key, desc);
}
}
}
}
*
* 原生构造函数:
* Array,String,Object,RegExp,Date,Error,Function,Number,Boolean,Event等
*
*
*
* 对象的理解:属性的四个属性值:value,enumerable,writable,configurable等
* Object的一些方法:Object.create(),及一些和Reflect一样的方法,如:
* defineProperty(),deleteProperty(),getOwnPropertyDescriptor(),has(),ownKeys(),get(),set()等
*
* arguments.callee.caller.arguments[0] == event 的理解
*
* arguments的属性:
* callee --> 指代当前函数
* length
*当前函数的属性:
* caller --> 指代调用当前函数的函数(严格模式下不可使用)
*
* 火狐浏览器下:arguments.callee.caller为用户绑定的事件监听函数的事件函数,参数有event
*
* 严格模式下,arguments和caller,callee有可能不可使用
* */
参考自阮一峰es6入门 http://es6.ruanyifeng.com/#docs/class#Class-的-Generator-方法