Proxy

time 0m
不常用的Proxy操作
image.png

image.png
image.png

回顾原型内容

time 9m10s

  1. function Person(name = 'zhangsan', age = '18') {
  2. this.name = name;
  3. this.age=age;
  4. }
  5. Person.prototype.say=function () {
  6. console.log(`my name is ${this.name},my age is ${this.age}`);
  7. }
  8. new Person('lisi','19').say();
  9. console.log(new Person());

image.png

time 18m39s

  1. function Person(name = 'zhangsan', age = '18') {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. Person.prototype.say = function () {
  6. console.log(`my name is ${this.name},my age is ${this.age}`);
  7. }
  8. var person= new Person('lisi', '19');
  9. // console.log(new Person());
  10. console.log(Object.getPrototypeOf(person));
  11. console.log(Object.getPrototypeOf(person).constructor===Person);//true
  12. console.log(Person.prototype===Object.getPrototypeOf(person));//true

image.png

class

time 19m28s
es6新的关键字class,es5以前是保留字,也不可以var class,变量不能以关键字命名
class(类),js中严格来说是不存在class类的,主要在类c语言,c++、java纯面向对象的编程语言当中,是在模拟一个类的方式
本质上是一个语法糖,本质上还是函数,只不过通过class关键字把它重新封装了一遍,本身什么都没有改变,就是写法上面改变了,可以让可读性、维护性、减少出错机会,这是class的作用

用class类的方式模拟function构造函数
time 22m06s

  1. //class(类)
  2. class Person {
  3. }
  4. console.log(new Person())
  5. console.log(typeof Person);//function

image.png

私有属性、公有属性、静态属性

time 25m50s

  1. //class(类)
  2. class Person {
  3. constructor(name = 'zhangsan', age = '18') {
  4. /*实例化的属性配置:私有属性;因为每一个对象都不一样,实例化对象时传的参数可能不同,
  5. * 每个对象的这些值的value具体值可能不一样,不能共享,新建了两个人,一个老师、一个学生,
  6. * 他们不可能共享名字与年龄*/
  7. this.name = name;
  8. this.age = age;
  9. }
  10. /*公有属性*/
  11. say(){
  12. console.log(`my name is ${this.name}, my age is ${this.age}`);
  13. }
  14. }
  15. console.log(new Person())
  16. console.log(typeof Person);//function

image.png

assign

time 37m31s

  1. function Person(name = 'zhangsan', age = '18') {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. Person.prototype.say = function () {
  6. console.log(`my name is ${this.name},my age is ${this.age}`);
  7. }
  8. Object.assign(Person.prototype, {
  9. eat:function() {
  10. console.log(`I can eat`);
  11. },
  12. drink(){
  13. console.log(`I can drink`);
  14. }
  15. })
  16. /*可枚举,这种方式出来的属性是可以枚举的*/

class不能枚举

time 38m09s

  1. //class(类)
  2. class Person {
  3. constructor(name = 'zhangsan', age = '18') {
  4. this.name = name;
  5. this.age = age;
  6. }
  7. /*公有属性*/
  8. say() {
  9. console.log(`my name is ${this.name}, my age is ${this.age}`);
  10. }
  11. /*这样定义时错的,用简写定义*/
  12. /* eat:function() {//Uncaught SyntaxError: Unexpected identifier
  13. console.log(`I can eat`);
  14. }*/
  15. eat() {
  16. console.log(`I can eat`);
  17. }
  18. drink() {
  19. console.log(`I can drink`);
  20. }
  21. }
  22. console.log(new Person());
  23. //类内部的方法是不可枚举的
  24. console.log(Object.keys(Person.prototype));

默认添加constructor,如果没有自定义

time 40m

  1. class Person {
  2. }
  3. /*没写等效于下面代码,自动给添加,new就必须有constructor才能new,
  4. * 必须有constructor才能new*/
  5. /* class Person {
  6. constructor() {
  7. }
  8. }*/
  9. console.log(new Person());

image.png

constructor与return

time 43m24s

  1. class Person {
  2. constructor() {
  3. return Object.create(null);
  4. }
  5. }
  6. console.log(new Person() instanceof Person);//false

time 44m

  1. function Person() {
  2. }
  3. console.log(new Person() instanceof Person);//true
  1. class Person {
  2. }
  3. console.log(new Person() instanceof Person);//true

函数表达式

time 46m39s

  1. var test=function (){
  2. }
  3. /*可以加个函数名,但这个函数名没有任何意义,一般可以省略
  4. * 上面的写法是一般写法*/
  5. var test=function test1(){
  6. }

time 48m08s

  1. /*class Person{
  2. say(){
  3. console.log(1)
  4. }
  5. }*/
  6. var Foo=class Person{
  7. say(){
  8. console.log(1)
  9. }
  10. }
  11. var Person=class{
  12. say(){
  13. console.log(1)
  14. }
  15. }
  16. new Person().say();//1

class必须通过new的方式执行

time 49m
不像function可以当函数直接运行,也可以当构造函数

  1. /*必须通过new 的方式执行 class(表达式的方式)*/
  2. var Person = class {
  3. say() {
  4. console.log(1)
  5. }
  6. }()
  7. Person.say();//TypeError: Class constructors cannot be invoked without 'new'
  1. /*必须通过new 的方式执行 class*/
  2. var person = new class {
  3. say() {
  4. console.log(1)
  5. }
  6. }();
  7. person.say();//1

time 50m46s
知道这种写法就行了,别这样用

  1. /*必须通过new 的方式执行 class*/
  2. var person = new class {
  3. constructor(name = 'zhangsan', age = '18') {
  4. this.name = name;
  5. this.age = age;
  6. }
  7. say() {
  8. console.log(1)
  9. }
  10. }('lisi', '19');
  11. person.say();//1
  12. console.log(person);//{ name: 'lisi', age: '19' }

class不能提升

time 54m

  1. console.log(new Person());//Person {}
  2. function Person() {
  3. }

time 54m03s

  1. console.log(new Person());
  2. //ReferenceError: Cannot access 'Person' before initialization
  3. //不存在TDZ
  4. class Person {
  5. }

属性自定义

time 55m38s
通过class定义,公有的方法可以,但公有的属性不可以,在原型上定义的是公有的,属性定义不到原型上面

  1. class Person {
  2. /*es2017新写法,等于在constructor里面写
  3. * a不是在原型上面定义*/
  4. a = 1;
  5. constructor() {
  6. // this.a=1;
  7. }
  8. /* Person.prototype.say={
  9. }*/
  10. /* this.person.say={
  11. }*/
  12. /*say等于在原型上面定义*/
  13. say() {
  14. }
  15. }
  16. console.log(new Person());//Person { a: 1 }

image.png

私有方法

time 1h1m04s
上面的定义,方法都是共有的,但我想让它们私有,不想暴露给外面有什么办法

symbol方式

time 1h3m

  1. const eat=Symbol();
  2. class Person {
  3. /*es2017新写法,等于在constructor里面写
  4. * a不是在原型上面定义*/
  5. a = 1;
  6. constructor() {
  7. // this.a=1;
  8. }
  9. /* Person.prototype.say={
  10. }*/
  11. /* this.person.say={
  12. }*/
  13. /*say等于在原型上面定义*/
  14. say() {
  15. console.log(1);
  16. }
  17. [eat](){
  18. console.log(2);
  19. }
  20. }
  21. console.log(new Person().say());//1
  22. console.log(new Person().eat());
  23. /*new Person()['eat'](),因为eat变量是Symbol定义的是独一无二的值,而不是‘eat’字符串,所以访问不到*/
  24. /*undefined
  25. *Uncaught TypeError: (intermediate value).eat is not a function */

写外面配合call

time 1h5m

  1. const eat=Symbol();
  2. class Person {
  3. // a = 1;
  4. constructor(name,age) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. say(baz) {
  9. console.log(this,baz);
  10. }
  11. }
  12. function children(baz){
  13. return this.bar=baz;
  14. }
  15. console.log(new Person().say());

static

time 1h7m50s

  1. class Person {
  2. static a=1;
  3. }
  4. console.log(new Person());
  5. console.log(new Person().a);//undefined
  6. console.log( Person.a);//1

time 1h10m37s

  1. class Person {
  2. static a=1;
  3. }
  4. console.log(new Person());
  5. console.log(new Person().a);//undefined
  6. console.log( Person.a);//1

image.png

  1. class Person {
  2. static a(){
  3. console.log(1);
  4. }
  5. }
  6. console.log(new Person());
  7. console.log(new Person().a);//undefined
  8. console.log( Person.a);//1

image.png
给函数本身赋值属性,一般不会这样做

相当于以下代码,用static关键字实现了以下代码
image.png

time 13m50s
相当于在外界进行Person.a=10;操作,更方便
静态方法是没有问题的,属性 得升级Chrome版本;

  1. class Person {
  2. // static a=10;
  3. }
  4. Person.a=10;

get

time 1h15m41s
image.png

time 1h17m16s

  1. class Person {
  2. get a() {
  3. console.log(1)
  4. }
  5. set b(value) {
  6. console.log(2)
  7. }
  8. }
  9. var person=new Person();
  10. person.a;//1
  11. person.b=4;//2

time 1h20m36s
默认是严格模式的
“use strict”;

不难,多练几遍就会了,以后都会用这种写法

总结

time 1h21m58s
image.png

继承

time 1h28m02s
extends

time 1h30m22s

  1. class Parent {
  2. constructor(name = 'zhangsan') {
  3. this.name = name;
  4. }
  5. }
  6. class Child extends Parent {
  7. }
  8. console.log(new Child());//Child { name: 'zhangsan' }
  1. class Parent {
  2. constructor(name = 'zhangsan') {
  3. this.name = name;
  4. }
  5. say(){
  6. console.log(1);
  7. }
  8. static a(){
  9. console.log(2)
  10. }
  11. }
  12. /*派生类*/
  13. class Child extends Parent {
  14. }
  15. // console.log(new Child());
  16. /*能继承原型上面的属性*/
  17. console.log(new Child().say());//1
  18. /*能继承构造器上面的属性*/
  19. console.log(new Child().name);//zhangsan
  20. /*不能继承static上面的属性*/
  21. console.log(new Child().a())//Uncaught TypeError: (intermediate value).a is not a function

class实现传值

time 1h33m37s

  1. class Parent {
  2. constructor(name = 'zhangsan') {
  3. this.name = name;
  4. }
  5. say(){
  6. console.log(1);
  7. }
  8. }
  9. //派生类
  10. class Child extends Parent{
  11. constructor(name = 'zhangsan') {
  12. /*必须加super*/
  13. // super();
  14. this.name = name;
  15. }
  16. say(){
  17. console.log(1);
  18. }
  19. }
  20. console.log(new Child())
  21. /*Uncaught ReferenceError: Must call super constructor in derived class before accessing
  22. 'this' or returning from derived constructo*/
  1. class Parent {
  2. constructor(name = 'zhangsan') {
  3. this.name = name;
  4. }
  5. say(){
  6. console.log(1);
  7. }
  8. }
  9. //派生类
  10. class Child extends Parent{
  11. constructor(age = '19') {
  12. /*必须加super*/
  13. /*因为new Child()没有传值*/
  14. // super(name);//Child{name: '', type: 'child', age: '19'}
  15. // super();//Child{name: 'zhangsan', type: 'child', age: '19'}
  16. /*相当于先运行Parent父级的构造函数,new Parent(age=19)*/
  17. super(age);//Child{name: '19', type: 'child', age: '19'}
  18. this.type='child';
  19. this.age = age;
  20. }
  21. say(){
  22. console.log(1);
  23. }
  24. }
  25. console.log(new Child())

time 1h41m38s
super第一种用法,继承父类的属性
在constructor里的,以函数的方式来执行

  1. class Parent {
  2. constructor(name = 'zhangsan') {
  3. this.name = name;
  4. }
  5. say(){
  6. console.log(1);
  7. }
  8. }
  9. //派生类
  10. class Child extends Parent{
  11. constructor(age = '19',name = 'lisi') {
  12. super(name);//Child{name: '19', type: 'child', age: '19'}
  13. this.type='child';
  14. this.age = age;
  15. }
  16. say(){
  17. console.log(1);
  18. }
  19. }
  20. console.log(new Child())
  21. //Child{name: 'lisi', type: 'child', age: '19'}

第二种用法
image.png

time 1h44m55s

  1. let proto = {
  2. y: 20,
  3. z: 40
  4. }
  5. let obj={
  6. x:10,
  7. foo(){
  8. console.log(super.y)//20
  9. console.log(this.y)//20
  10. }
  11. }
  12. Object.setPrototypeOf(obj,proto);
  13. console.log(obj);
  14. obj.foo()

image.png

time 1h48m
image.png

class特征

time 1h53m30s
image.png

package.json
time 1h55m
image.png

  1. 'use strict';
  2. var _createClass = function () {
  3. function defineProperties(target, props) {
  4. for (var i = 0; i < props.length; i++) {
  5. var descriptor = props[i];
  6. descriptor.enumerable = descriptor.enumerable || false;
  7. descriptor.configurable = true;
  8. if ("value" in descriptor) descriptor.writable = true;
  9. Object.defineProperty(target, descriptor.key, descriptor);
  10. }
  11. }
  12. return function (Constructor, protoProps, staticProps) {
  13. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  14. if (staticProps) defineProperties(Constructor, staticProps);
  15. return Constructor;
  16. };
  17. }();
  18. function _classCallCheck(instance, Constructor) {
  19. if (!(instance instanceof Constructor)) {
  20. throw new TypeError("Cannot call a class as a function");
  21. }
  22. }
  23. var Parent = function () {
  24. function Parent() {
  25. var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'zhangsan';
  26. var age = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '18';
  27. _classCallCheck(this, Parent);
  28. this.name = name;
  29. this.age = age;
  30. }
  31. _createClass(Parent, [{
  32. key: 'say',
  33. value: function say() {
  34. console.log('hello world');
  35. }
  36. }, {
  37. key: 'drink',
  38. value: function drink() {
  39. console.log('drink');
  40. }
  41. }], [{
  42. key: 'eat',
  43. value: function eat() {
  44. console.log('eat');
  45. }
  46. }]);
  47. return Parent;
  48. }();
  49. /*class Child extends Parent {
  50. }
  51. console.log(new Child());//Child { name: 'zhangsan' }*/

core-decorators
npm install core-decorators —save
安装,官网最新版本 0.20.0

源码分析
time 1h59m

  1. 'use strict';
  2. var _createClass = function () {
  3. function defineProperties(target, props) {
  4. for (var i = 0; i < props.length; i++) {
  5. var descriptor = props[i];
  6. descriptor.enumerable = descriptor.enumerable || false;
  7. descriptor.configurable = true;
  8. if ("value" in descriptor) descriptor.writable = true;
  9. Object.defineProperty(target, descriptor.key, descriptor);
  10. }
  11. }
  12. return function (Constructor, protoProps, staticProps) {
  13. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  14. if (staticProps) defineProperties(Constructor, staticProps);
  15. return Constructor;
  16. };
  17. }();
  18. function _classCallCheck(instance, Constructor) {
  19. if (!(instance instanceof Constructor)) {
  20. throw new TypeError("Cannot call a class as a function");
  21. }
  22. }
  23. var Parent = function () {
  24. function Parent() {
  25. var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'zhangsan';
  26. var age = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '18';
  27. _classCallCheck(this, Parent);
  28. this.name = name;
  29. this.age = age;
  30. }
  31. _createClass(Parent, [{
  32. key: 'say',
  33. value: function say() {
  34. console.log('hello world');
  35. }
  36. }, {
  37. key: 'drink',
  38. value: function drink() {
  39. console.log('drink');
  40. }
  41. }], [{
  42. key: 'eat',
  43. value: function eat() {
  44. console.log('eat');
  45. }
  46. }]);
  47. return Parent;
  48. }();
  49. /*class Child extends Parent {
  50. }
  51. console.log(new Child());//Child { name: 'zhangsan' }*/

time 2h28m08s
1听课听明白
2理解代码、源码 ,把顺序理下来
3复写一遍,先照真写,之后看看能不能托手写
考验大家的是一种逻辑能力
并不难,按照一定的顺序

修饰器

time 2h29m33s

修饰器模式

time 2h32m53s
代理是完全拦截,不允许访问(被代理的对象)
修饰器可以访问对象,仅仅是帮助修饰一下,仅仅是修饰作用,给你添加一些新的功能

  1. /*修饰器模式:为对象添加新的功能,而不改变原有的结构和功能*/
  2. class Parent {
  3. constructor(name = 'zhangsan', age = '18') {
  4. this.name = name;
  5. this.age = age;
  6. }
  7. @readonly
  8. say() {
  9. console.log('hello world');
  10. }
  11. static eat() {
  12. console.log('eat')
  13. }
  14. static eat1() {
  15. console.log('eat')
  16. }
  17. }

time 2h38m50s
npm i babel-plugin-transform-decorators-legacy —save-dev

time 2h44m

  1. {
  2. "presets": ["babel-preset-env"],
  3. "plugins": ["transform-decorators-legacy"]
  4. }

本身不支持

time 2h47m33s

  1. /*修饰器模式:为对象添加新的功能,而不改变原有的结构和功能*/
  2. @testable
  3. /*SyntaxError: Invalid or unexpected token
  4. * 不支持这个语法,报错*/
  5. class Parent {
  6. constructor(name = 'zhangsan', age = '18') {
  7. this.name = name;
  8. this.age = age;
  9. }
  10. say() {
  11. console.log('hello world');
  12. }
  13. static eat() {
  14. console.log('eat')
  15. }
  16. static eat1() {
  17. console.log('eat')
  18. }
  19. }
  20. let person=new Person();
  21. console.log(person);
  22. function testable(target) {
  23. console.log(target)
  24. }

run build

time 2h49m47s

  1. 'use strict';
  2. var _createClass = function () {
  3. function defineProperties(target, props) {
  4. for (var i = 0; i < props.length; i++) {
  5. var descriptor = props[i];
  6. descriptor.enumerable = descriptor.enumerable || false;
  7. descriptor.configurable = true;
  8. if ("value" in descriptor) descriptor.writable = true;
  9. Object.defineProperty(target, descriptor.key, descriptor);
  10. }
  11. }
  12. return function (Constructor, protoProps, staticProps) {
  13. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  14. if (staticProps) defineProperties(Constructor, staticProps);
  15. return Constructor;
  16. };
  17. }();
  18. var _class;
  19. function _classCallCheck(instance, Constructor) {
  20. if (!(instance instanceof Constructor)) {
  21. throw new TypeError("Cannot call a class as a function");
  22. }
  23. }
  24. /*SyntaxError: Invalid or unexpected token
  25. * 不支持这个语法,报错*/
  26. var Parent = testable(_class = function () {
  27. function Parent() {
  28. var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'zhangsan';
  29. var age = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '18';
  30. _classCallCheck(this, Parent);
  31. this.name = name;
  32. this.age = age;
  33. }
  34. _createClass(Parent, [{
  35. key: 'say',
  36. value: function say() {
  37. console.log('hello world');
  38. }
  39. }], [{
  40. key: 'eat',
  41. value: function eat() {
  42. console.log('eat');
  43. }
  44. }, {
  45. key: 'eat1',
  46. value: function eat1() {
  47. console.log('eat');
  48. }
  49. }]);
  50. return Parent;
  51. }()) || _class;
  52. var person = new Person();
  53. console.log(person);
  54. function testable(target) {
  55. console.log(target);
  56. }

time 2h50m05s
把bundle在html引入,运行
target就是要修饰的对象本身

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <script src="./bundle.js"></script>
  9. <script !src="">
  10. </script>
  11. </body>
  12. </html>

image.png

time 2h55m06s

  1. class Parent {
  2. constructor(name = 'zhangsan', age = '18') {
  3. this.name = name;
  4. this.age = age;
  5. }
  6. @readonly
  7. say() {
  8. console.log('hello world');
  9. }
  10. eat(){
  11. console.log('eat')
  12. }
  13. }
  14. function readonly(target,name,descriptor) {
  15. console.log(target,name,descriptor)
  16. }

image.png

image.png

time 3h3m45s

  1. class Person {
  2. constructor(name = 'zhangsan', age = '18') {
  3. this.name = name;
  4. this.age = age;
  5. }
  6. @readonly
  7. say() {
  8. console.log('hello world');
  9. }
  10. eat(){
  11. console.log('eat')
  12. }
  13. }
  14. function readonly(target,name,descriptor) {
  15. // console.log(target,name,descriptor)
  16. console.log(descriptor);
  17. descriptor.writable = false;
  18. }
  19. let person=new Person();
  20. person.say=function() {
  21. console.log(1)
  22. }

image.png
修改eat可以修改,只不过say不能修改

这样可以让业务和逻辑分离

应用:埋点

time 3h15m40s

  1. let log = type => {
  2. return function (target, name, descriptor) {
  3. let src_method = descriptor.value;
  4. descriptor.value = (...arg) => {
  5. src_method.apply(target, arg);
  6. console.log(type);
  7. }
  8. }
  9. }
  10. class AD {
  11. @log('show')
  12. show() {
  13. console.log('ad is show');
  14. }
  15. @log('click')
  16. click() {
  17. console.log('ad is click')
  18. }
  19. }
  20. let ad = new AD();
  21. ad.show();
  22. ad.click();

image.png
这种方式不怎么用