Coder Social home page Coder Social logo

ES6 Class Methods 定义方式的差异 about blog HOT 15 OPEN

dwqs avatar dwqs commented on June 11, 2024 20
ES6 Class Methods 定义方式的差异

from blog.

Comments (15)

ChaosGT avatar ChaosGT commented on June 11, 2024 2

@beiatisi 这跟作用域完全没关系。
@cdswyda 我觉得你的回答完全不对。箭头函数本身根本就没有this,需要在上下文中查找,表现出来就是对this透明;而普通函数是有this的,默认为undefined,通过对象点号调用时赋值this为点号前的对象。可能你连我想要问什么都没看明白。

我仔细想了一下,自己尝试回答一下自己的问题:
之所以字段中的箭头函数能绑定对象的this,应该是和javascript引擎的class语法实现有关。

class Animal extends BaseClass {
    constructor() {
        //构造函数的执行过程大概如下:
        let animal = {};
        animal.__proto__ = Animal.prototype;
        super.constructor.call(animal);
        初始化字段(字段属于animal,而不是Animal.prototype)
        用户自定义初始化语句
        return animal;
    }
}

引擎在初始化字段过程中,对箭头函数,会用animal进行替换,导致绑定this。使用函数重写Animal如下:

function Animal(){
    let animal = {};
    animal.__proto__ = Animal.prototype;
    //如果Animal是继承来的,还需要调用原型链上的构造函数
   //Animal.prototype.__proto__.constructor.call(animal);
    animal.name = 'animal';
    animal.age = 17;
    animal.sayName = ()=>console.log(animal.name);   //因为是字段,可以确定属于animal,因此可以直接绑定
    return animal;
}

Animal.prototype.sayAge = function(){
    console.log(this.age);  // 属于原型链上的方法,不能直接确定到某个对象
}

Animal.prototype.__proto__ = BaseClass.prototype; //继承

let tom = new Animal();
let [sayName, sayAge] = [tom.sayName, tom.sayAge];
sayName();  //输出animal
sayAge();  //出错,this为undefined

from blog.

phyzess avatar phyzess commented on June 11, 2024 2

@ChaosGT 用 babel 把上面你写的这段代码编译到 ES5 看一下就能明白了
省略掉无关编译结果,下面这段是你疑惑的解答应该:

var Animal = function Animal(name, age) {
  var _this = this;

  _classCallCheck(this, Animal);

  _defineProperty(this, "sayName", function () {
    console.log(this.name);
  });

  _defineProperty(this, "sayAge", function () {
    console.log(_this.age);
  });

  this.name = name;
  this.age = age;
};

注意两个_defineProperty 的回调函数内对于 this 的使用方式。一个是直接用了 this,一个用了构造实例的闭包,所以一个 this 会丢失(成为undefined),而另一个不会。
结合「箭头函数不具有自己的 this,它的 this 永远是定义时包裹它的代码块的 this」,就可以理解为什么 ES6 编译到 ES5 是这样的实现。其实还是作用域、执行上下文、闭包的问题。

from blog.

towersxu avatar towersxu commented on June 11, 2024 1
// 方式二
class B {
    print = () => {
    	console.log('print b');
    }
}

有个小细节,上面这种写法ES6里面应该没有吧,应该只是静态属性的提案中的写法,在使用babel时,如果plugins中只有transform-es2015-classes没有transform-class-properties的话,会报错的。

from blog.

ChaosGT avatar ChaosGT commented on June 11, 2024 1
'use strict';

class Animal {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    sayName = function(){console.log(this.name);};

    sayAge = ()=>{console.log(this.age);}
}

let tom = new Animal('tom',19);
let [sayName, sayAge] = [tom.sayName, tom.sayAge];
sayAge();   // 正常输出19
sayName();  // this为undefined

我明白字段函数是属于对象本身而不是原型的,但我不明白为什么箭头函数能绑定this值????
在上面的例子中sayName会丢失this值我可以理解,但为什么sayAage不会丢失???

