前言

JS 中函数是高等公民,但是function 和 class 的区别你真的清楚嘛?本文从PolyFill 实现,再到性能分析,再复习哈基础篇的使用;另外深圳前端求坑,有坑的大佬麻烦内推一下。

1. PolyFill

1.利用原生 js 撸一个简单的 class; 2.根据上面的用法知道 class 必须通过 new 调用,不能直接调用;

// 阻止直接()调用,直接在ES6运行Parent(),这是不允许的,ES6中抛出Class constructor Parent cannot be invoked without 'new'错误function _classCallCheck(instance, Constructor) {    if (!(instance instanceof Constructor)) {        throw new TypeError("Cannot call a class as a function");    }}复制代码

3.里面可以定义实例的属性

// _createClass方法,它调用Object.defineProperty方法去给新创建的Parent添加各种属性// defineProperties(Constructor.prototype, protoProps)是给原型添加属性// defineProperties(Constructor, staticProps)是添加静态属性const _createClass = function () {    function defineProperties(target, props) {        for (var i = 0; i 

4.实现继承

function _inherits(subClass, superClass) {  // 判断父类必须是函数    if (typeof superClass !== "function" && superClass !== null) {        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);    }    subClass.prototype = Object.create(superClass && superClass.prototype, {        constructor: {            value: subClass,            enumerable: false,            writable: true,            configurable: true        }    });    //Object.setPrototypeOf(obj, prototype),将一个指定的对象的原型设置为另一个对象或者null    // 等同于 subClass.prototype.__proto__ = superClass.prototype    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;}复制代码

5.完整演示代码请戳:,欢迎star!

2.性能上

2.1 先测试下

1.先用 Google 的开源插件 bench测试下 function 和 class 的性能; 如果不知道 benchMark 是啥的,请戳:

2.测试代码

const bench = require('benchmark')const suite = new bench.Suite()function myFun(i) {   let baz = 42; }class myClass{  constructor() {    this.fol = 42;   }}suite.add('function', () => {  myFun()}).add('class', () => {  myClass()}).on('cycle', (evt) => {  console.log(String(evt.target));}).on('complete', function() {  console.log('Fastest is ' + this.filter('fastest').map('name'));}).run()复制代码

3.测试结果

// node 版本v10.16.0function x 815,978,962 ops/sec ±4.53% (87 runs sampled)class x 812,855,174 ops/sec ±4.49% (88 runs sampled)Fastest is function,class// 可以看出 class 和 function 速度差不多复制代码

4.完整代码请戳:,欢迎star!

2.2 原因

4.function 的 AST 元素Functions

2.class 的 AST元素: ClassBody MethodDefinition ClassDeclaration ClassExpression 元属性

AST 虽然新增了新的 AST 元素,但是内部属性和方法相对于 function 来说增加了很多,所以两个性能基本差不多; 但是 class 定义代码更利于维护;

3 hooks和 class 的性能

3.1 先测试下

1.在 2.1 测试中知道 class 比 function 要快好几倍; 2.假设场景是有一个父组件,包裹一个function子组件和class子组件,class组件在render过后,定义好的function,可以通过this.func进行调用,并且不会重新再创建,function组件会重新执行一遍,并且重新进行创建需要的function,那是不是 hooks 比 class 更耗性能呢;

const React = require('react')const ReactDOM = require('react-dom/server.node')const bench = require('benchmark')const suite = new bench.Suite()function Func(){  return React.createElement('span', {onClick: () => {console.log('click') }}, 'children')}class Cls extends React.Component{  handleP() {    console.log('click')  }  render(){   return React.createElement('span', {onClick: this.handleP}, 'children')    }}suite.add('function component', () => {  ReactDOM.renderToString(React.createElement(Func))}).add('class component', () => {  ReactDOM.renderToString(React.createElement(Cls))}).on('cycle', (evt) => {  console.log(String(evt.target));}).on('complete', function() {  console.log('Fastest is ' + this.filter('fastest').map('name'));}).run()复制代码

3.结果

// node 版本v10.16.0function component x 110,115 ops/sec ±13.91% (44 runs sampled)class component x 118,909 ops/sec ±12.71% (43 runs sampled)Fastest is class component,function component复制代码

可以看出 function 和 class 性能基本差不多

4.完整代码请戳:,欢迎star!

https://github.com/lanzhsh/react-vue-koa/blob/master/js/class%2Cfunction/2.class-polyfill.js

3.2 原因

React官方回答:4.Hooks避免了类所需的大量开销,例如在构造器中创建类实例和绑定事件处理程序的开销。2.使用Hooks的不需要在使用高阶组件,渲染道具和上下文的代码库中普遍存在的深层组件树嵌套。使用较小的组件树,React要做的工作更少。3.传统上,与React中的内联函数有关的性能问题与如何在每个渲染器上传递新的回调破坏shouldComponentUpdate子组件的优化有关。Hooks从三个方面解决了这个问题。 该useCallback 的 hooks可以让你保持相同的回调引用之间重新呈现,这样shouldComponentUpdate继续工作:

// Will not change unless `a` or `b` changesconst memoizedCallback = useCallback(() => {  doSomething(a, b);}, [a, b]);复制代码

该useMemo钩使得它更容易控制,当个别儿童的更新,减少了对纯组件的需求; useReducerHook减少了深入传递回调的需要

4.用法上

这个是基础篇,只是带大家回顾一下用法;class 是 function 的语法糖;

4.1 定义方法

表达式

const MyClass = class My {  getClasOsName() {    return My.name;  }};复制代码

声明式

const MyClass = class My {  getClassName() {    return My.name;  }};复制代码

4.2 严格模式

内部是默认严格模式

// 引用一个未声明的变量function Bar() {  baz = 42; // it's ok}const bar = new Bar();class Foo {  constructor() {    fol = 42; // ReferenceError: fol is not defined  }}const foo = new Foo();复制代码

4.3 constructor

是 class 的默认方法,默认为空,通过new命令生成对象实例时,自动调用该方法; constructor方法是一个特殊的方法,用来创建并初始化一个对象,并默认返回; 在一个class中只能有一个命名为constructor的特殊方法; constructor中可以通过super关键字,调用父类的constructor方法;

class Rectangle {  // 构造函数  constructor(height, width) {    this.height = height;    this.width = width;  }  get area() {    return this.calcArea();  }  calcArea() {    return this.height * this.width;  }}const square = new Rectangle(10, 10);console.log(square.area); // 100复制代码

4.4 static

static关键字为一个class创建静态方法; static methods的调用无需对class实例化,也不能被实例对象所调用;

class Point {  constructor(x, y) {    this.x = x;    this.y = y;  }      static distance(a, b) {    const dx = a.x - b.x;    const dy = a.y - b.y;    return Math.hypot(dx, dy);  }}const p1 = new Point(5, 5);const p2 = new Point(10, 10);console.log(Point.distance(p1, p2)); // 7.0710678118654755复制代码

当static或prototype method被调用的时候,如果没有对this赋值,那么this将是undefine状态; 这和是否采用static模式无关,因为class类体中的代码已经默认执行static模式;

class Animal {   talk() {    return this;  }  static drink() {    return this;  }}let obj = new Animal();obj.talk(); // Animal {}let talk = obj.talk;talk(); // undefinedAnimal.drink() // class Animallet drink = Animal.drink;drink(); // undefined复制代码

4.5 指向构造函数

class Point {  // ...}typeof Point // "function"Point === Point.prototype.constructor // true复制代码

4.6 必须用 new 调用

function Bar() {  this.bar = 42;}const bar = Bar(); // 正常执行,也可以同 new 调用class Foo {  constructor() {    this.foo = 42;  }}const foo = Foo(); // 报错复制代码

4.7 内部methods 不可枚举

// 引用一个未声明的变量function Bar() {  this.bar = 42;}Bar.answer = function() {  return 42;};Bar.prototype.print = function() {  console.log(this.bar);};const barKeys = Object.keys(Bar); // ['answer']const barProtoKeys = Object.keys(Bar.prototype); // ['print']class Foo {  constructor() {    this.foo = 42;  }  static answer() {    return 42;  }  print() {    console.log(this.foo);  }}const fooKeys = Object.keys(Foo); // []const fooProtoKeys = Object.keys(Foo.prototype); // []复制代码

4.8 属性默认定义在类上

//定义类class Point {  constructor(x, y) {    this.x = x;    this.y = y;  }  toString() {    return '(' + this.x + ', ' + this.y + ')';  }}var point = new Point(2, 3);point.toString() // (2, 3)point.hasOwnProperty('x') // truepoint.hasOwnProperty('y') // truepoint.hasOwnProperty('toString') // falsepoint.__proto__.hasOwnProperty('toString') // true复制代码

因为属性 x,y 是显式定义在 this(实例) 上,而 toString 属性默认定义在类 Point 上.

4.9 getter 和 setter

和function 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为

class MyClass {  constructor() {    // ...  }  get prop() {    return 'getter';  }  set prop(value) {    console.log('setter: '+value);  }}let inst = new MyClass();inst.prop = 123;// setter: 123inst.prop// 'getter'复制代码

4.10 this 指向

默认指向类的实例

class My {  printName(name = 'there') {    this.print(`Hello ${name}`);  }  print(text) {    console.log(text);  }}const my = new My();const { printName } = logger;printName(); //  报错,print未定义复制代码

解决方法一:可以在constructor绑定 this

class My {  constructor() {    this.printName = this.printName.bind(this);  }  // ...}复制代码

解决方法二:使用Proxy,获取方法的时候,自动绑定this

function selfish (target) {  const cache = new WeakMap();  const handler = {    get (target, key) {      const value = Reflect.get(target, key);      if (typeof value !== 'function') {        return value;      }      if (!cache.has(value)) {        cache.set(value, value.bind(target));      }      return cache.get(value);    }  };  const proxy = new Proxy(target, handler);  return proxy;}const logger = selfish(new Logger());复制代码

4.11 super

4.super这个关键字,既可以当作函数使用,也可以当作对象使用; 2.super作为函数调用时,代表父类的构造函数;

class Person {}class Child extends Person {  constructor() {    // 调用父类的构造函数    // 返回子类 Child    // 等同于Person.prototype.constructor.call(this)    super();  }}复制代码

3.作为对象,普通方法指向父类的原型对象;在静态方法中,指向父类

// 普通方法class Person {  p() {    return 2;  }}class Child extends Person{  constructor() {    super();    console.log(super.p()); // 2  }}let child = new Child();// 子类Child当中的super.p(),就是将super当作一个对象使用。这时,super在普通方法之中,指向Person.prototype,所以super.p()就相当于Person.prototype.p()复制代码
// 静态方法class Parent {  static myMethod(msg) {    console.log('static', msg);  }  myMethod(msg) {    console.log('instance', msg);  }}class Child extends Parent {  static myMethod(msg) {    super.myMethod(msg);  }  myMethod(msg) {    super.myMethod(msg);  }}Child.myMethod(1); // static 1var child = new Child();child.myMethod(2); // instance 2复制代码

4.12 extends

父类

class Person{  constructor(name,birthday){    this.name = name;    this.birthday= birthday;  }  intro(){    return `${this.name},${this.birthday}`  }}复制代码

子类

class Child extends Person{  constructor(name,birthday){    super(name,birthday);  }}let child = new Child('xiaoming','2020-1-25');console.log(child.intro()); //zhangsan,1988-04-01复制代码

4.13 不存在变量提升

new Foo(); // ReferenceErrorclass Foo {}复制代码

4.14 怎么实现多继承

4.function 和 class 单次只能继承一个;

// 如 A继承 B和Cclass A extends B{}class A extends C{}复制代码

2.这样写还是比较 low,我们回顾下,Vue 和 React 的 mixin 方法,用来将多个Class的功能复制到一个新的Class上; 我们可以简单来实现一个 mixins,核心是遍历 B,C原型的属性,通过Object.defineProperty设置到 A上;

function mixin(constructor) {  return function (...args) {    for (let arg of args) {      for (let key of Object.getOwnPropertyNames(arg.prototype)) {        if (key === 'constructor') continue // 跳过构造函数        Object.defineProperty(constructor.prototype, key, Object.getOwnPropertyDescriptor(arg.prototype, key))      }    }  }}mixin(A)(B,C)const a = new A()复制代码

5.总结

原创码字不易,你的 star是我持续创作更新的动力,欢迎 star!

github地址: https://github.com/lanzhsh/react-vue-koa/blob/master/js/class%2Cfunction/2.class-polyfill.js

原链接:https://juejin.im/post/5e7aadd16fb9a07cc3216c17

es6 filter方法_ES5和ES6函数你不知道的区别相关推荐

  1. Java 方法与C语言函数微区别

    简介 Java 方法与C语言函数的区别在于函数的调用方式不同 示例 方式一: static法 public class Test {static void function(){System.out. ...

  2. js中数组filter过滤奇偶数_JS filter()方法:根据指定条件过滤数组元素

    JavaScript filter() 方法可以返回数组中满足指定条件的元素.具体用法如下: array.filter(callbackfn[, thisArg]); 参数说明: array:必需参数 ...

  3. jQuery源码分析之实例find和filter方法的区别七问

    问题1:jQuery.filter的源码是什么? jQuery.filter = function( expr, elems, not ) {var elem = elems[ 0 ];//如果含有第 ...

  4. JavaScript 数组filter方法完整介绍

    数组过滤器方法是 JavaScript 中使用最广泛的方法之一. 它允许我们快速过滤出具有特定条件的数组中的元素. 因此,在本文中,您将了解有关过滤器方法及其各种用例的所有内容. 所以让我们开始吧. ...

  5. es5的data语法_ES5与ES6数组方法总结

    Array 对象属性 constructor 返回对创建此对象的数组函数的引用. length 设置或返回数组中元素的数目. prototype 使您有能力向对象添加属性和方法. 传统Array 对象 ...

  6. es6 filter() 数组过滤方法总结

    Array.every(x=>x)是每一个都要满足 Array.some(x=>x)是有一个满足. Array.find(findIndex),返回符合条件的第一个值. Array.fil ...

  7. ES6 必须要用的数组Filter() 方法,不要再自己循环遍历了!!!

    1,来一个最简单最常用的栗子: 获得年龄为9岁的孩子 1 let arr = [2 {3 name:'小明',4 sex:0,5 age:96 },7 { 8 name:'小红', 9 sex:1, ...

  8. indexof方法_[ 翻译 ] ES6中数组去重的三种方法

    原文:How to Remove Array Duplicates in ES6 翻译:Hytonight云息 有三种方法可以过滤掉一个数组的重复元素并且返回去重后的新数组.我最喜欢使用Set,因为它 ...

  9. 数组方法大全ES5+ES6

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1. 使用 Array 构造函数 2. 使用数组字面量表示法 数组原型方法 1. join() 2.push()和pop() ...

最新文章

  1. Shiny平台构建与R包开发(一)——ui布局
  2. PostgreSQL学习手册(七) 事物隔离
  3. (九) shiro采用AES加密和解密
  4. Spring 中设置依赖注入
  5. python argparse 解析命令行参数
  6. 快点来学吧!mysql批量插入数据
  7. HDU 1556【线段树区间更新】
  8. PB 程序发布相关
  9. c++程序调用python代码_使用C++调用Python代码的方法详解
  10. 数据结构与算法课程笔记(七)
  11. 会声会影滤镜特效教程之气泡滤镜
  12. 柱状图怎么设置xy轴_经验-Origin做柱状图常遇问题-柱状图X坐标轴如何设置—小技巧...
  13. unity摄像机环绕物体旋转
  14. Flutter侧边栏控件-SideBar
  15. Cypress(7)测试用例断言
  16. 剑指offer面试题(1-10)——java实现
  17. 如何取消wow3.0后与服务器设置的同步(设置、键位、宏)
  18. 吾生也有涯,吾知也无涯_乌拉(6)
  19. 关羽闯关的c语言编程,腾讯中国象棋残局264关怎么过 三国演义264关关羽降汉攻略...
  20. 大专计算机专业建设计划书,新时期计算机专业建设的策略

热门文章

  1. 笔记本电脑投屏到电视_同是无线投屏器,家用级与商用级的区别,除了盘活老电视还能干嘛...
  2. 使用 SAP Cloud SDK 连接 OData 服务
  3. SAP Commerce Cloud WCMS 里的 home 页面和 SAP Spartacus Page API 返回的数据比较
  4. 在没有任何前端开发经验的基础上, 创建第一个 SAP Fiori Elements 应用
  5. 为加快SAP Commerce Cloud在windows服务器上的启动速度,而禁用的一些服务
  6. 我的工作日常:一个CSS问题引起的小插曲
  7. SAP Spartacus routing参数的权重和HTTP校验逻辑
  8. StorefrontModule和B2CStorefrontModule的区别
  9. try to navigate from button to line item page
  10. UI component html code 查看工具