mirror of
https://github.com/robertkrimen/otto
synced 2025-10-12 20:27:30 +08:00
Add Function.bind
This commit is contained in:
parent
bef32b9223
commit
fef122900f
|
@ -71,3 +71,20 @@ func builtinFunction_call(call FunctionCall) Value {
|
||||||
}
|
}
|
||||||
return thisObject.Call(this, []Value{})
|
return thisObject.Call(this, []Value{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func builtinFunction_bind(call FunctionCall) Value {
|
||||||
|
target := call.This
|
||||||
|
if !target.isCallable() {
|
||||||
|
panic(newTypeError())
|
||||||
|
}
|
||||||
|
targetObject := target._object()
|
||||||
|
|
||||||
|
this := call.Argument(0)
|
||||||
|
argumentList := call.slice(1)
|
||||||
|
if this.IsUndefined() {
|
||||||
|
// FIXME Do this elsewhere?
|
||||||
|
this = toValue(call.runtime.GlobalObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
return toValue(call.runtime.newBoundFunctionObject(targetObject, this, argumentList))
|
||||||
|
}
|
||||||
|
|
|
@ -69,3 +69,25 @@ func TestFunctionDeclarationInFunction(t *testing.T) {
|
||||||
typeof abc();
|
typeof abc();
|
||||||
`, "function")
|
`, "function")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFunction_bind(t *testing.T) {
|
||||||
|
Terst(t)
|
||||||
|
|
||||||
|
test := runTest()
|
||||||
|
test(`
|
||||||
|
abc = function(){
|
||||||
|
return "abc";
|
||||||
|
};
|
||||||
|
def = abc.bind();
|
||||||
|
def();
|
||||||
|
`, "abc")
|
||||||
|
|
||||||
|
test(`
|
||||||
|
abc = function(){
|
||||||
|
return arguments[1];
|
||||||
|
};
|
||||||
|
def = abc.bind(undefined, "abc");
|
||||||
|
ghi = abc.bind(undefined, "abc", "ghi");
|
||||||
|
[ def(), def("def"), ghi("def") ];
|
||||||
|
`, ",def,ghi")
|
||||||
|
}
|
||||||
|
|
|
@ -184,6 +184,7 @@ func newContext() *_runtime {
|
||||||
},
|
},
|
||||||
"apply", 2, builtinFunction_apply,
|
"apply", 2, builtinFunction_apply,
|
||||||
"call", 2, builtinFunction_call,
|
"call", 2, builtinFunction_call,
|
||||||
|
"bind", 1, builtinFunction_bind,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.Global.Array = self.newGlobalFunction(
|
self.Global.Array = self.newGlobalFunction(
|
||||||
|
|
|
@ -27,6 +27,17 @@ func (runtime *_runtime) newNodeFunctionObject(node *_functionNode, scopeEnviron
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (runtime *_runtime) newBoundFunctionObject(target *_object, this Value, argumentList []Value) *_object {
|
||||||
|
self := runtime.newClassObject("Function")
|
||||||
|
self._Function = &_functionObject{
|
||||||
|
Call: newBoundCallFunction(target, this, argumentList),
|
||||||
|
Construct: defaultConstructFunction,
|
||||||
|
}
|
||||||
|
// FIXME
|
||||||
|
self.stash.set("length", toValue(0), _propertyMode(0))
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
func (self *_object) Call(this Value, argumentList ...interface{}) Value {
|
func (self *_object) Call(this Value, argumentList ...interface{}) Value {
|
||||||
if self._Function == nil {
|
if self._Function == nil {
|
||||||
panic(newTypeError("%v is not a function", toValue(self)))
|
panic(newTypeError("%v is not a function", toValue(self)))
|
||||||
|
@ -159,6 +170,31 @@ func (self _nodeCallFunction) Source() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type _boundCallFunction struct {
|
||||||
|
_callFunction_
|
||||||
|
target *_object
|
||||||
|
this Value
|
||||||
|
argumentList []Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBoundCallFunction(target *_object, this Value, argumentList []Value) *_boundCallFunction {
|
||||||
|
self := &_boundCallFunction{
|
||||||
|
target: target,
|
||||||
|
this: this,
|
||||||
|
argumentList: argumentList,
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self _boundCallFunction) Dispatch(_ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, _ bool) Value {
|
||||||
|
argumentList = append(self.argumentList, argumentList...)
|
||||||
|
return runtime.Call(self.target, self.this, argumentList, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self _boundCallFunction) Source() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// FunctionCall{}
|
// FunctionCall{}
|
||||||
|
|
||||||
// FunctionCall is an enscapulation of a JavaScript function call.
|
// FunctionCall is an enscapulation of a JavaScript function call.
|
||||||
|
@ -177,6 +213,13 @@ func (self FunctionCall) Argument(index int) Value {
|
||||||
return valueOfArrayIndex(self.ArgumentList, index)
|
return valueOfArrayIndex(self.ArgumentList, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self FunctionCall) slice(index int) []Value {
|
||||||
|
if index < len(self.ArgumentList) {
|
||||||
|
return self.ArgumentList[index:]
|
||||||
|
}
|
||||||
|
return []Value{}
|
||||||
|
}
|
||||||
|
|
||||||
func (self *FunctionCall) thisObject() *_object {
|
func (self *FunctionCall) thisObject() *_object {
|
||||||
if self._thisObject == nil {
|
if self._thisObject == nil {
|
||||||
this := self.runtime.GetValue(self.This) // FIXME Is this right?
|
this := self.runtime.GetValue(self.This) // FIXME Is this right?
|
||||||
|
|
Loading…
Reference in New Issue
Block a user