Vue 与 CSS变量.png

前言

引用数据类型主要用于区别基本数据类型,描述的是具有属性和函数的对象
JavaScript中常用的引用数据类型包括**Object类型****Array类型****Date类型****RegExp类型****Math类型****Function类型**以及**基本数据类型的包装类型**,如Number类型、String类型、Boolean类型等。

  • 引用数据类型的实例需要通过new操作符生成,有的是显式调用,有的是隐式调用。
  • 引用数据类型变量赋值传递的是内存地址。
  • 引用数据类型的比较是对内存地址的比较,而基本数据类型的比较是对值的比较。

    new 操作符

    new操作符在执行过程中会改变this的指向,所以在了解new操作符之前,我们先解释一下this的用法。
    this的用法
    1. function Cat(name, age){
    2. console.log(this) // Cat {}
    3. this.name = name;
    4. this.age = age;
    5. }
    6. console.log(new Cat('miaomiao', 8)) // Cat {name: "miaomiao", age: 8}
    事实上我们并未通过return返回任何值,为什么输出的信息中会包含name和age属性呢?其中起作用的就是this这个关键字了。在JavaScript中,如果函数没有return值,则默认return this。代码里his实际值是Cat空对象,后两句就相当于给Cat对象添加name和age属性。
    new操作符背后做了什么: ```javascript var cat = new Cat()

// 实际new操作符做了3件事 var cat = {}; cat.proto = Cat.prototype; Cat.call(cat);

  1. 1. 创建一个空对象。
  2. 1. 将空对象的__proto__属性指向Cat对象的prototype属性。
  3. 1. Cat()函数中的this指向cat变量。于是cat变量就是Cat对象的一个实例。
  4. <a name="jP6cj"></a>
  5. # Object类型
  6. <a name="miARd"></a>
  7. ## Object类型的实例函数
  8. <a name="kFVSa"></a>
  9. ### 1. hasOwnProperty(propertyName)函数
  10. 该函数的作用是判断对象自身是否拥有指定属性,不会检查实例对象原型链上的属性。
  11. ```javascript
  12. // 1. Object
  13. var o = new Object();
  14. o.name = 'xjp'
  15. console.log(o.hasOwnProperty('name')) // true name属性为实例o自己定义的,而非继
  16. console.log(o.hasOwnProperty('toString')) // false toString为继承属性
  17. // 2. 自定义对象
  18. var Student = function(name){
  19. this.name = name
  20. }
  21. Student.prototype.sayHi = function(){
  22. alert('Hi' + this.name)
  23. }
  24. var st = new Student('张三')
  25. console.log(st.hasOwnProperty('name')) // true 调用构造函数时,通过this.name附加到实例对象上
  26. console.log(st.hasOwnProperty('sayHi')) // false sayHi为原型上的成员

2. propertyIsEnumerable(propertyName)函数

该函数的作用是判断指定属性是否为实例属性并且是否是可枚举的,如果是原型链上的属性或者不可枚举都将返回“false”。

  1. // 1. 数组
  2. var arr = [1,2,3];
  3. arr.name = 'Array'
  4. console.log(arr.propertyIsEnumerable('name')) // true name为实例属性
  5. console.log(arr.propertyIsEnumerable('join')) // false join函数继承自Array类型
  6. console.log(arr.propertyIsEnumerable('length')) // false length属性继承自Array类型
  7. console.log(arr.propertyIsEnumerable('toString')) // false toString函数继承自Object类型
  8. // 2. 自定义对象
  9. var Student = function(name){
  10. this.name = name
  11. }
  12. Student.prototype.sayHi = function(){
  13. alert('Hi' + this.name)
  14. }
  15. var a = new Student('tom')
  16. console.log(a.propertyIsEnumerable('name')) // true name为自身定义的实例属性
  17. console.log(a.propertyIsEnumerable('sayHi')) // // false sayHi为原型上的成员
  18. Object.defineProperty(a, 'name', {
  19. enumerable:false
  20. })
  21. console.log(a.propertyIsEnumerable('name')); // false name设置不可枚举

Object类型的静态函数

静态函数指的是方法的调用基于Object类型自身,不需要通过Object类型的实例。

1. Object.create(prototype, prototypeDescriptor)函数

