Skip to main content

Ivan Teoh

Something personal yet public

Javascript: 101 Week 3 Track 1

On track 1 week 3, we are continuing understanding JavaScript through Douglas Crockford's video 3 and video 4.

Reflection

  1. In Javascript, functions are first class objects. What does it mean to be a first class object? From Wikipedia - First-class_object, first class object is an entity that can be passed as a parameter, returned from a subroutine, or assigned into a variable.
  2. Functions and variables share the same namespace. What does this mean and what important implication does this have? We can have same name for both function and variable. They are the same in JavaScript.
  3. Douglas Crockford equates JavaScript functions with Lambdas, and also mentions that they are a secure construct. Can you do some research and reflect on what he means by 'secure construct'? From the presentation, he said it can constraint the scope.
  4. Can you explain the concept of a closure. Closures got very clear explanation on closure. A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).
  5. What is the difference between a function and a method? A function in an object is called a method.
  6. In Javascript there is no implicit type checking of arguments passed to functions. This could lead to bugs if programmers are not careful about what they pass to functions. If you create a function, how would you protect it from well meaning but careless programmers? One way, we can use function's arguments property to verify on each arguments. When a function is invoked, in addition to its parameters, it also gets a special parameter called arguments. It contains all of the arguments from the invocation. It is an array-like object. We can use arguments.length to verify the total of arguments are passed.
  7. JavaScript functions have implicit access to something called this. this points to different things depending on how the function was created. Can you explain why we need this, and what it represents in different type of functions. From the presentation, this is an extra parameter. Its value depends on the calling form. It also gives methods access to their objects and it is bound at invocation time. If the invocation form is function, functionObject(arguments), then this is the global object. If the invocation form is method, thisObject.methodName(arguments), then this is the object. Finally, if the invocation form is constructor, new functionObject(arguments), this is the new object.
  8. Why doesn't JavaScript have a cast operator? The cast operator converts one type into another. In C, its general form is (type) variable. Because it uses other way, for example using parseInt() function to convert string type to integer type.
  9. What is reflection and why is it easy in JavaScript (you may need to do research to answer this question)? Reflection is the process by which a computer program can observe and modify its own structure and behavior at runtime. Every object is a separate namespace. Use an object to organize your variables and functions.

Homework

