浅析Object和Array上属性和方法

519 阅读8分钟

1.Array上的属性和方法

首先来看一下数组上的方法有哪些:

数组对象实例能调用的共有属性和方法:

能改变原数组的:push,pop,unshift,shift,splice,reverse,sort,这几个方法在vue中属于变异方法,可以直接触发视图更新;

不能改变原数组的:concat,join,slice,indexOf,lastIndexOfes5 /// includes,map,forEach,fill,some,every,filter,reducees6 还有valueOf,toString

数组的私有属性和方法:

Array.from()(将类数组转换为数组),Array.isArray()(判断是否为数组)

1.forEach和map

参数:回调函数 -> (当前值,当前索引值,当前数组);

forEach不支持返回值,map支持返回值;都是不会修改原数组的;map会返回一个新的数组。

let arr = [1,2,3,4,5];
arr.forEach((item,index,ary)=>{
    console.log(item,index,ary)
})

arr = arr.map((item,index)=>{
    return item+'t';
})
// ["1t", "2t", "3t", "4t", "5t"]
2.some,every和filter

参数:回调函数 -> (当前值,当前索引值,当前数组);

some:当有一个返回值为true就停止遍历,结果返回true;

every:当有一个返回值为false就停止遍历,结果返回false;

filter:返回符合条件的值并存储在一个新的数组中;

let arr = [ 1,2,3,4,5,6 ];

// some
arr.some(item=>{
    console.log(item); // 查找到符合条件的那项就结束 (1 2 3 4 5)
    return item > 4; // 结果为true
})

// every
arr.every(item=>{
    console.log(item); // 查找到不符合条件的那项就结束 (1 2 3 )
    return item < 3; // 结果为false
})

// filter
let ary = arr.filter(item=>{
    return item > 2; // 返回符合条件的值存储到一个新的数组中
})
console.log(ary); // [3, 4, 5, 6]
3.reduce

参数:第一个参数回调函数 -> (累加器,当前值,当前索引值,当前数组);第二个参数‘

返回值:函数返回的值

let arr = [1,2,3];
arr.reduce((prev,next,index,ary)=>{
    console.log(next,index,ary);
    return prev+next;
})
// prev 开始是第一个值,之后的值取决于函数的返回值,返回什么就是什么,不然就是undefined
// next 开始是第二个值,之后是后一位的值
// index 是当前next值所对应的索引值
// ary 是当前调用的对象

// 若reduce存在第二个参数,那么第一次回调函数执行的时候,prev就是这个参数,next就是数组中的第一项;之后是一样的
let ary3 = [10,20,30,40];
let res6 = ary3.reduce((prev,next)=>{
  // debugger
  return prev + next
},1000)
// 1000 + 10 + 20 + 30 + 40 = 1100

2.Object上的属性和方法

对象上的方法:

共有属性和方法:

hasOwnproperty,valueOf,toString,其他的不常用

1.hasOwnProperty

返回自己私有的变量,而xxx in xxx返回所有可枚举的属性

对象私有属性和方法:

Object.assign(),Object.create(),Object.defineProperty(),Object.is(),Object.keys(),Object.values(),Object.freeze(),Object.isFrozen()

1.Object.assign

参数:源对象,目标对象;

返回值:源对象的地址;

合并原理:把目标对象的值合并到源对象上,如果出现冲突,保留目标对象的值。

let obj1 = {
    age:12,
    name:'xt'
}
let obj2 = {
    age:18,
    address:'home'
}
console.log(Object.assign(obj1,obj2)); // {age: 18, name: "xt", address: "home"}
2.Object.create

参数:某个类的原型或者null;

返回值:返回创建的对象并将对象的原型重新指向;

function Fn(){
    this.name = name;
}
Fn.prototype.func = function(){
    console.log('可以');
}
let obj = Object.create(Fn.prototype);
obj.func(); // "可以"
console.log(obj.__proto__); // Fn
3.Object.defineProperty

参数:目标对象,要定义或修改的属性的名称,属性描述符;

返回值:get()返回的值;

属性的描述符:

configurable:当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为 false。

//configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。
var o = {};
Object.defineProperty(o, 'a', {
  get() { return 1; },
  configurable: false
});
delete o.a; // 不起作用
console.log(o.a); // => 1

Object.defineProperty(o, 'a', {
  configurable: true
}); // throws a TypeError
Object.defineProperty(o, 'a', {
  enumerable: true
}); // throws a TypeError
Object.defineProperty(o, 'a', {
  set() {}
}); // throws a TypeError (set was undefined previously)
Object.defineProperty(o, 'a', {
  get() { return 1; }
}); // throws a TypeError
// (even though the new get does exactly the same thing)
Object.defineProperty(o, 'a', {
  value: 12
}); // throws a TypeError // ('value' can be changed when 'configurable' is false but not in this case due to 'get' accessor)
//(value属性是可以修改但是的不能在设置过get函数后在使用value)

