探究JavaScript:Array方法、原型链继承和JSON

目录

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 对值的类型和格式有严格的规定。

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

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

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

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

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

以下都是合法的 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()方法类似。

猜你喜欢

转载自blog.csdn.net/qq_68163788/article/details/131107597