The answers here that suggest the use of indexOf() to check for existence are inefficient O(n^2) runtime. A more efficient approach would be to use a Map and check for existence with has(), bringing the runtime down to O(n):
// see the bottom of the answer for a more efficient implementation than this
Object.defineProperty(Array.prototype, 'subtract', {
  configurable: true,
  value: function subtract (array) {
    return this.filter(
      function (element) {
        const count = this.get(element)
        if (count > 0) {
          this.set(element, count - 1)
        }
        return count === 0
      }, array.reduce(
        (map, element) => {
          if (map.has(element)) {
            map.set(element, map.get(element) + 1)
          } else {
            map.set(element, 1)
          }
          return map
        }, new Map()
      )
    )
  },
  writable: true
})
let a = [1, 2, 2, 3, 3, 3]
let b = [1, 2, 3]
console.log(a.subtract(b))
 
 
Here's a testbench to show the efficiency of this solution compared to @Nina's answer:
Array.prototype.ninaSubtract = function (array) {
    var hash = Object.create(null);
    array.forEach(function (a) {
        hash[a] = (hash[a] || 0) + 1;
    });
    return this.filter(function (a) {
       return !hash[a] || (hash[a]--, false);
    });
}
Object.defineProperty(Array.prototype, 'patrickSubtract', {
  configurable: true,
  value: function subtract (array) {
    return this.filter(
      function (element) {
        const count = this.get(element)
        if (count > 0) {
          this.set(element, count - 1)
        }
        return count === 0
      }, array.reduce(
        (map, element) => {
          if (map.has(element)) {
            map.set(element, map.get(element) + 1)
          } else {
            map.set(element, 1)
          }
          return map
        }, new Map()
      )
    )
  },
  writable: true
})
let a = [1, 2, 2, 3, 3, 3]
let b = [1, 2, 3]
let ninaStart = 0
let ninaStop = 0
let patrickStart = 0
let patrickStop = 0
ninaStart = performance.now()
for (let i = 100000; i > 0; i--) {
  a.ninaSubtract(b)
}
ninaStop = performance.now()
patrickStart = performance.now()
for (let i = 100000; i > 0; i--) {
  a.patrickSubtract(b)
}
patrickStop = performance.now()
console.log('Nina time: ', ninaStop - ninaStart, 'ms')
console.log('Patrick time: ', patrickStop - patrickStart, 'ms')
 
 
Running it several times on my laptop using Chrome v60 indicates that Nina's updated answer using a plain object is approximately 13% faster than my answer.
Let's try to beat that by improving upon her answer:
Array.prototype.ninaSubtract = function (array) {
    var hash = Object.create(null);
    array.forEach(function (a) {
        hash[a] = (hash[a] || 0) + 1;
    });
    return this.filter(function (a) {
       return !hash[a] || (hash[a]--, false);
    });
}
Object.defineProperty(Array.prototype, 'patrickSubtract', {
  configurable: true,
  value: function subtract (array) {
    const lookup = Object.create(null)
    const output = []
    for (let index = 0; index < array.length; index++) {
      const element = array[index]
      lookup[element] = element in lookup ? lookup[element] + 1 : 1
    }
    for (let index = 0; index < this.length; index++) {
      const element = this[index]
      if (!(element in lookup) || lookup[element]-- <= 0) {
        output.push(element)
      }
    }
    return output
  },
  writable: true
})
let a = [1, 2, 2, 3, 3, 3]
let b = [1, 2, 3]
let ninaStart = 0
let ninaStop = 0
let patrickStart = 0
let patrickStop = 0
ninaStart = performance.now()
for (let i = 100000; i > 0; i--) {
  a.ninaSubtract(b)
}
ninaStop = performance.now()
patrickStart = performance.now()
for (let i = 100000; i > 0; i--) {
  a.patrickSubtract(b)
}
patrickStop = performance.now()
console.log('Nina time: ', ninaStop - ninaStart, 'ms')
console.log('Patrick time: ', patrickStop - patrickStart, 'ms')
 
 
That is a lot more performant, though a bit less canonical since it avoids the use of reduce(), forEach() or filter() in order to reduce context switches from function calls. This solution executes in almost half the time of Nina's updated answer (about 43% faster):
Object.defineProperty(Array.prototype, 'subtract', {
  configurable: true,
  value: function subtract (array) {
    const lookup = Object.create(null)
    const output = []
    for (let index = 0; index < array.length; index++) {
      const element = array[index]
      lookup[element] = element in lookup ? lookup[element] + 1 : 1
    }
    for (let index = 0; index < this.length; index++) {
      const element = this[index]
      if (!(element in lookup) || lookup[element]-- <= 0) {
        output.push(element)
      }
    }
    return output
  },
  writable: true
})
let a = [1, 2, 2, 3, 3, 3]
let b = [1, 2, 3]
console.log(a.subtract(b))
 
 
Update
The reason for the discrepancy in performance before was because my previous algorithm using Set was not correct. If b were to contain non-unique elements, then the output would not have been correct.