目录
Array对象
构造函数
静态方法
Array.isArray()
实例方法
valueOf()
toString()
对象的继承
构造函数的缺点
prototype属性作用
原型链
读取对象的某个属性的过程:
constructor属性
instanceof运算符
JSON
JSON优点:
JSON 对值的类型和格式有严格的规定。
JSON对象
JSON.stringify()【JS格式->JSON格式】
第一个参数
第二个参数
第三个参数
参数对象的 toJSON() 方法
JSON.parse()【JSON格式->JS格式】
Array对象
构造函数
Array是javaScript的原生对象,同时也是一个构造函数,可以用它来生成新的数组
静态方法
Array.isArray()
Array.isarray方法返回一个布尔值,表示参数是否为数组。他可以弥补typeof运算法的不足
例如:
<script>
var arr = [1, 2, 3];
var a = typeof arr;
var b = Array.isArray(arr)
console.log(a, b);
</script>
结果:
实例方法
valueOf()
valueOf方法是一个所有对象都拥有的方法,表示对该对象求值
不同对象的valueof方法不尽一致,数组的valueof放阿飞返回数组本身
例如:
<script>
var arr = [1, 2, 3]
var arr_result = arr.valueOf()
console.log(arr_result);
</script>
结果:
toString()
toString方法也是对象的通用方法
数组的toString方法返回数组的字符串形式
例如:
<script>
var arr = [1, 2, 3]
var arr_result = arr.toString()
console.log(arr_result);
</script>
结果:
对象的继承
A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法。这对于代码的复用是非常有用的。
大部分面向对象的编程语言,都是通过“类”(class)实现对象的继承。传统JavaScript 语言的继承不通过 class,而是通过“原型对象”(prototype)实现(类==原型对象)
对象是类的具体化
构造函数的缺点
JS通过构造函数生成新对象,因此构造函数可以视为对象的模版。实例对象的属性和方法,可以定义在构造函数内部
例如:
<script>
function Cat(name, color) {
this.name = name;
this.color = color;
}
var cat1 = new Cat('大毛', '白色');
cat1.name // '大毛'
console.log(cat1.name);
cat1.color // '白色'
console.log(cat1.color);
</script>
上面代码中,Cat函数是一个构造函数,函数内部定义了name属性和color属性,所有实例对象(上例是cat1)都会生成这两个属性,即这两个属性会定义在实例对象上面。
结果:
问题的提出:同一个构造函数的多个实例之间,无法共享属性,从而造成了对系统资源的浪费
问题的解决:JavaScript的原型对象(prototype)
prototype属性作用
JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
js规定,每一个函数都有一个Prototype属性,执行一个对象
对于普通函数来说,该属性基本无用,但是对于构造函数来说,生成实例的时候,该属性会自动生成实例对象的原型。
例如:
function Animal(name) {
this.name = name;
}
Animal.prototype.color = 'white';//为Animal原型对象添加一个属性white
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color // 'white'
cat2.color // 'white'\
console.log(cat1.color, cat2.color);
上面代码中,构造函数Animal的prototype属性,就是实例对象cat1和cat2的原型对象。原型对象上添加一个color属性和方法miaomiao,结果,实例对象都共享了该属性和方法。
结果:
结果显示实例对象可以正常的使用原型对象的属性和方法
注意:
只要修改了原型对象,变动就立即会体现在所有实例对象上
如果实例对象自身就有某个属性或者方法,它就不会再取原型对象寻找这个属性或者方法(即自身拥有的优先级大于原型对象的优先级)
原型对象的作用,就是定义所有实例对象共享的属性和方法。
原型链
JavaScript规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于对象也是对象,所以它也有自己的原型。因此就会形成一个“原型链(prototype chain)”:对象到原型,再到原型的原型……
原型链继承:原型对象定义一个属性
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。
Object.prototype的原型是null,null没有任何属性和方法,也灭有自己的原型,因此原型链的尽头就是null
读取对象的某个属性的过程:
读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
覆盖:如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性
注意:一级级向上,在整个原型链上寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
constructor属性
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数
constructor属性的作用是:可以得知某个实例对象,到底是哪一个构造函数产生的。
例如:
function F() { };
var f = new F();
a = f.constructor === F // true
b = f.constructor === RegExp // false
console.log(a, b);
结果:
根据可以知道:constructor属性确定了实例对象f的构造函数时F而不是RegExp
instanceof运算符
instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例
instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构造函数的原型对象(prototype),是否在左边对象的原型链上。
instanceof的原理是检查右边构造函数的prototype属性,是否在左边对象的原型链上。有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。
例如:
var obj = Object.create(null);
typeof obj // "object"
obj instanceof Object // false
上面代码中,Object.create(null)返回一个新对象obj,它的原型是null。右边的构造函数Object的prototype属性,不在左边的原型链上,因此instanceof就认为obj不是Object的实例。这是唯一的instanceof运算符判断会失真的情况(一个对象的原型是null)。
instanceof运算符的一个用处,是判断值的类型。
例如:
var x = [1, 2, 3];
var y = {};
x instanceof Array // true
y instanceof Object // true
根据结果显示可以知道x为数组,y为对象
注意:instanceof运算符只能用于对象,不适用原始类型的值。
JSON
JSON格式(JavaScript Object Notation)是一种用于数据交换的文本格式,目的是取代繁琐笨重的XML格式
JSON优点:
书写简单,一目了然;符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。
每个 JSON 对象就是一个值,可能是一个数组或对象,也可能是一个原始类型的值。总之,只能是一个值,不能是两个或更多的值。
JSON 对值的类型和格式有严格的规定。
-
复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
-
原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用NaN(非数字的值), Infinity(无限大), -Infinity(无限小)和undefined(未定义))。
-
字符串必须使用双引号表示,不能使用单引号。
-
对象的键名必须放在双引号里面。
-
数组或对象最后一个成员的后面,不能加逗号。
以下都是合法的 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;
}
} // 属性值不能使用函数和日期对象
注意:null、空数组和空对象都是合法的 JSON 值。
JSON对象
JSON对象是 JavaScript 的原生对象,用来处理 JSON 格式数据。
它有两个静态方法:JSON.stringify()和JSON.parse()。
JSON.stringify()【JS格式->JSON格式】
第一个参数
基本用法:
JSON。stringify()方法用于将一个值转换为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.stringify({ name: "张三" })
// '{"name":"张三"}'
上面的各种类型的值都会被转换为JSON字符串
注意:对于原始类型的值,转换结果会带双引号“”
特别的:
a = (JSON.stringify('foo') === "fool")
b = (JSON.stringify('foo') === "\"foo\"")
console.log(a, b);
上面代码中,字符串foo被转换为了"\"“foo”\“”。这是因为还原的时候,内层的双引号可以让js引擎知道,这是一个字符串,而不是其他的类型
结果:
如果对象的属性是undefined、函数或 XML 对象,该属性会被JSON.stringify()过滤。
如果数组的成员是undefined、函数或 XML 对象,则这些值被转成null。
如果是正则对象会被转成空对象。
第二个参数
JSON.stringify()方法还可以接受一个数组,作为第二个参数,指定参数对象的哪些属性需要转成字符串
第二个参数还可以是一个函数,用来更改JSON.stringify()的返回值。
例:
function f(key, value) {
if (typeof value === "number") {
value = 2 * value;
}
return value;
}
a = JSON.stringify({ a: 1, b: 2 }, f)
console.log(a);
上面代码中的f函数,接受两个参数,分别是被转换的对象的键名和键值。如果键值是数值,就将它乘以2,否则就原样返回。
结果:
第三个参数
JSON.stringify()还可以接受第三个参数,用于增加返回的 JSON 字符串的可读性。
默认返回的是单行字符串,对于大型的 JSON 对象,可读性非常差。第三个参数使得每个属性单独占据一行,并且将每个属性前面添加指定的前缀(不超过10个字符)。
例:
// 默认输出
a = JSON.stringify({ p1: 1, p2: 2 })
console.log(a);
// 分行输出
b = JSON.stringify({ p1: 1, p2: 2 }, null, '\t')
console.log(b);
上面例子中,第三个属性\t在每个属性前面添加一个制表符,然后分行显示。
结果:
第三个属性如果是一个数字,则表示每个属性前面添加的空格(最多不超过10个)。
参数对象的 toJSON() 方法
如果参数对象有自定义的toJSON()方法,那么JSON.stringify()会使用这个方法的返回值作为参数,而忽略原对象的其他属性
例:
var user = {
firstName: '三',
lastName: '张',
get fullName() {
return this.lastName + this.firstName;
},
toJSON: function () {
return {
name: this.lastName + this.firstName
};
}
};
a = JSON.stringify(user)
console.log(a);
上面代码中,JSON.stringify()发现参数对象有toJSON()方法,就直接使用这个方法的返回值作为参数,而忽略原对象的其他参数。
结果:
toJSON方法的一个应用是:将正则对象自动转换为字符串。
因为JSON.stringify()默认不能转换正则表达式,但是设置了toJSON()方法以后,就可以转换正则对象了。
例:
var obj = {
reg: /foo/
};
// 不设置 toJSON 方法时
JSON.stringify(obj)
//结果: "{"reg":{}}"
// 设置 toJSON 方法时
RegExp.prototype.toJSON = RegExp.prototype.toString;
JSON.stringify(/foo/)
//结果: ""/foo/""
hacker 平替写法 绕弯的写法
上面代码在正则对象的原型上面部署了toJSON()方法,将其指向toString()方法,因此转换成 JSON 格式时,正则对象就先调用toJSON()方法转为字符串,然后再被JSON.stringify()方法处理。
JSON.parse()【JSON格式->JS格式】
JSON,parse()方法用于将JSON字符串转换为对应的值。
例如:
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 // 张三
如果传入的字符串不是有效的 JSON 格式,JSON.parse()方法将报错。
JSON.parse()方法可以接受一个处理函数,作为第二个参数,用法与JSON.stringify()方法类似。