from blog.

ChaosGT avatar ChaosGT commented on June 11, 2024 1
'use strict';

let tom =  {
    name: 'tom',
    age: 19,
    sayName: function(){console.log(this.name);},
    sayAge: ()=>{console.log(this.age);},
};

let [sayName, sayAge] = [tom.sayName, tom.sayAge];
sayAge();   // this指向外面的空对象{},输出undefined
sayName();  // 抛出错误,this为undefined

那为什么这里面的sayAge就无法绑定对象tom

from blog.

dwqs avatar dwqs commented on June 11, 2024

@towersxu es6 官方提案目前没有 但在实际应用中 这种写法很常见了 所以一般都会配置对应的 babel plugin

方式二是通过箭头函数来定义方法,如果你写过 React 应用,应该接触过这种方式。

from blog.

dwqs avatar dwqs commented on June 11, 2024

提案 已经处于 s3 箭头函数的写法就类似给类定义了 public method fields 是需要配置 transform-class-properties

from blog.

lz-lee avatar lz-lee commented on June 11, 2024

“转换后的 class A 就是一个函数,所以理论上就可以把 A 当作函数调用,但 _classCallCheck 的作用就是禁止将类作为函数调用”。这里应该改成禁止将类当作普通函数调用更合理。毕竟是当作构造函数调用呀。

from blog.

dwqs avatar dwqs commented on June 11, 2024

@lz-lee 已纠正

from blog.

Moonburni avatar Moonburni commented on June 11, 2024

我觉得class不仅仅是个语法糖,应该还是加了一些东西的。

class A extends Array {};
var a = new A;
var B = function () {};
B.prototype = Object.create(Array.prototype);
var b = new B;
var c = new Array;

console.log(Array.isArray(a)) //true;
console.log(Array.isArray(b)) //false;
console.log(Array.isArray(c))  //true;

from blog.

okboy5555 avatar okboy5555 commented on June 11, 2024

厉害

from blog.

beiatisi avatar beiatisi commented on June 11, 2024

箭头函数作用域问题

from blog.

magicds avatar magicds commented on June 11, 2024

@ChaosGT 箭头函数的this是在定义时就决定的,你的代码中 sayAge 处时 this 执行全局,strict 下就是 undefined
你再上面是 class 语法,那里面的定义时, this 为 Animal 的实例。

from blog.

ChaosGT avatar ChaosGT commented on June 11, 2024

@phyzess 感谢你给出的babel结果,这样就很清楚了,说到底还是解释器硬绑定,和语法本身关系不大,虽然很方便,但个人觉得这破坏了语言的统一性。
「箭头函数不具有自己的 this,它的 this 永远是定义时包裹它的代码块的 this」这句话的后半句是不对的,箭头函数只有作为class的field时候,才会绑定当前对象,是解释器的trick,其它时候都是从执行的上下文中获取,而不是定义时的代码块。

from blog.

JSjump avatar JSjump commented on June 11, 2024

@ChaosGT 用 babel 把上面你写的这段代码编译到 ES5 看一下就能明白了
省略掉无关编译结果,下面这段是你疑惑的解答应该:

var Animal = function Animal(name, age) {
  var _this = this;

  _classCallCheck(this, Animal);

  _defineProperty(this, "sayName", function () {
    console.log(this.name);
  });

  _defineProperty(this, "sayAge", function () {
    console.log(_this.age);
  });

  this.name = name;
  this.age = age;
};

注意两个_defineProperty 的回调函数内对于 this 的使用方式。一个是直接用了 this,一个用了构造实例的闭包,所以一个 this 会丢失(成为undefined),而另一个不会。
结合「箭头函数不具有自己的 this,它的 this 永远是定义时包裹它的代码块的 this」,就可以理解为什么 ES6 编译到 ES5 是这样的实现。其实还是作用域、执行上下文、闭包的问题。

同意。

from blog.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.