安全基础 --- JSON + 函数声明

JSON

格式:JSON(JavaScript Object Notation缩写)是一种用于数据交换的文本格式,目的是取代繁琐笨重的 XML 格式。

(1)规定

  1. 复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。

  2. 原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用NaN, Infinity, -Infinityundefined)。

  3. 字符串必须使用双引号表示,不能使用单引号。

  4. 对象的键名必须放在双引号里面。

  5. 数组或对象最后一个成员的后面,不能加逗号。

(2)实例:

  • 合法JSON
["one", "two", "three"]
{ "one": 1, "two": 2, "three": 3 }
{"names": ["张三", "李四"] 
[ { "name": "张三"}, {"name": "李四"} ]
  • 不合法JSON
{ name: "张三", 'age': 32 }  // 属性名必须使用双引号

[32, 64, 128, 0xFFF] // 不能使用十六进制值

{ "name": "张三", "age": undefined } // 不能使用 undefined

{ "name": "张三",
  "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
  "getName": function () {
      return this.name;
  }
} // 属性值不能使用函数和日期对象

(3)JSON对象

JSON对象是 JavaScript 的原生对象,用来处理 JSON 格式数据。它有两个静态方法:JSON.stringify()JSON.parse()

<1> JSON.stringify()

[1] 基本用法

JSON.stringfy()方法将一个值转为JSON字符串,该字符串符合JSON格式,且可被JSON.parse()还原

例:

JSON.stringify('abc')  // ""abc""
JSON.stringify(1) // "1"
JSON.stringify(false) // false
JSON.stringify([])  // "[]"
JSON.stringify({})  // "{}"

JSON.stringify([1,"false",false])
// '[1,"false",false]'

JSON.stringfy({name:"张三"})
// '{name:张三}'

上方将各种类型的值,转为JSON字符串,对于原始类型,转换结果会带双引号
JSON.stringify('foo') === "foo" // false
JSON.stringify('foo') === "\"foo\""  // true
// 上面代码中,如果不是内层的双引号,将来还原的时候,引擎就无法知道原始值是布尔值还是字符串。

JSON.stringify()方法会忽略对象的不可遍历的属性

var obj = {};

Object.defineProperties(obj,{
    'foo':{
    value:1,
    enumerable:true
    },
    'bar':{
    value:2,
    enumerable:false
    }
});

JSON.stringify(obj);  // "{"foo":1}"

// bar是obj对象的不可遍历属性,JSON.stringify方法将会忽略这个属性
[2] 第二个参数

JSON.stringify()方法还可以接受一个数组,作为第二个参数,指定参数对象的哪些属性需要转为字符串

var obj = {
    'prop1':'value1',
    'prop2':'value2',
    'prop3':'value3'
};

var selectedProperties = ['prop1','prop2'];

JSON.stringify(obj,selectedProperties)
// "{"prop1":"value1","prop2":"value2"}"
// JSON.stringify()方法的第二个参数指定,只转prop1和prop2的两个属性

类似白名单的数组,只对对象的属性有效,对数组无效。

JSON.stringfy(['a','b'],[0]);
// "["a","b"]"

JSON.stringify({0:'a',1:'b'},['0']);
// "{"0":"a"}"

第二个参数还可以是函数,用来更改JSON.stringify()的返回值

function f(key,value) {
    if(typeof value === "number") {
        value = 2 * value;
    }
    return value;
}

JSON.stringify({a:1,b:2},f);
// '{"a":2,"b":4}'

// f函数,接受两个参数,分别是被转换的对象的键名和键值。键值为数值的话,将乘2,否则原样返回,

注意:这个处理函数是递归处理所有的键

var obj = {a:{b:1}}

function f(key.value) {
    console.log("[" + key + "]:" + value);
    return value;
}

JSON.stringify(obj.f);
//[]:[object object]
//[a]:[object object]
//[b]:1
//'{"a":{"b":1}}'

// 对象 obj 一共会被函数 f 处理三次,输出的最后那行是JSON.stringify()的默认输出,第一次键名为空,键值是整个对象的obj;第二次键名为a,键值是{b:1};第三次键名为b,键值为1

递归处理中,每一次处理的对象,都是前一次返回的值

var obj = {a:1};

function f(key,value) {
    if (typeof value === 'object') {
        return {b:2};
    }
    return value * 2;
}

JSON.stringify(obj,f);
// "{"b":4}"

// 上面代码中,f函数修改了对象obj,接着JSON.stringify()方法就递归处理修改后的对象obj

如果处理函数返回undefined或没有返回值,则该属性会被忽略

function f(key,value) {
    if (typeof(value) === "string") {
        return undefined;
    }
    return value;
}

JSON.stringify({a:"abc",b:123},f)
// '{"b":123}'

// a属性被处理后,返回undefined,于是该属性被忽略
[3] 第三个参数

JSON.stringify()还可以接受第三个参数,用于增加返回的JSON字符串的可读性

默认返回单行字符串,对于大型JSON对象,可读性差。第三个参数使得每个属性单独占据一行,并将每个属性前面添加指定的前缀(前缀不超过10个字符)

// 默认输出
JSON.stringify({p1:1,p2:2})
// JSON.stringify({p1:1,p2:2})

// 分行输出
JSON.stringify({p1:1,p2:2},null,'\t')
/*
{
    "p1":1,
    "p2":2
)
*/

// 第三个属性\t在每个属性前面添加一个制表符(从当前位置移动到下一个tab位置),然后分行显示

第三个属性如果是数字,则表示在每个属性前面添加的空格(不超过10个)

JSON.stringify({ p1: 1, p2: 2 }, null, 2);
/*
"{
  "p1": 1,
  "p2": 2
}"
*/

<2> JSON.parse()

JSON.parse()方法用于将 JSON 字符串转换成对应的值。

例1:

JSON.parse('{}');  // {}
JSON.parse('true');  // true
JSON.parse('"foo"');  // "foo"
JSON.parse('[1,5,"false"]');  // [1,5,"false"]
JSON.parse('null');  // null

var o = JSON.parse('{"name":"张三"}');
o.name  // 张三

例2:传入字符串不是有效的JSON格式,将报错

JSON.parse("'String'");
// 报错

// 双引号字符串中是一个单引号字符串,因为单引号字符串不符合JSON格式,所以报错

try...catch代码块,解析错误

try {
    JSON.parse("'String'");
}catch(e) {
    console.log('parsing error');
}

JSON.parse()方法接受一个处理函数,作为第二个参数,用法与JSON.stringify()方法类似

function f(key,value) {
    if (key === 'a') {
        return value + 10;
    }
    return value;
}

JSON.parse('{"a":1,"b":2}',f);
// {a:11,b:2}

// JSON.parse()的第二个参数是一个函数,如果键名是a,该函数会将键值加上10

函数声明

js中有三种声明函数的方法

(1)function命令

function命令声明的代码区块,就是一个函数。function命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面

function print(s) {
    console.log(s);
}

// 代码中命名了一个print函数,使用print()这种形式,就可以调用相应的代码,这叫做函数的声明

(2)函数表达式

funciton命令声明函数,还可采用变量赋值的写法

var print = function(s) {
    console.log(s);
}

// 将一个匿名函数赋值给变量,匿名函数又被称为函数表达式,赋值语句右侧只能放表达式

采用函数表达式声明函数时,function命令后面不带有函数名。加上函数名,则函数名只在函数体内部有效,在函数体外部无效

var print = funciton x() {
    coonsole.log(typeof x);
};

print();
// funciton

// 上面代码在函数表达式中,加入了函数x。x只在函数体内部可用,指代函数表达式本身,其他地方都不可用
// 两种用法:
//(1)函数体内部调用自身
//(2)方便除错(除错工具显示函数调用栈时,显示函数名,而不再显示这里是一个匿名函数)

var funciton  f()  {};

函数表达式末尾加分号,表示语句结束;而函数声明在结尾的大括号后面不用加分号。

(3)Function构造函数

var add = new Function(
    'x',
    'y',
    'return x + y'
);

// 等同于
function add(x,y) {
    return x + y;
}

// Function构造函数接受三个参数,除了最后一个参数是add函数的“函数体”,其他参数都是add函数的参数

可传递任意数量参数给Function构造函数,仅最后一个参数会被当做函数体;若仅一个参数,该参数就是函数体

var foo = new Function(
    'return "hello world";'
);

// 等同于
function foo() {
    return "hello world";
}

// function构造函数可不使用new命令,返回结果相同。(声明函数的方式不直观,无人使用)

你可能感兴趣的:(安全攻击,json,安全,网络,javascript,web安全)