I am reading "Object-Oriented JavaScript" by Stoyan Stefanov to learn JavaScript and in the end of the chapter named "Objects", there's an exercise that asks you to implement your own String
object. I have implemented some methods of String
(not all), I'd be happy if you could check and let me know how it could be done better:
function MyString(primitive) {
this.length = 0;
var i = 0;
// Here length is calculated and the indexer is set.
for (var c in primitive) {
this[i++] = primitive[c];
this.length++;
}
this.toString = function() { return primitive; };
this.valueOf = this.toString;
this.substring = function(start, end) {
var result = '';
// Edge cases for the parameters.
if ((typeof end !== 'number' && typeof parseInt(end) !== 'number') || end > this.length)
end = this.length;
if (end <= 0 || isNaN(end)) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
result += this[i];
}
return result;
}
this.charAt = function(i) {
var x = parseInt(i);
x = isNaN(x) ? 0 : x;
return this.substring(x, x+1);
};
return this;
}
var s = new MyString('hello');
console.log(s.length);
console.log(s[0]);
console.log(s.toString());
console.log(s.valueOf());
console.log(s.charAt(1));
console.log(s.charAt('2'));
console.log(s.charAt('e'));
console.log(s.substring(1, 3));
Any and all suggestions are welcome. I'm completely new to JavaScript and would love to hear my mistakes.
-
\$\begingroup\$ You'll want to use prototypes. \$\endgroup\$Shmiddty– Shmiddty2013年07月02日 22:03:46 +00:00Commented Jul 2, 2013 at 22:03
-
\$\begingroup\$ The length property should be read-only. \$\endgroup\$Shmiddty– Shmiddty2013年07月02日 22:08:05 +00:00Commented Jul 2, 2013 at 22:08
-
\$\begingroup\$ I know it should be read-only but I have no idea at the moment how to make it so. And the prototypes chapter is the next one (I'm reading it now). Could you add an answer with your suggested improvements? \$\endgroup\$hattenn– hattenn2013年07月02日 22:10:29 +00:00Commented Jul 2, 2013 at 22:10
1 Answer 1
Some information up front:
Object.defineProperty
is an Ecmascript 5 feature, and is not available in older browsers (IE < 9).There is likely a cleaner way of doing all of this.
This is a basic skeleton:
function MyString(primitive) {
var length = 0, a; // private internal variable to track length, and our iterator
// the loop below basically ensures that this string object is immutable.
for(a in primitive){
(function(char){
Object.defineProperty(this, length++, {
get:function(){return char;}
});
}).call(this,primitive[a]);
}
// we can "get" the length, but we can't "set" it.
Object.defineProperty(this, "length", {
get:function(){return length;}
});
return this;
}
// defining methods on the prototype of an object allows us to share the same instance
// of the method without recreating it for each instance of the object.
// (reduced memory footprint)
MyString.prototype.toString = function(){
return [].join.call(this, '');
// since our object is "array-like", we can use array methods on it.
}
MyString.prototype.charAt = function(index){
return this[index];
}
-
\$\begingroup\$ Note: Be aware of the problem when using
this[index]
, not supported in IE < 8, see string.charAt(x) or string[x]? \$\endgroup\$Xotic750– Xotic7502013年07月04日 13:22:26 +00:00Commented Jul 4, 2013 at 13:22 -
\$\begingroup\$ @Xotic750 This is true but in this case it should work since he is not accessing the string but the MyString object which has an internal 0: 'a' etc representations \$\endgroup\$Haagenti– Haagenti2015年01月06日 08:16:37 +00:00Commented Jan 6, 2015 at 8:16