作用:创建并返回一个指定原型和指定属性的对象。该对象的proto === 指定原型对象。
第一个参数prototype为对象的原型,可以为null。若为null,则对象的原型为undefined
第二个参数prototypeDescriptor属性描述符,格式如下:

  1. {
  2. value: '', // 设置属性的值
  3. writable: true, // 设置此属性是否可写入修改;默认false:只读
  4. enumerable: true, // 设置此属性是否可枚举;默认false:不可以枚举
  5. configurable: true // 设置此属性是否可配置,如是否可以修改此属性的特性及是否可以删除属性;默认fakse
  6. }

2. Object.defineProperties(obj, prototypeDescriptor)函数

作用:添加或修改对象的属性值

3. Object.getOwnPropertyNames(obj)函数

作用:获取对象的所有实例属性和函数,不包含原型链继承的属性和函数,数据格式为数组。

  1. function Person(name,age,gender){
  2. this.name = name;
  3. this.age = age;
  4. this.gender = gender;
  5. this.getName = function(){
  6. return this.name
  7. }
  8. }
  9. Person.prototype.eat = function(){
  10. return '吃饭'
  11. }
  12. var p = new Person();
  13. console.log(Object.getOwnPropertyNames(p)) // ['name', 'age', 'gender', 'getName'] eat()函数处在原型上

4. Object.keys()函数

作用:获取对象可枚举的实例属性,不包含原型链继承的属性,数据格式为数组。
keys()函数区别于getOwnPropertyNames()函数的地方在于,keys()函数只获取可枚举类型的属性。

Array类型

image.png

判断一个变量是数组还是对象

**typeof**运算符在判断基本数据类型时会很有用,但是在判断引用数据类型时,不能区分是数组还是对象

1. instanceof运算符

**instanceof**运算符通过查找原型链来检测某个变量是否为某个类型数据的实例,使用**instanceof**运算符可以判断一个变量是数组还是对象,要封装一下先判断数组类型,再判断对象类型

  1. // 数组不仅是Array类型的实例,也是Object类型的实例。
  2. var arr = [1,2,3]
  3. console.log(arr instanceof Array) // true
  4. console.log(arr instanceof Object) // true
  5. var obj = { name: 'xjp' }
  6. console.log(obj instanceof Array) // false
  7. console.log(obj instanceof Object) // true
  8. // 封装 判断变量是数组还是对象
  9. function getDataType(o) {
  10. if (o instanceof Array) {
  11. return 'Array'
  12. } else if (o instanceof Object) {
  13. return 'Object'
  14. } else {
  15. return '参数不是objec类型'
  16. }
  17. }

2. 判断构造函数

判断一个变量是否是数组或者对象,从另一个层面讲,就是判断变量的构造函数是Array类型还是Object类型
因为一个对象的实例都是通过构造函数生成的,所以,我们可以直接判断一个变量的constructor属性。

  1. var arr = [1,2,3]
  2. console.log(arr.constructor === Array) // true
  3. console.log(arr.constructor === Object) // false
  4. var obj = { name: 'xjp' }
  5. console.log(obj.constructor === Array) // false
  6. console.log(obj.constructor === Object) // true

每个变量都会有一个proto属性,表示的是隐式原型。一个对象的隐式原型指向的是构造该对象的构造函数的原型:

  1. [].constructor === [].__proto__.constructor // true
  2. [].__proto__ === [].constructor.prototype // true
  3. [].__proto__ === Array.prototype // true
  4. var arr = [1,2,3]
  5. console.log(arr.__proto__.constructor === Array) // true
  6. console.log(arr.__proto__.constructor === Object) // false
  7. // 判断变量是数组还是对象
  8. function getDataType(o) {
  9. // 获取构造函数
  10. var constructor = o.constructor || o.__proto__.constructor
  11. if (constructor === Array) {
  12. return 'Array'
  13. } else if (constructor === Object) {
  14. return 'Object'
  15. } else {
  16. return 'param is not object type'
  17. }
  18. }

3. toString()函数

基本任意类型都包含**toString()**函数(除nullundefined)。不同数据类型的toString()函数返回值也不一样,所以通过toString()函数就可以判断一个变量是数组还是对象。
这里我们会借助**call()**函数,直接调用Object原型上的toString()函数,把主体设置为需要传入的变量,然后通过返回值进行判断。

  1. var a = [1, 2, 3];
  2. var b = {name: 'kingx'};
  3. var c;
  4. console.log(Object.prototype.toString.call(a)); // [object Array]
  5. console.log(Object.prototype.toString.call(b)); // [object Object]
  6. console.log(Object.prototype.toString.call(c)); // [object Undefined]
  7. console.log(Object.prototype.toString.call(null)); // [object Null]
  8. console.log(Object.prototype.toString.call('xjp')); // [object String]
  9. console.log(Object.prototype.toString.call(18)); // [object Number]

