Javascript中对象文字的动态键

时间:2011-06-28 01:04:25

标签: javascript object-literal

好的,所以我正在研究Nodes中的一个项目,我遇到了一个关于对象文字中的键的小问题,我有以下设置:

var required = {
    directories : {
        this.applicationPath                    : "Application " + this.application + " does not exists",
        this.applicationPath + "/configs"       : "Application config folder does not exists",
        this.applicationPath + "/controllers"   : "Application controllers folder does not exists",
        this.applicationPath + "/public"        : "Application public folder does not exists",
        this.applicationPath + "/views"         : "Application views folder does not exists"
    },
    files : {
        this.applicationPath + "/init.js"               : "Application init.js file does not exists",
        this.applicationPath + "/controllers/index.js"  : "Application index.js controller file does not exists",
        this.applicationPath + "/configs/application.js": "Application configs/application.js file does not exists",
        this.applicationPath + "/configs/server.js"     : "Application configs/server.js file does not exists"
    }
}

好的,你们很多人都会看这个并认为它看起来没问题,但编译器一直告诉我,我错过了:(冒号),我不是,它似乎是{{1} }或+都影响编译器。

现在我相信(不确定),对象文字在编译时创建,而不是在运行时创建,这意味着.和连接等动态变量不可用:(:(< / p>

在不必重写大块代码的情况下,克服这类障碍的最佳方法是什么。

8 个答案:

答案 0 :(得分:85)

在对象文字中(ECMA-262§11.1.5将其称为“对象初始化程序”),密钥必须是以下之一:

  1. IdentifierName
  2. 串文字
  3. NumericLiteral
  4. 因此,您无法将表达式用作初始化器中的键。您可以使用带方括号表示法的表达式来访问属性。因此,要使用您必须执行的表达式设置属性:

    var required = { directories : {}};
    required.directories[this.applicationPath] = "Application " + this.application + " does not exists";
    required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";
    ...
    

    等等。由于this.applicationPath被重用了很多,最好存储一个引用以帮助提高性能并减少代码量:

    var a = this.applicationPath;
    var required = { directories : {}};
    var rd = required.directories;
    rd[a] = "Application " + this.application + " does not exists";
    rd[a + "/configs"] = "Application config folder does not exists";
    ...
    

    修改

    从ECMAScript ed 6开始,对象初始值设定项可以使用以下方法计算密钥:

    [expression]: value
    

    属性和方法名称也有简写语法。

    请参阅MDN: Object InitializerECMAScript §12.2.6

答案 1 :(得分:78)

ECMAScript2015支持计算属性名称:

<?php

//database connection variables
$hostname = "";
$username = "";
$password = "";
$dbName = "";

//files to capture json
$incomingJson = 'json.txt';

// initialize the string with a blank value
$string = "";

function insertNewRowIntoStatistics($db,
                        $rowName, 
                        $charactersName, 
                        $highscoreFeet, 
                        $charactersFitnessLevel, 
                        $worstJump, 
                        $totalTrainingTime, 
                        $startingDate) {            
 $sqlInsertNewRow = <<<'EOT'
 INSERT INTO Statistics(
 charactersName, 
 highscoreFeet, 
 charactersFitnessLevel, 
 worstJump, 
 totalTrainingTime, 
 startingDate 
 ) VALUES ( ?, ?, ?, ?, ?, ? ) 
 ON DUPLICATE KEY UPDATE    

     highscoreFeet = VALUES(highscoreFeet), 
 charactersFitnessLevel = VALUES(charactersFitnessLevel), 
         worstJump = VALUES(worstJump), 
 totalTrainingTime = VALUES(totalTrainingTime)

EOT;

$stmt1 = $db->prepare($sqlInsertNewRow);
$stmt1->bind_param("siiiis", 
                    $charactersName, 
                    $highscoreFeet, 
                    $charactersFitnessLevel, 
                    $worstJump, 
                    $totalTrainingTime, 
                    $startingDate);
$stmt1->execute();
$stmt1->bind_result($result);
$stmt1->fetch();
$stmt1->close();
if(!$result){
    trigger_error("Error inserting into Statistics, $result", E_USER_ERROR);
}
}


//Create function for deleting rows that have been in queuedRows for more then 5 minutes.
function deleteExpiredRowsInQueuedRows($db) {   
$sqlDeleteQueuedRow = "DELETE FROM queuedRows WHERE timeOfCreation < ?";
$stmt4 = $db->prepare($sqlDeleteQueuedRow);
$stmt4->bind_param($stmt4, 'i', DateAdd(mi, -5, GetDate()));
$stmt4->execute();
$stmt4->bind_result($result);
$stmt4->fetch();
$stmt4->close();

// catch any errors
if(!$result){ 
    trigger_error("Error deleting from queuedRows, $result", E_USER_ERROR);
}
}

//Create function for inserting rows that have been searched for into queued rows.
function insertRowInQueuedRows($db, $charactersName) {    
$sqlInsertRowInQueuedRows = "Insert INTO queuedRows(charactersName, highscoreFeet, charactersFitnessLevel, worstJump, totalTrainingTime, startingDate, timeOfCreation) SELECT (charactersName, highscoreFeet, charactersFitnessLevel, worstJump, totalTrainingTime, startingDate, timeOfCreation) FROM Statistics where charactersName = ?";
$stmt3 = $db->prepare($sqlInsertRowInQueuedRows);
$stmt3->bind_param(1, $charactersName);
$stmt3->execute(); 
$stmt3->bind_result($result);
$stmt3->fetch();
$stmt3->close();

if(!$result){
    trigger_error("Error inserting into queuedRows, $result", E_USER_ERROR);
}
}

function handleLineOfData(  $db,
                        $rowName, 
                        $charactersName, 
                        $highscoreFeet, 
                        $charactersFitnessLevel, 
                        $worstJump, 
                        $totalTrainingTime, 
                        $startingDate ) {
if($startingDate != "1/1/1") {                
    //Insert or update a row in main table, Statistics.
    insertNewRowIntoStatistics($db,
                        $rowName, 
                        $charactersName, 
                        $highscoreFeet, 
                        $charactersFitnessLevel, 
                        $worstJump, 
                        $totalTrainingTime, 
                        $startingDate);             
} else {                
    //Search for the character name instead of adding it/delete expired rows.
    insertRowInQueuedRows($db, $charactersName);
    deleteExpiredRowsInQueuedRows($db);
}                           
}




//Connecting to your database
$mysqli = new mysqli($hostname, $username, $password, $dbName);

//If error occurs connection to database
if (mysqli_connect_error()) { trigger_error("Cannot connect", E_USER_ERROR); exit; }

//var_dump($_SERVER);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

var_dump( $_POST );

//capture incoming data
error_reporting(E_ALL);
ini_set('display_errors', 1);

//$sig = $_POST["sig"];

if( isset($_POST['params']) ) {
    $jsondata = $_POST["params"];

    //Captures sent json to figure out what to send back
    //file_put_contents($incomingJson,$jsondata);

    //converts JSON to an array
    $array = json_decode($jsondata, TRUE);

    //formats the array to view it easier
    $results = print_r($array,true);
    //file_put_contents($fullArray, $results);

    //gets the total number of objects in the array
    $arrlength = count($array['Children']['1']['Properties']); 
    //loop through array node and get row values
    for ($i=0; $i < $arrlength; $i++) {
        // get row value
        $value = $array['Children']['1']['Properties'][$i]['Value']."\n"; 

        // convert delimited string to an array
        $arrayPieces = explode("|", $value);

        $rowName = $arrayPieces[0];  
        $charactersName = $arrayPieces[1];
        $highscoreFeet = $arrayPieces[2];
        $charactersFitnessLevel = $arrayPieces[3];
        $worstJump = $arrayPieces[4];
        $totalTrainingTime = $arrayPieces[5];
        $startingDate = $arrayPieces[6];

        handleLineOfData( $mysqli, $rowName, $charactersName, 
                          $highscoreFeet, $charactersFitnessLevel, 
                          $worstJump, $totalTrainingTime, $startingDate );              
    }
}

// report http success even if data wasn't found
//Tells application of success 
echo '{"Status":"Success"}';
} // end of POST 

// start GET data
if ($_SERVER['REQUEST_METHOD'] === 'GET') {

//var_dump( $_GET );

// initialize the JSON body variable
$jsonBody="";

//get table contents
$query = mysqli_query($mysqli, "SELECT * FROM queuedRows"); 

//construct an array to hold the data pulled down from mySQL
$rows = array();

// loop through the table and drop the data into the array
while($row = mysqli_fetch_assoc($query)) {
    $rows[] = $row;    
}

// get the number of rows in the array for the JSON return
$arrlength = count($rows);

// set while loop index
$i = 0;

//loop through array node and get row values
while ($i < $arrlength ) {

    // tables we are capturing
    $charactersName = $rows[$i]['charactersName'];
    $highscoreFeet =$rows[$i]['highscoreFeet'];
    $charactersFitnessLevel = $rows[$i]['charactersFitnessLevel'];
    $worstJump = $rows[$i]['worstJump'];
    $totalTrainingTime = $rows[$i]['totalTrainingTime'];
    $startingDate = $rows[$i]['startingDate'];

    // table row numbers. index starts at 0, increment it by 1 to get valid row numbers.
    $tableRow = $i+1;

    // construct the JSON return from data
    $jsonString ='{"Name":"'.$tableRow.'","Value":"|'.$charactersName.'|'.$highscoreFeet.'|'.$charactersFitnessLevel.'|'.$worstJump.'|'.$totalTrainingTime.'|'.$startingDate.'|"},';

    // append the JSON return with the new data
    $jsonBody=$jsonBody.$jsonString;

    // increase index and loop again if not at end of array.
    $i++;           
}

// construct the JSON response to send table back to app

// this is the header of the JSON return.
$jsonHeadher='{"Properties":[],"Name":"id946381_headers","Children":[{"Properties":[{"Name":"rowCount","Value":'.$arrlength.'},{"Name":"columnCount","Value":6},{"Name":"0-1-name","Value":"charactersName"},{"Name":"0-1-type","Value":1},{"Name":"0-2-name","Value":"highscoreFeet"},{"Name":"0-2-type","Value":2},{"Name":"0-3-name","Value":"charactersFitnessLevel"},{"Name":"0-3-type","Value":2},{"Name":"0-4-name","Value":"worstJump"},{"Name":"0-4-type","Value":2},{"Name":"0-5-name","Value":"totalTrainingTime"},{"Name":"0-5-type","Value":2},{"Name":"0-6-name","Value":"startingDate"},{"Name":"0-6-type","Value":1}],"Name":"id946381_headers","Children":[]},{"Properties":[';

// this is the footer of the JSON return.
$jsonFooter='],"Name":"id946381","Children":[]}]}';

// removes an extra comma that the loop above leaves behind
$jsonBody=rtrim($jsonBody, ",");

// constructing the full JSON return
$returnedJson=$jsonHeadher.$jsonBody.$jsonFooter;

// write the JSON data so the app can read it.
echo $returnedJson; 

} // end of get


//Close out mysql
$mysqli->close();
?>

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

答案 2 :(得分:39)

设置动态键的唯一方法是使用括号表示法:

required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";

(当然,无论您在何处执行此定义,都必须存在this.applicationPath

但你需要钥匙中的this.applicationPath吗?你如何访问这些价值观?也许您可以从用于访问属性的任何值中删除this.applicationPath


但万一你需要它:

如果您想避免重复大量代码,可以使用数组初始化键:

var dirs = ['configs', 'controllers', ...];
var files = ['init.js', 'controllers/index.js', ...];

var required = { directories: {}, files: {} };
required.directories[this.applicationPath] = "Application " + this.application + " does not exists";

for(var i = dirs.length; i--;) {
    required.directories[this.applicationPath + '/' + dirs[i]] = "Application " + dirs[i] + " folder does not exists";
}

for(var i = files.length; i--;) {
    // same here
}

答案 3 :(得分:5)

受到babel将新ES6语法({[expression]: value})转换为旧Javascript的启发的启发,我了解到您可以使用一个内容来实现:

var obj = (_obj = {}, _obj[expression] = value, _obj);

示例:

var dynamic_key = "hello";
var value = "world";
var obj = (_obj = {}, _obj[dynamic_key] = value, _obj);

console.log(obj);
// Object {hello: "world"}

(在最新的Chrome上测试)

答案 4 :(得分:2)

对于对象文字,Javascript / ECMAScript脚本指定键可以是有效的IdentifierName,字符串文字或数字 credit RobG (甚至是十六进制)。不是表达式,而是required.applicationPath + "/configs"

答案 5 :(得分:2)

如果你有一个深层对象结构(例如Grunt配置),有时可以使用Felix概述的括号表示法返回动态生成的对象键,但在对象结构中内联。这可以通过使用函数在深层对象的上下文中动态返回对象来实现;在这个问题的代码的情况下,像这样:

var required = {
    directories : function() {
        var o = {};
        o[this.applicationPath] = "Application " + this.application + " does not exists";
        o[this.applicationPath + "/configs"] = "Application config folder does not exists";
        o[this.applicationPath + "/controllers"] = "Application controllers folder does not exists";
        o[this.applicationPath + "/public"] = "Application public folder does not exists";
        o[this.applicationPath + "/views"] = "Application views folder does not exists";
        return o;
    }(),
    files : function() {
        var o = {};
        o[this.applicationPath + "/init.js"] = "Application init.js file does not exists";
        o[this.applicationPath + "/controllers/index.js"]  = "Application index.js controller file does not exists";
        o[this.applicationPath + "/configs/application.js"] ="Application configs/application.js file does not exists";
        o[this.applicationPath + "/configs/server.js"]     ="Application configs/server.js file does not exists";
        return o;
    }()
}

This fiddle验证了这种方法。

答案 6 :(得分:2)

一个老问题,答案当时是正确的,但时间会发生变化。如果有人在谷歌搜索中挖掘它,新的JavaScript版本(ES6)允许使用表达式作为对象文字的键,如果它们被方括号括起来: var obj={["a"+Math.PI]:42}

答案 7 :(得分:0)

问题在于使用'this',因为它没有引用任何智能*。 使用applicationPath创建静态文字。

var required={
    "applicationPath":"someWhereOverTheRainboW"
};

然后使用

required.directories={};
required.directories[required.applicationPath + "/configs"]="Application config folder does not exists";
....

动态填充

编辑; 我赶紧用我的第一个想法,它没有用。以上工作现在 - 抱歉!

*关键字'this'非常聪明:)但它经常引用窗口对象或元素,事件已被触发或被调用的'active'对象。因此,造成了很多困惑;)