// 总结,configurable设置为flase时,value和writable可以修改,其余属性不可以,否则报错,并且删除此对象上的这个属性无效,但是在使用value时需要注意之前使用了get,那么就不能再使用value

enumerable:当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。 默认为 false。

// enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
// 请注意:for...in不仅仅遍历自己的属性,还会遍历原型链上属性,可以使用hasOwnProperty来过滤一下,而Object.keys()则是只遍历自己的属性。
var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable: true });
Object.defineProperty(o, "b", { value : 2, enumerable: false });
Object.keys(o); // '[a]' 返回值是一个数组和values()一样
for(key in o){
    console.log(key); // a
}

let arr = [1,2];
Array.prototype.age = 1;
Object.prototype.name = 2;
for(let key in arr){
    console.log(key);
}
// => 0 1 age name

Object.keys(arr);
// => ['0','1']

value:value 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为 undefined。

// 但是注意,如果使用了get函数的话就不能再使用value
var o = {};
Object.defineProperty(o, "a", { value : 1});
console.log(o.a);// => 1

writable:当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。 默认为 false。

// 当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。

var o = {}; // 创建一个新对象

Object.defineProperty(o, 'a', {
  value: 37,
  writable: false
});

console.log(o.a); // logs 37
o.a = 25; // No error thrown
// (it would throw in strict mode,
// even if the value had been the same)
console.log(o.a); // logs 37. The assignment didn't work.

// 严格模式下会报错,提示该属性就是只读属性
// strict mode
(function() {
  'use strict';
  var o = {};
  Object.defineProperty(o, 'b', {
    value: 2,
    writable: false
  });
  o.b = 3; // throws TypeError: "b" is read-only
  return o.b; // returns 2 without the line above
}());

get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为 undefined。

let o = {age:10};
Object.defineProperty(o,'age',{
    get(){
      return '10'  
    }
})
console.log(o.age); // 10

set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为 undefined。

let o = {age:10};
Object.defineProperty(o,'age',{
    set(value){
        age = value 
    }
})
console.log(o.age=18); // 18 把值设置为18,然后在通过get获取到
4.Object.is()

参数:第一个需要比较的值,第二个需要比较的值;

返回值:是否相同的布尔值;

Object.is() 判断两个值是否相同。如果下列任何一项成立,则两个值相同:

  • 两个值都是 undefined
  • 两个值都是 null
  • 两个值都是 true 或者都是 false
  • 两个值是由相同个数的字符按照相同的顺序组成的字符串
  • 两个值指向同一个对象
  • 两个值都是数字并且
    • 都是正零 +0
    • 都是负零 -0
    • 都是 NaN
    • 都是除零和 NaN 外的其它同一个数字

这种相等性判断逻辑和传统的 == 运算不同,== 运算符会对它两边的操作数做隐式类型转换(如果它们类型不同),然后才进行相等性比较,(所以才会有类似 "" == false 等于 true 的现象),但 Object.is 不会做这种类型转换。

这与 === 运算符的判定方式也不一样。=== 运算符(和== 运算符)将数字值 -0+0 视为相等,并认为 Number.NaN 不等于 NaN

Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo);         // true
Object.is(foo, bar);         // false

Object.is(null, null);       // true

// 特例
Object.is(0, -0);            // false
Object.is(0, +0);            // true
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true
5.Object.keys()和Object.values()

参数:目标对象;

返回值:返回一个数组,数组中存储着对象中的键或者值;

// 请注意:for...in不仅仅遍历自己的属性,还会遍历原型链上属性,可以使用hasOwnProperty来过滤一下,而Object.keys()则是只遍历自己的属性。
// 而且在class上添加公共方法是不能被遍历到的,因为它是不可枚举的
class A{
	b = 10;
	a(){}
}
let a = new A;
console.log(Object.getOwnPropertyNames(a));
console.log(Object.keys(A.prototype)) //这样获取不到方法a
//Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
console.log(Object.getOwnPropertyNames(A.prototype)) //这样可以获取到constructor和a方法
let obj = {
    age:10,
    name:'xt'
}
console.log(Object.keys(obj)); //['age', 'name']
console.log(Object.values(obj)); // [10, 'xt']

// 对于数组来说,Object.keys()会把number类型的索引值改为字符串
let arr = [1,2,3];
console.log(Object.keys(arr)); // => ['0','1','2']
6.Object.freeze()和Object.isFrozen()

Object.freeze():

参数:目标对象;

返回值:被冻结的对象;

let obj = {age:10};
Object.freeze(obj);
obj.age = 12; //修改不报错但是不成功,在严格模式下还会报错
console.log(obj); // { age: 10 }

Object.isFrozen():

参数:目标对象;

返回值:是否被冻结的布尔值,被冻结返回true,否则返回false;

let obj = {age:10};
console.log(Object.isFrozen(obj)); // false
Object.freeze(obj);
console.log(Object.isFrozen(obj)); //true