You could use the same merge and aggregate in a little more readable way.  Merging the actual df with result of aggregate on left outer join all.x = TRUE will do the job. I hope this is better to understand.
df <- data.frame(id=c(01,02,03,04),category=c("AB","BC","AB","CD"),
                 quantity=c(235,987,366,287))
df <- merge(df,aggregate(quantity ~ category, data=df, sum),"category",all.x = TRUE)
names(df)[4] <- "sum.category"
df
#   category  id     quantity.x   sum.category
#         AB  1        235        601
#         AB  3        366        601
#         BC  2        987        987
#         CD  4        287        287
If you still want a more easy-to-understand way, then sql is the best option. For this you might need sqldf library. We are doing the same aggregate and merge back to the actual df in an sql  way. Its more like a self-join thing. And the sql codes are quite easier to understand
library (sqldf)
dfnew<-sqldf("select a.*,b.sum_quantity
             from df a left join 
             (select category, sum(quantity) sum_category
             from df group by 1) b
             on a.category=b.category")
dfnew
# category id quantity sum_category
#       AB  1      235          601
#       BC  2      987          987
#       AB  3      366          601
#       CD  4      287          287