mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
3e70d31e5d
Bound methods are implemented as assignments to `this` in the constructor. In derived classes, where `this` is unavailable until after `super` has been called, the binding is applied and assigned after the `super` call. This means that any references to 'bound' methods reachable from the parent constructor will actually point to the unbound prototype methods. This can lead to very subtle bugs where a method that is thought to be bound is handed off and later called with an incorrect context, and the only defence is for users to be vigilant about referencing bound methods in constructors.
118 lines
2.4 KiB
CoffeeScript
118 lines
2.4 KiB
CoffeeScript
# Scope
|
|
# -----
|
|
|
|
# * Variable Safety
|
|
# * Variable Shadowing
|
|
# * Auto-closure (`do`)
|
|
# * Global Scope Leaks
|
|
|
|
test "reference `arguments` inside of functions", ->
|
|
sumOfArgs = ->
|
|
sum = (a,b) -> a + b
|
|
sum = 0
|
|
sum += num for num in arguments
|
|
sum
|
|
eq 10, sumOfArgs(0, 1, 2, 3, 4)
|
|
|
|
test "assignment to an Object.prototype-named variable should not leak to outer scope", ->
|
|
# FIXME: fails on IE
|
|
(->
|
|
constructor = 'word'
|
|
)()
|
|
ok constructor isnt 'word'
|
|
|
|
test "siblings of splat parameters shouldn't leak to surrounding scope", ->
|
|
x = 10
|
|
oops = (x, args...) ->
|
|
oops(20, 1, 2, 3)
|
|
eq x, 10
|
|
|
|
test "catch statements should introduce their argument to scope", ->
|
|
try throw ''
|
|
catch e
|
|
do -> e = 5
|
|
eq 5, e
|
|
|
|
test "loop variable should be accessible after for-of loop", ->
|
|
d = (x for x of {1:'a',2:'b'})
|
|
ok x in ['1','2']
|
|
|
|
test "loop variable should be accessible after for-in loop", ->
|
|
d = (x for x in [1,2])
|
|
eq x, 2
|
|
|
|
test "loop variable should be accessible after for-from loop", ->
|
|
d = (x for x from [1,2])
|
|
eq x, 2
|
|
|
|
class Array then slice: fail # needs to be global
|
|
class Object then hasOwnProperty: fail
|
|
test "#1973: redefining Array/Object constructors shouldn't confuse __X helpers", ->
|
|
arr = [1..4]
|
|
arrayEq [3, 4], arr[2..]
|
|
obj = {arr}
|
|
for own k of obj
|
|
eq arr, obj[k]
|
|
|
|
test "#2255: global leak with splatted @-params", ->
|
|
ok not x?
|
|
arrayEq [0], ((@x...) -> @x).call {}, 0
|
|
ok not x?
|
|
|
|
test "#1183: super + fat arrows", ->
|
|
dolater = (cb) -> cb()
|
|
|
|
class A
|
|
constructor: ->
|
|
@_i = 0
|
|
foo : (cb) ->
|
|
dolater =>
|
|
@_i += 1
|
|
cb()
|
|
|
|
class B extends A
|
|
constructor : ->
|
|
super()
|
|
foo : (cb) ->
|
|
dolater =>
|
|
dolater =>
|
|
@_i += 2
|
|
super cb
|
|
|
|
b = new B
|
|
b.foo => eq b._i, 3
|
|
|
|
test "#1183: super + wrap", ->
|
|
class A
|
|
m : -> 10
|
|
|
|
class B extends A
|
|
constructor : -> super()
|
|
m: -> r = try super()
|
|
m: -> r = super()
|
|
|
|
eq (new B).m(), 10
|
|
|
|
test "#1183: super + closures", ->
|
|
class A
|
|
constructor: ->
|
|
@i = 10
|
|
foo : -> @i
|
|
|
|
class B extends A
|
|
foo : ->
|
|
ret = switch 1
|
|
when 0 then 0
|
|
when 1 then super()
|
|
ret
|
|
eq (new B).foo(), 10
|
|
|
|
test "#3259: leak with @-params within destructured parameters", ->
|
|
fn = ({@foo}, [@bar], [{@baz}]) ->
|
|
foo = bar = baz = false
|
|
|
|
fn.call {}, {foo: 'foo'}, ['bar'], [{baz: 'baz'}]
|
|
|
|
eq 'undefined', typeof foo
|
|
eq 'undefined', typeof bar
|
|
eq 'undefined', typeof baz
|