试图了解ES6中的Object.assign行为

试图了解ES6中的Object.assign行为

问题描述:

我试图理解这种行为,我正在观察ES6类。考虑下面的代码。这很简单:我有一个父类(Parent)和一个子类(Child)从它继承。 Parent类有一个名为getLabel的方法,它简单地返回该类的标签属性。试图了解ES6中的Object.assign行为

当我创建子类的实例时,设置它的标签并尝试打印它的所有作品。

但是,当我在第一个实例上使用Object.assign创建子类的另一个实例时,即使我明确更改它,新实例也会保留第一个实例的标签值。

class Parent { 
    constructor(label) { 
    this.getLabel =() => { 
     return this.label; 
    }; 
    this.label = label; 
    } 
} 

class Child extends Parent { 
    constructor(label) { 
    super(label); 
    this.label = label; 
    } 
} 

const c = new Child('Child'); 
console.log('c getLabel() = ' + c.getLabel());//Prints "Child" 
const c1 = Object.assign(new Child('C1'), c); 
c1.label = 'Child Modified'; 
console.log('c1 getLabel() = ' + c1.getLabel());//Prints "Child" again instead of "Child Modified". 

我不知道为什么会这样!

我做了什么,然后改变我定义getLabel方法的方式Parent类:

class Parent2 { 
    constructor(label) { 
    this.label = label; 
    } 

    getLabel() { 
    return this.label; 
    } 
} 

class Child2 extends Parent2 { 
    constructor(label) { 
    super(label); 
    this.label = label; 
    } 
} 

const c2 = new Child2('Child 2'); 
console.log('c2 getLabel() = ' + c2.getLabel());//Prints "Child 2" as expected. 
const c3 = Object.assign(new Child2('C3'), c2); 
c3.label = 'Child 2 Modified'; 
console.log('c3 getLabel() = ' + c3.getLabel());//Prints "Child 2 Modified" as expected. 

我将不胜感激,如果有人可以解释这两种不同的行为。

下面是上述代码的ES6小提琴:http://www.es6fiddle.net/is6ex359/

+1

箭头函数使用词法'this'。你的对象有一个名为'getLabel'的属性,当你调用Object.assign时,该属性被复制到你的新子中,该属性包含一个函数,该函数对原始Parent有一个词汇'this'引用。如果您使用普通函数而不是箭头函数,则不会看到该行为。 – Paulpro

+1

顺便说一句,'super(label)'已经指定'this.label',所以你不需要'this.label = label'。 – Oriol

+0

@Oriol ...谢谢!这只是我想为这个问题提出一个例子。 –

这是因为getLabel是在每个实例中定义的,所以它不在原型中共享。由于您使用箭头函数定义它,因此它不会为this定义本地绑定,this值将是constructor之一。

然后,当你使用Object.assignc1接收的c的方法,和this值将是c,即使你把它的c1。所以你得到c.label,这仍然是'Child'

所以你应该避免使用箭头函数。我建议定义在原型方法:

class Parent { 
 
    constructor(label) { 
 
    this.label = label; 
 
    } 
 
    getLabel() { 
 
    return this.label; 
 
    } 
 
} 
 
class Child extends Parent { 
 
    constructor(label) { 
 
    super(label); 
 
    this.label = label; 
 
    } 
 
} 
 
const c = new Child('Child'); 
 
console.log('c getLabel() = ' + c.getLabel()); // "Child" 
 
const c1 = Object.assign(new Child('C1'), c); 
 
c1.label = 'Child Modified'; 
 
console.log('c1 getLabel() = ' + c1.getLabel()); // "Child Modified"

(注Object.assign不分配getLabel因为它的继承,但c1.getLabel ==== c.getLabel反正)

或者在构造函数中,但使用功能表达:

class Parent { 
 
    constructor(label) { 
 
    this.getLabel = function() { 
 
     return this.label; 
 
    }; 
 
    this.label = label; 
 
    } 
 
} 
 
class Child extends Parent { 
 
    constructor(label) { 
 
    super(label); 
 
    this.label = label; 
 
    } 
 
} 
 
const c = new Child('Child'); 
 
console.log('c getLabel() = ' + c.getLabel()); // "Child" 
 
const c1 = Object.assign(new Child('C1'), c); 
 
c1.label = 'Child Modified'; 
 
console.log('c1 getLabel() = ' + c1.getLabel()); // "Child Modified"

+3

这是我今天看到的第二个问题,其中问题是由于使用箭头函数引起的。我想人们正在爱上它简单的语法,而没有意识到它在行为上有着显着的差异。 – Barmar

+0

这对回调函数很好,但不适用于对象方法。 – Barmar

+1

@Barmar:这就是为什么我创建了http://stackoverflow.com/q/34361379/218196,但它仍然是特定的(例如,它本身不适合这个用例)。就我个人而言,我希望能够关闭所有将箭头函数视为单个问题的重复的问题,但这可能只是一厢情愿的想法。 –