具有单个字符串的数组会自动且意外地转换为字符串
Array with a single String getting automatically and undesireably converted to just a String
在我的 CasperJS 脚本中,当我通过评估函数将一个数组传递给我的函数时,它可能有 1 个或多个字符串。当有多个字符串时,它按预期工作,但当数组只有 1 个字符串时,它的行为非常奇怪。如果我传递一个里面只有一个字符串的数组,它就变成了字符串。我哪里错了?
我的 CasperJS 脚本:
function myFunction(input) {
console.log(JSON.stringify(input));
}
//allow console logs through for debugging
casper.on('remote.message', function(message) {
this.echo(message);
});
//get my page
casper.start(...);
//attempt to call myFunction with an array as input
casper.then(function() {
var input = ['#someId'];
this.evaluate(myFunction, input);
});
期望的输出:
["#someId"]
实际输出:
"#someId"
输出 if var input = ['#firstId', '#secondId']
["#firstId", "#secondId"]
当您使用 JSON.stringify(input)
时,此方法将 JavaScript 值转换为 JSON 字符串,而您发送的是我认为不正确的单个字符串 json格式。
JSON.stringify() 将值转换为表示它的 JSON 表示法:
不保证非数组对象的属性按任何特定顺序进行字符串化。不要依赖字符串化中同一对象内的属性排序。
Boolean、Number 和 String 对象在字符串化过程中被转换为相应的原始值,符合传统的转换语义。
如果在转换过程中遇到未定义、函数或符号,则将其忽略(当在对象中找到时)或截断为 null(当在数组中找到时)。
所有以符号为键的属性都将被完全忽略,即使在使用替换函数时也是如此。
不可枚举的属性将被忽略
请查看 JSON API 及其相关方法,
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
这正是 CasperJS 在恰好有两个参数时添加的内容:函数和函数参数。如果它是根据 this:
的数组或对象,它将尝试 "unpack" 您传递的一个参数
Casper.prototype.evaluate = function evaluate(fn, context) {
...
// function context
if (arguments.length === 1) {
return utils.clone(this.page.evaluate(fn));
} else <strong>if (arguments.length === 2) {
// check for closure signature if it matches context
if (utils.isObject(context) && eval(fn).length === Object.keys(context).length) {
context = utils.objectValues(context);
} else {
context = [context];
}
}</strong> else {
// phantomjs-style signature
context = [].slice.call(arguments, 1);
}
return utils.clone(this.page.evaluate.apply(this.page, [fn].concat(context)));
};
这会导致有趣的行为,如以下完整脚本所示:
var casper = require('casper').create();
casper.on("remote.message", function(msg) {
this.echo("Console: " + msg);
});
casper.start('http://example.com/').then(function(){
var arr = ['#someId'];
var arrm = ['#someId', '#someOtherId'];
var obj = {a:'#someId'};
var objm = {a:'#someId', b:'#someOtherId'};
this.echo("1");
this.evaluate(function(arr) {
console.log(JSON.stringify(arr));
}, arr);
this.echo("2");
this.evaluate(function(arr) {
console.log(JSON.stringify(arr));
}, arrm);
this.echo("3");
this.evaluate(function(obj) {
console.log(JSON.stringify(obj));
}, obj);
this.echo("4");
this.evaluate(function(obj) {
console.log(JSON.stringify(obj));
}, objm);
this.echo("5");
this.evaluate(function(arr, obj) {
console.log(JSON.stringify(arr));
console.log(JSON.stringify(obj));
}, arr, obj);
this.echo("6");
this.evaluate(function(a) {
console.log(JSON.stringify(a));
}, obj);
this.echo("7");
this.evaluate(function(b) {
console.log(JSON.stringify(b));
}, objm);
this.echo("8");
this.evaluate(function(a, b) {
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
}, objm);
this.echo("9");
this.evaluate(function(b, a) {
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
}, objm);
}).run();
输出:
1
Console: "#someId"
2
Console: ["#someId","#someOtherId"]
3
Console: "#someId"
4
Console: {"a":"#someId","b":"#someOtherId"}
5
Console: ["#someId"]
Console: {"a":"#someId"}
6
Console: "#someId"
7
Console: {"a":"#someId","b":"#someOtherId"}
8
Console: "#someId"
Console: "#someOtherId"
9
Console: "#someOtherId"
Console: "#someId"
请注意,如果对象的键匹配(请参阅测试 8 和 9),对象将按名称解压缩到 evaluate()
回调参数。
PhantomJS 本身不进行任何类型的解包。这就是 CasperJS。
在我的 CasperJS 脚本中,当我通过评估函数将一个数组传递给我的函数时,它可能有 1 个或多个字符串。当有多个字符串时,它按预期工作,但当数组只有 1 个字符串时,它的行为非常奇怪。如果我传递一个里面只有一个字符串的数组,它就变成了字符串。我哪里错了?
我的 CasperJS 脚本:
function myFunction(input) {
console.log(JSON.stringify(input));
}
//allow console logs through for debugging
casper.on('remote.message', function(message) {
this.echo(message);
});
//get my page
casper.start(...);
//attempt to call myFunction with an array as input
casper.then(function() {
var input = ['#someId'];
this.evaluate(myFunction, input);
});
期望的输出:
["#someId"]
实际输出:
"#someId"
输出 if var input = ['#firstId', '#secondId']
["#firstId", "#secondId"]
当您使用 JSON.stringify(input)
时,此方法将 JavaScript 值转换为 JSON 字符串,而您发送的是我认为不正确的单个字符串 json格式。
JSON.stringify() 将值转换为表示它的 JSON 表示法:
不保证非数组对象的属性按任何特定顺序进行字符串化。不要依赖字符串化中同一对象内的属性排序。 Boolean、Number 和 String 对象在字符串化过程中被转换为相应的原始值,符合传统的转换语义。 如果在转换过程中遇到未定义、函数或符号,则将其忽略(当在对象中找到时)或截断为 null(当在数组中找到时)。 所有以符号为键的属性都将被完全忽略,即使在使用替换函数时也是如此。 不可枚举的属性将被忽略
请查看 JSON API 及其相关方法,
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
这正是 CasperJS 在恰好有两个参数时添加的内容:函数和函数参数。如果它是根据 this:
的数组或对象,它将尝试 "unpack" 您传递的一个参数Casper.prototype.evaluate = function evaluate(fn, context) {
...
// function context
if (arguments.length === 1) {
return utils.clone(this.page.evaluate(fn));
} else <strong>if (arguments.length === 2) {
// check for closure signature if it matches context
if (utils.isObject(context) && eval(fn).length === Object.keys(context).length) {
context = utils.objectValues(context);
} else {
context = [context];
}
}</strong> else {
// phantomjs-style signature
context = [].slice.call(arguments, 1);
}
return utils.clone(this.page.evaluate.apply(this.page, [fn].concat(context)));
};
这会导致有趣的行为,如以下完整脚本所示:
var casper = require('casper').create();
casper.on("remote.message", function(msg) {
this.echo("Console: " + msg);
});
casper.start('http://example.com/').then(function(){
var arr = ['#someId'];
var arrm = ['#someId', '#someOtherId'];
var obj = {a:'#someId'};
var objm = {a:'#someId', b:'#someOtherId'};
this.echo("1");
this.evaluate(function(arr) {
console.log(JSON.stringify(arr));
}, arr);
this.echo("2");
this.evaluate(function(arr) {
console.log(JSON.stringify(arr));
}, arrm);
this.echo("3");
this.evaluate(function(obj) {
console.log(JSON.stringify(obj));
}, obj);
this.echo("4");
this.evaluate(function(obj) {
console.log(JSON.stringify(obj));
}, objm);
this.echo("5");
this.evaluate(function(arr, obj) {
console.log(JSON.stringify(arr));
console.log(JSON.stringify(obj));
}, arr, obj);
this.echo("6");
this.evaluate(function(a) {
console.log(JSON.stringify(a));
}, obj);
this.echo("7");
this.evaluate(function(b) {
console.log(JSON.stringify(b));
}, objm);
this.echo("8");
this.evaluate(function(a, b) {
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
}, objm);
this.echo("9");
this.evaluate(function(b, a) {
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
}, objm);
}).run();
输出:
1 Console: "#someId" 2 Console: ["#someId","#someOtherId"] 3 Console: "#someId" 4 Console: {"a":"#someId","b":"#someOtherId"} 5 Console: ["#someId"] Console: {"a":"#someId"} 6 Console: "#someId" 7 Console: {"a":"#someId","b":"#someOtherId"} 8 Console: "#someId" Console: "#someOtherId" 9 Console: "#someOtherId" Console: "#someId"
请注意,如果对象的键匹配(请参阅测试 8 和 9),对象将按名称解压缩到 evaluate()
回调参数。
PhantomJS 本身不进行任何类型的解包。这就是 CasperJS。