4. Array.isArray()函数

使用Array.isArray()函数只能判断出变量是否为数组,并不能确定是否为对象。

  1. // 下面的函数调用都返回“true”
  2. Array.isArray([]);
  3. Array.isArray([1]);
  4. Array.isArray(new Array());
  5. // 鲜为人知的事实:其实 Array.prototype 也是一个数组。
  6. Array.isArray(Array.prototype);
  7. // 下面的函数调用都返回“false”
  8. Array.isArray();
  9. Array.isArray({});
  10. Array.isArray(null);
  11. Array.isArray(undened);
  12. Array.isArray(17);
  13. Array.isArray('Array');
  14. Array.isArray(true);

reduce()函数

reduce()函数最主要的作用是做累加处理,即接收一个函数作为累加器,将数组中的每一个元素从左到右依次执行累加器,返回最终的处理结果。

语法:
**arr.reduce(callback(accumulator、currentValue、currentIndex、array), initialValue)**

  • **initialValue**用作callback的第一个参数值,如果没有设置,则会使用数组的第一个元素值。
  • **accumulator**表示上一次调用累加器的返回值,或设置的initialValue值。如果设置了initialValue,则accumulator=initialValue;否则accumulator=数组的第一个元素值。
  • **currentValue**表示数组正在处理的值。
  • **currentIndex**表示当前正在处理值的索引。如果设置了initialValue,则currentIndex从0开始,否则从1开始。
  • **array**表示数组本身。

应用场景:

  1. 找出数组中出现次数最多的元素 ```javascript var getMost = function(arr) { var maxNum=1, maxEle; var obj = arr.reduce(function(p, k) {
    1. p[k]?p[k]++ :p[k] = 1; // 这边可以统计出每个元素出现的次数
    2. if(p[k] > maxNum) {
    3. maxEle=k;
    4. maxNum++;
    5. }
    6. return p;
    }, {}); // 将initialValue设置为一个空对象{},key表示数组元素,value表示元素出现的次数 return ‘出现次数最多的元素为:’+ maxEle + ‘,次数为’ + obj[maxEle] }; getMost([3, 5, 10, 10, 5, 7, 7, 10, 10]); // “出现次数最多的元素为:10,次数为4”

// 借助ES6与逗号运算符进行代码优化 Array.prototype.getMost = function () { var obj = this.reduce((p, n) => (p[n]++ || (p[n] = 1), (p.max = p.max >= p[n] ? p.max : p[n]), (p.key = p.max > p[n] ? p.key : n), p), {}) return ‘出现次数最多的元素为:’ + obj.key + ‘,次数为:’ + obj.max } var arr = [3, 5, 10, 10, 5, 7, 7, 10, 10]; console.log(arr.getMost()); // 出现次数最多的元素为:10,次数为:4

  1. 2. 求数组的最大值和最小值
  2. ```javascript
  3. // 最大值
  4. Array.prototype.max = function () {
  5. return this.reduce(function (preValue, curValue) {
  6. return preValue > curValue ? preValue : curValue; // 比较后,返回大的值
  7. });
  8. };
  9. // 最小值
  10. Array.prototype.min = function () {
  11. return this.reduce(function (preValue, curValue) {
  12. return preValue > curValue ? curValue : preValue; // 比较后,返回小的值
  13. });
  14. };
  15. var arr = [2,4,10,7,5,8,6];
  16. console.log(arr.min()); // 2
  17. console.log(arr.max()); // 10
  1. 数组去重
    1. function arrayUnique(array) {
    2. var obj = {}, type;
    3. return array.reduce(function (preValue, curValue) {
    4. type = typeof curValue;
    5. if (!obj[curValue]) {
    6. obj[curValue] = [type];
    7. preValue.push(curValue);
    8. } else if (obj[curValue].indexOf(type) < 0) { // 判断数据类型是否存在,如1和"1"
    9. obj[curValue].push(type);
    10. preValue.push(curValue);
    11. }
    12. return preValue;
    13. }, []);
    14. }
    15. var array = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
    16. console.log(arrayUnique(array)); // [1, 4, 5, 7, 8, 10, "1"]