更多设置对象属性的方法
在之前的绑定中,我们基本上是使用JS_SetPrototypeStr
进行代码绑定。但还有其他的方法。
JS_SetProperty系列
JS_SetPrototype
系列有如下函数:
int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, const char *prop, JSValue val)
this_obj
:要设置到的值prop
:设置的成员名称val
:要设置的值
int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val)
与JS_SetPropertyStr
的区别是第三个参数是JSAtom
。这其实是更底层的函数。JSAtom
就是一个字符串。只是如果你用JS_NewAtom
创建之后你可以复用他,这样QuickJS就不用将字符串字面量在底层到处拷贝(比如使用JS_SetPropertyStr
时)
JS_DefineProperty系列
这个系列函数给了你更加精细的控制:
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags)
int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags)
int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, const char *prop, JSValue val, int flags)
int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue getter, JSValue setter, int flags)
同样的,有带有JSAtom
和直接使用字符串的。但都多出了int flags
这个参数。取值如下:
#define JS_PROP_CONFIGURABLE (1 << 0)
#define JS_PROP_WRITABLE (1 << 1)
#define JS_PROP_ENUMERABLE (1 << 2)
#define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)
#define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */
#define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */
#define JS_PROP_NORMAL (0 << 4)
#define JS_PROP_GETSET (1 << 4)
#define JS_PROP_VARREF (2 << 4) /* used internally */
#define JS_PROP_AUTOINIT (3 << 4) /* used internally */
/* throw an exception if false would be returned
(JS_DefineProperty/JS_SetProperty) */
#define JS_PROP_THROW (1 << 14)
/* throw an exception if false would be returned in strict mode
(JS_SetProperty) */
#define JS_PROP_THROW_STRICT (1 << 15)
JS_PROP_NORMAL
:默认值,无任何属性JS_PROP_ENUMERABLE
:属性可被枚举(可被for...in
遍历到)JS_PROP_WRITABLE
:可写入JS_PROP_CONFIGURABLE
:属性的配置可被修改。如果第一次使用JS_DefinePropertyXXX
未指定这个值,那之后使用JS_DefinePropertyXXX
不允许修改属性的PROP。JS_PROP_C_W_E
:JS_PROP_CONFIGURABLE
,JS_PROP_WRITABLE
,JS_PROP_ENUMERABLE
的组合JS_PROP_GETSET
:标识属性是getter/setter(一般和JS_DefineProperty
配合使用)。注意:- 使用这个枚举的时候还需要配合
JS_PROP_HAS_GET
,JS_PROP_HAS_SET
来告诉QuickJS是否有getter/setter - 传入的getter/setter相关
JSValue
需要被JS_FreeValue
,因为底层调用了js_dup
- 使用这个枚举的时候还需要配合
JS_PROP_THROW
:如果JS_SetPropertyXXX
或JS_DefinePropertyXXX
产生了非法行为,抛出一个异常。JS_PROP_THROW_STRICT
:在严格模式下判断是否非法并抛出异常
JS_SetPropertyFunctionList
可以通过这个函数一次性绑定多个属性:
const JSCFunctionListEntry entries[] = {
// bind member function
JS_CFUNC_DEF("introduce", 0, IntroduceBinding),
// bind getter/settrer
JS_CGETSET_DEF("name", NameGetter, NameSetter),
JS_CGETSET_DEF("bmi", BMIBinding, nullptr),
};
JS_SetPropertyFunctionList(ctx, proto, entries, std::size(entries));
首先构造一个JSCFunctionListEntry
数组,然后使用一些方便的宏就可以进行绑定。
只需要将我们的绑定函数的函数指针传给宏即可,不需要担心函数类型不一致,宏会自动帮你处理(也就不需要JSCFunctionType
)
最后使用JS_SetPropertyFunctionList
即可完成。
缺点:JSCFunctionListEntry[]
是传指针进去的。也就是说你需要保证此数组在JS_Eval
之前是有效的。
删除属性
使用JS_DeleteProperty
函数。
JS_SetProperty和JS_DefineProperty的区别
JS_SetPropertyXXX
相当于JS中的复制。当没有这个属性的时候,赋值时会生成一份属性。但不能给const
属性赋值:
JS_SetPropertyStr(ctx, global_this, "const_global_var2", new_obj); // error!
而JS_DefinePropertyXXX
则是定义属性。他等于是完全重新创建属性。