diff --git a/array_test.go b/array_test.go index 8228485..7985434 100644 --- a/array_test.go +++ b/array_test.go @@ -435,3 +435,13 @@ func TestArray_map(t *testing.T) { test(`[1,2,3].map(function(value) { return value * value })`, "1,4,9") test(`[1,2,3].map(function(value) { return 1 })`, "1,1,1") } + +func TestArray_filter(t *testing.T) { + Terst(t) + + test := runTest() + test(`raise: [].filter("abc")`, "TypeError") + test(`[].filter(function() { return 1 }).length`, "0") + test(`[1,2,3].filter(function() { return false }).length`, "0") + test(`[1,2,3].filter(function() { return true })`, "1,2,3") +} diff --git a/builtin_array.go b/builtin_array.go index deff7c9..b0b3a59 100644 --- a/builtin_array.go +++ b/builtin_array.go @@ -570,7 +570,25 @@ func builtinArray_map(call FunctionCall) Value { values[index] = UndefinedValue() } } - return toValue(call.runtime.newArrayOf(values)) + return toValue_object(call.runtime.newArrayOf(values)) + } + panic(newTypeError()) +} + +func builtinArray_filter(call FunctionCall) Value { + if thisObject, fn := call.thisObject(), call.Argument(0); fn.isCallable() { + length := int64(toUint32(thisObject.get("length"))) + thisValue := call.Argument(1) + values := make([]Value, 0) + for index := int64(0); index < length; index++ { + if key := arrayIndexToString(index); thisObject.hasProperty(key) { + value := thisObject.get(key) + if fn.call(thisValue, value, index, toValue_object(thisObject)).isTrue() { + values = append(values, value) + } + } + } + return toValue_object(call.runtime.newArrayOf(values)) } panic(newTypeError()) } diff --git a/inline b/inline index 2d07f31..bafb5d2 100755 --- a/inline +++ b/inline @@ -238,6 +238,7 @@ sub newContext { "some", 1, "forEach", 1, "map", 1, + "filter", 1, ); return ".${class}Prototype =", diff --git a/inline.go b/inline.go index 951f0b8..6016b0b 100644 --- a/inline.go +++ b/inline.go @@ -1067,6 +1067,25 @@ func _newContext(runtime *_runtime) { call: _nativeCallFunction(builtinArray_map), }, } + filter_function := &_object{ + runtime: runtime, + class: "Function", + objectClass: _classObject, + prototype: runtime.Global.FunctionPrototype, + extensible: true, + property: map[string]_property{ + "length": _property{ + mode: 0, + value: Value{ + _valueType: valueNumber, + value: 1, + }, + }, + }, + value: _functionObject{ + call: _nativeCallFunction(builtinArray_filter), + }, + } isArray_function := &_object{ runtime: runtime, class: "Function", @@ -1227,6 +1246,13 @@ func _newContext(runtime *_runtime) { value: map_function, }, }, + "filter": _property{ + mode: 0101, + value: Value{ + _valueType: valueObject, + value: filter_function, + }, + }, }, } runtime.Global.Array = &_object{