Week 3 homework for track 1 are the same as track 2. Here will be exercises 6.1 to 6.5. Track 2 will be showing the answers that is recommended by JSLint.

  • Ex. 6.1: Write a function countZeroes, which takes an array of numbers as its argument and returns the amount of zeroes that occur in it. Use reduce. Then, write the higher-order function count, which takes an array and a test function as arguments, and returns the amount of elements in the array for which the test function returned true. Re-implement countZeroes using this function.

    170-exercise61a.js (Source)

    function forEach(array, action) {
      for (var i = 0; i < array.length; i++)
        action(array[i]);
    }
    
    function reduce(combine, base, array) {
      forEach(array, function (element) {
        base = combine(base, element);
      });
      return base;
    }
    
    function zeroes(a, b) {
        if (b) {
            return a;
        }
        return a + 1;
    }
    
    function countZeroes(numbers) {
        return reduce(zeroes, 0, numbers);
    }
    
    document.write(countZeroes([1, 3, 0, 6, 0, 0, 0])); // 4
    

    Using count.

    170-exercise61b.js (Source)

    function forEach(array, action) {
      for (var i = 0; i < array.length; i++)
        action(array[i]);
    }
    
    function count(array, test) {
        total = 0;
        forEach(array, function (element) {
            if (test(element)) {
                total += 1;
            }
        });
        return total;
    }
    
    function zeroes(a) {
        return !a;
    }
    
    function countZeroes(numbers) {
        return count(numbers, zeroes);
    }
    
    document.write(countZeroes([1, 3, 0, 6, 0, 0, 8, 2])); // 3
    
  • Ex. 6.2: Write a function processParagraph that, when given a paragraph string as its argument, checks whether this paragraph is a header. If it is, it strips of the '%' characters and counts their number. Then, it returns an object with two properties, content, which contains the text inside the paragraph, and type, which contains the tag that this paragraph must be wrapped in, "p" for regular paragraphs, "h1" for headers with one '%', and "hX" for headers with X '%' characters. Remember that strings have a charAt method that can be used to look at a specific character inside them.

    170-exercise62.js (Source)

    function processParagraph(paragraph) {
        // check whether this paragraph is header
        var typeString = 'p';
        var header = 0;
        for (var i = 0; i < paragraph.length; i++) {
            if (paragraph.charAt(i) == '%') {
                header += 1;
            } else {
                break;
            }
        }
    
        if (header) {
            typeString = 'h' + header;
            content = paragraph.substr(header + 1);
        } else {
            content = paragraph.substr(header);
        }
    
    
    
        return {'content': content, 'type': typeString};
    }
    // {'content': 'Language', 'type': 'h2'}
    console.log(processParagraph("%% Language"));
    // {'content': 'A hermit spent ten years writing a program.', 'type': 'p'}
    console.log(processParagraph("A hermit spent ten years writing a program."));
    // {'content': 'The Book of Programming', 'type': 'h1'}
    console.log(processParagraph("% The Book of Programming"));
    
  • Ex. 6.3: Build a function splitParagraph which, given a paragraph string, returns an array of paragraph fragments. Think of a good way to represent the fragments. The method indexOf, which searches for a character or sub-string in a string and returns its position, or -1 if not found, will probably be useful in some way here. This is a tricky algorithm, and there are many not-quite-correct or way-too-long ways to describe it. If you run into problems, just think about it for a minute. Try to write inner functions that perform the smaller actions that make up the algorithm.

    170-exercise63.js (Source)

    function splitParagraph(paragraph) {
        var paragraphs = [];
    
        function spliting(first, last, typeString) {
            while (true)  {
                start = paragraph.indexOf(first, 0);
                if (start == -1) {
                    break;
                }
                end = paragraph.indexOf(last, start + 1);
                if (end == -1) {
                    break;
                }
                // content does not have "*"
                content = paragraph.slice(start, end + 1).slice(1, -1);
                paragraph = paragraph.slice(0,
                                paragraph.charAt(start) == " "? start - 1 :start)
                                .concat(paragraph.slice(end + 1));
                paragraphs.push({'content': content, 'type': typeString});
            }
        }
    
        // emphasised part
        spliting("*", "*", "emphasised");
    
        // footnote
        spliting("{", "}", "footnote");
    
        // normal text
        paragraphs.push({'content': paragraph, 'type': 'normal'});
        return paragraphs;
    }
    
    // [{'content': 'million', 'type': 'emphasised'},
    //  {'content': 'mine is almost a lines', 'type': 'normal'}]
    console.log(splitParagraph("mine is almost a *million* lines"));
    // [{'content': 'Type something!', 'type': 'emphasised'},
    //  {'content': "and shouted '' The student", 'type': 'normal'}]
    console.log(splitParagraph("and shouted '*Type something!*' The student"));
    // [{'content': 'square', 'type': 'emphasised'},
    //  {'content': 'result', 'type': 'emphasised'},
    //  {'content': 'two and then it again, the is already inaccurate!',
    //   'type': 'normal'}]
    console.log(splitParagraph("two and then *square* it again, the *result* is " +
    "already inaccurate!"));
    // [{'content': 'million', 'type': 'footnote'},
    //  {'content': 'mine is almost a lines', 'type': 'normal'}]
    console.log(splitParagraph("mine is almost a {million} lines"));
    // [{'content': 'square', 'type': 'emphasised'},
    //  {'content': 'result', 'type': 'footnote'},
    //  {'content': 'two and then it again, the is already inaccurate!',
    //   'type': 'normal'}]
    console.log(splitParagraph("two and then *square* it again, the {result} is " +
    "already inaccurate!"));
    
  • Ex. 6.4: Looking back at the example HTML document if necessary, write an image function which, when given the location of an image file, will create an img HTML element.

    170-exercise64.js (Source)

    function tag(name, content, attributes) {
      return {name: name, attributes: attributes, content: content};
    }
    
    function image(path) {
      return tag("img", [], {src: path});
    }
    
  • Ex. 6.5: Write a function renderFragment, and use that to implement another function renderParagraph, which takes a paragraph object (with the footnotes already filtered out), and produces the correct HTML element (which might be a paragraph or a header, depending on the type property of the paragraph object). This function might come in useful for rendering the footnote references:

    170-exercise65a.js (Source)

    function footnote(number) {
      return tag("sup", [link("#footnote" + number,
                              String(number))]);
    }
    

    A sup tag will show its content as 'superscript', which means it will be smaller and a little higher than other text. The target of the link will be something like "#footnote1". Links that contain a '#' character refer to 'anchors' within a page, and in this case we will use them to make it so that clicking on the footnote link will take the reader to the bottom of the page, where the footnotes live. The tag to render emphasized fragments with is em, and normal text can be rendered without any extra tags.

    170-exercise65b.js (Source)

    function splitParagraph(paragraph) {
        var paragraphs = [];
    
        function spliting(first, last, typeString) {
            while (true)  {
                start = paragraph.indexOf(first, 0);
                if (start == -1) {
                    break;
                }
                end = paragraph.indexOf(last, start + 1);
                if (end == -1) {
                    break;
                }
                // content does not have "*"
                content = paragraph.slice(start, end + 1).slice(1, -1);
                paragraph = paragraph.slice(0,
                                paragraph.charAt(start) == " "? start - 1 :start)
                                .concat(paragraph.slice(end + 1));
                paragraphs.push({'content': content, 'type': typeString});
            }
        }
    
        // emphasised part
        spliting("*", "*", "emphasised");
    
        // footnote
        spliting("{", "}", "footnote");
    
        // normal text
        paragraphs.push({'content': paragraph, 'type': 'normal'});
        return paragraphs;
    }
    
    function forEach(array, action) {
      for (var i = 0; i < array.length; i++)
        action(array[i]);
    }
    
    function map(func, array) {
      var result = [];
      forEach(array, function (element) {
        result.push(func(element));
      });
      return result;
    }
    
    function tag(name, content, attributes) {
      return {name: name, attributes: attributes, content: content};
    }
    
    function link(target, text) {
      return tag("a", [text], {href: target});
    }
    
    function footnote(number) {
      return tag("sup", [link("#footnote" + number,
                              String(number))]);
    }
    
    function renderFragment(fragment) {
        var content;
        switch (fragment.type) {
            case "emphasised":
                content = tag("em", [fragment.content]);
                break;
            case "footnote":
                content = footnote(fragment.content);
                break;
            //case "normal":
            default:
                content = fragment.content;
                break;
        }
        return content;
    }
    
    // {'content': 'A hermit spent ten years writing a program.', 'type': 'p'}
    // {'content': 'two and then *square* it again, the {result} is already
    // inaccurate!', 'type': 'p'}
    function renderParagraph(paragraph) {
        // [{'content': 'square', 'type': 'emphasised'},
        //  {'content': 'result', 'type': 'footnote'},
        //  {'content': 'two and then it again, the is already inaccurate!',
        //   'type': 'normal'}]
        fragments = splitParagraph(paragraph.content);
        return tag(paragraph.type, map(renderFragment, fragments));
    }
    
    console.log(renderParagraph({'content': 'two and then *square* it again, the ' +
    '{result} is already inaccurate!', 'type': 'p'}));
    

Comments

Comments powered by Disqus