在javascript中扩展Object与不扩展之间有区别吗?

时间:2017-10-17 08:59:37

标签: javascript ecmascript-6

我发现我可以像这样扩展Object:

class MyObject extends Object {}

与此有什么不同而根本没有延伸,如下:

class MyObject {}

我问这个的原因是因为我有以下mixin:

const MapMixin = (Base = Object) => class extends Base {
  static from(array) {
    return new this(Object.assign(...array.map(([key, value]) => ({[key]: value}))));
  }

  map(...args) {
    return this.constructor.from(this.entries().map(...args));
  }

  entries() {
    return Object.entries(this);
  }
};

这个mixin可以这样使用:

class MyObject extends MapMixin(MyBaseClass) {}

但是如果没有基类,我现在已经指定它然后默认扩展Object

class MyObject extends MapMixin() {}

所以我想知道,如果这实际上和没有任何扩展一样有效。

3 个答案:

答案 0 :(得分:3)

我不知道这里的其他答案是否清楚,但区别在于静态继承。

class关键字之前,JavaScript中的继承一直非常关注实例继承。没有人(我已经看过)关心让一个类/构造函数从超类/构造函数继承静态成员。更不用说实现这一目标的唯一方法是通过非标准的__proto__属性。

因此,当我们今天查看扩展另一个类的类时,我们会考虑继承如何在该类的实例之间起作用。例如,扩展Object或根本不扩展是相同的,因为实例本身将继承Object作为基础。

class A {}
class B extends Object {}

let a = new A()
let b = new B()

// a.__proto__.__proto__ === b.__proto__.__proto__ === Object.prototype 

但可能并不清楚,或者很清楚extends关键字不只是为实例设置继承。它还设置了类构造函数之间的继承。因此,对于上面的B,使用extends也意味着在后台为B调用Object.setPrototypeOf(B, Object)。例如:

class A {} // A constructor inherits nothing (is a basic Function type)
class B extends Object {} // B inherits from Object

// A.setPrototypeOf === undefined
// B.setPrototypeOf === Object.setPrototypeOf

B,延伸Object,继承Object的所有静态方法,而A不延伸任何内容,不会。

区别在于B.prototype(或B.prototype.__proto__) - 继承自哪些实例,以及B.__proto__ - 类构造函数从哪个实例继承。是否Object扩展不会影响prototype或实例继承的内容,但会影响类__proto__或静态继承。

答案 1 :(得分:2)

有一个微妙的区别。

如果您声明类A,B并创建如下的实例:

#data
df <- data.frame(City = c("NY", "AMS", "BER", "PAR", "NY", "AMS", "AMS", "PAE"),
             Time_Diff = c(4, 2, 7, 9, 2, 1, 10, 9),
             Outliers = c(0, 0, 0, 0, 0, 1, 1, 0))

#data summary
summary <- df %>%
  group_by(City) %>%
  summarise(Median = median(Time_Diff),
        IQR = IQR(Time_Diff),
        Outliers = sum(Outliers))    %>%
  arrange(desc(Median), desc(IQR), desc(Outliers))

summary <- as.data.frame(summary)

# Preproces data for figure
order_city <- summary$City

# Create ggplot object
bp <-ggplot(data = df, aes(x = reorder(City, Time_Diff, FUN = median), y= Time_Diff)) # Creates boxplots

# Create boxplot figure
bp + 
  geom_boxplot(outlier.shape = NA) + #exclude outliers to increase visibility of graph
  coord_flip(ylim = c(0, 25)) +
  geom_hline(yintercept = 4) +
  ggtitle("Time Difference") +
  ylab("Time Difference") +
  xlab("City") +
  theme_light() +
  theme(panel.grid.minor = element_blank(),
    panel.border = element_blank(), #remove all border lines
    axis.line.x = element_line(size = 0.5, linetype = "solid", colour = "black"), #add x-axis border line
    axis.line.y = element_line(size = 0.5, linetype = "solid", colour = "black")) + #add y-axis
  scale_x_discrete(limits = rev(order_city)) #this is the function to change the order of the axis

class A {} class B extends Object {} let a = new A() let b = new B() 基类A派生类

因此,B直接从a分配,但A是从b分配的。
所以你可以找到他们的原型:

Object

通过http://2ality.com/2015/02/es6-classes-final.html#the-extends-clause

答案 2 :(得分:1)

正如Shu Ding所说,原型链不同

更明确:

const getNProtos = (n, { __proto__:p }={}, protos=[]) => n && p ? getNProtos(n-1, p, [ ...protos, p ]) : [ ...protos, p ]

[ 
  class extends Object{}, 
  class extends (class {}){}, 
  class {} 
].map(obj => getNProtos(3, obj)
  .forEach(x => x.forEach(y => console.log(y)) || console.log('\n'))
)

ƒ Object() { [native code] }
ƒ () { [native code] }
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
null


class {}
ƒ () { [native code] }
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
null


ƒ () { [native code] }
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
null

原型链几乎相同,派生类在链上面只有一个额外的(对象构造函数)。使用Object扩展看起来类似于使用普通class {}进行扩展,当然除了Object有自己的方法可用。