• Item 23: Never Modify the arguments Object


    Item 23: Never Modify the arguments Object
    The arguments object may look like an array, but sadly it does not
    always behave like one. Programmers familiar with Perl and UNIX
    shell scripting are accustomed to the technique of “shifting” elements
    off of the beginning of an array of arguments. And JavaScript’s arrays
    do in fact contain a shift method, which removes the first element of
    an array and shifts all the subsequent elements over by one. But the

    arguments object itself is not an instance of the standard Array type,
    so we cannot directly call arguments.shift() .
    Thanks to the call method, you might expect to be able to extract the
    shift method from an array and call it on the arguments object. This
    might seem like a reasonable way to implement a function such as
    callMethod , which takes an object and a method name and attempts
    to call the object’s method on all the remaining arguments:
    function callMethod(obj, method) {
    var shift = [].shift;
    shift.call(arguments);
    shift.call(arguments);
    return obj[method].apply(obj, arguments);
    }
    But this function does not behave even remotely as expected:
    var obj = {
    add: function(x, y) { return x + y; }
    };
    callMethod(obj, "add", 17, 25);
    // error: cannot read property "apply" of undefined
    The reason why this fails is that the arguments object is not a copy
    of the function’s arguments. In particular, all named arguments are
    aliases to their corresponding indices in the arguments object. So obj
    continues to be an alias for arguments[0] and method for arguments[1] ,
    even after we remove elements from the arguments object via shift .
    This means that while we appear to be extracting obj["add"] , we are
    actually extracting 17[25] ! At this point, everything begins to go hay-
    wire: Thanks to the automatic coercion rules of JavaScript, this pro-
    motes 17 to a Number object, extracts its "25" property (which does
    not exist), produces undefined , and then unsuccessfully attempts to
    extract the "apply" property of undefined to call it as a method.
    The moral of this story is that the relationship between the arguments
    object and the named parameters of a function is extremely brittle.
    Modifying arguments runs the risk of turning the named parameters
    of a function into gibberish. The situation is complicated even further
    by ES5’s strict mode. Function parameters in strict mode do not alias
    their arguments object. We can demonstrate the difference by writing
    a function that updates an element of arguments :
    function strict(x) {
    "use strict";
    arguments[0] = "modified";

    return x === arguments[0];
    }
    function nonstrict(x) {
    arguments[0] = "modified";
    return x === arguments[0];
    }
    strict("unmodified"); // false
    nonstrict("unmodified"); // true
    As a consequence, it is much safer never to modify the arguments
    object. This is easy enough to avoid by first copying its elements to a
    real array. A simple idiom for implementing the copy is:
    var args = [].slice.call(arguments);
    The slice method of arrays makes a copy of an array when called
    without additional arguments, and its result is a true instance of the
    standard Array type. The result is guaranteed not to alias anything,
    and has all the normal Array methods available to it directly.
    We can fix the callMethod implementation by copying arguments , and
    since we only need the elements after obj and method , we can pass a
    starting index of 2 to slice :
    function callMethod(obj, method) {
    var args = [].slice.call(arguments, 2);
    return obj[method].apply(obj, args);
    }
    At last, callMethod works as expected:
    var obj = {
    add: function(x, y) { return x + y; }
    };
    callMethod(obj, "add", 17, 25); // 42
    Things to Remember
    ✦ Never modify the arguments object.
    ✦ Copy the arguments object to a real array using [].slice.call(arguments)
    before modifying it.

    来源:Effective Javascript

    progress every day !
  • 相关阅读:
    linux
    网络编址
    抽象类 接口
    mysql
    java
    [lyu]Mysql解压版安装教程
    Mysql出现拒绝本地账户访问的情况副本
    js
    Redis限流和GeoHash
    布隆过滤器
  • 原文地址:https://www.cnblogs.com/hghrpg/p/4604166.html
Copyright © 2020-2023  润新知