[gjs] Class: improve prototype property descriptors
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] Class: improve prototype property descriptors
- Date: Mon, 21 Nov 2011 13:01:14 +0000 (UTC)
commit 9ec2adb40fc87ea58ce5006eb3449eb5a188909a
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sun Nov 20 13:18:34 2011 +0100
Class: improve prototype property descriptors
Use ES5 reflection methods to obtain and manipulate property
descriptors, instead of copying the property values with for-in.
This allows for non-enumerable properties, prevents Object.prototype
properties from being iterated, allows setting .configurable, and
most important allows accessor properties with the usual syntax.
https://bugzilla.gnome.org/show_bug.cgi?id=664437
modules/lang.js | 28 +++++++++++++++++++---------
test/js/testClass.js | 39 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 57 insertions(+), 10 deletions(-)
---
diff --git a/modules/lang.js b/modules/lang.js
index 47bd7f2..695d448 100644
--- a/modules/lang.js
+++ b/modules/lang.js
@@ -1,3 +1,4 @@
+/* -*- mode: js; indent-tabs-mode: nil; -*- */
// Copyright (c) 2008 litl, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -188,21 +189,30 @@ function Class(params) {
let parent = params.Extends;
if (!parent)
parent = _Base;
+ let name = params.Name;
- newClass.__super__ = parent;
- newClass.prototype = Object.create(parent.prototype);
+ let propertyObj = { };
+ let propertyDescriptors = Object.getOwnPropertyNames(params).forEach(function(name) {
+ if (name == 'Name' || name == 'Extends')
+ return;
- for (let prop in params) {
- let value = params[prop];
+ let descriptor = Object.getOwnPropertyDescriptor(params, name);
- if (typeof value === 'function')
- value = wrapFunction(newClass, prop, value);
+ if (typeof descriptor.value === 'function')
+ descriptor.value = wrapFunction(newClass, name, descriptor.value);
- newClass.prototype[prop] = value;
- }
+ // we inherit writable and enumerable from the property
+ // descriptor of params (they're both true if created from an
+ // object literal)
+ descriptor.configurable = false;
+ propertyObj[name] = descriptor;
+ });
+
+ newClass.__super__ = parent;
+ newClass.prototype = Object.create(parent.prototype, propertyObj);
newClass.prototype.constructor = newClass;
- newClass.prototype.__name__ = params.Name;
+ newClass.prototype.__name__ = name;
newClass.prototype.parent = _parent;
return newClass;
diff --git a/test/js/testClass.js b/test/js/testClass.js
index efcea13..c5f5110 100644
--- a/test/js/testClass.js
+++ b/test/js/testClass.js
@@ -1,4 +1,4 @@
-// application/javascript;version=1.8
+// application/javascript;version=1.8 -*- mode: js; indent-tabs-mode: nil -*-
const Lang = imports.lang;
@@ -50,6 +50,24 @@ const ToStringOverride = new Lang.Class({
}
});
+const Accessor = new Lang.Class({
+ Name: 'AccessorMagic',
+
+ _init: function(val) {
+ this._val = val;
+ },
+
+ get value() {
+ return this._val;
+ },
+
+ set value(val) {
+ if (val != 42)
+ throw TypeError('Value is not a magic number');
+ this._val = val;
+ }
+});
+
function testClassFramework() {
let newMagic = new MagicBase('A');
assertEquals('A', newMagic.a);
@@ -89,4 +107,23 @@ function testToString() {
assertEquals('[object ToStringOverride]; hello', override.toString());
}
+function testConfigurable() {
+ let newMagic = new MagicBase();
+
+ delete newMagic.foo;
+ assertNotUndefined(newMagic.foo);
+}
+
+function testAccessor() {
+ let newAccessor = new Accessor(11);
+
+ assertEquals(11, newAccessor.value);
+ assertRaises(function() {
+ newAccessor.value = 12;
+ });
+
+ newAccessor.value = 42;
+ assertEquals(42, newAccessor.value);
+}
+
gjstestRun();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]