Js Object 和 Map 和原型

263 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 14 天,点击查看活动详情

Js Object 和 Map 和原型

Object 和 Map 的差别

在 js 中,当你使用对象 object 时, 键 key 只能有 string 和 symbol 。然而 Map 的 key 支持的就比较多了,可以支持 string, symbol, number, function, object, 和 primitives

Map 上有 size 属性可以知道 map 的 keys 大小,如果想要获取 Object 的大小有通过循环的方式才能知道 map 大小确定 map 只需要 o(1),普通对象需要 o(n)

map 不需要把所有的键转换为字符串,节省了大量的性能。对象需要把所有的 key 都转换为 string,消耗了大量的性能

对象中的 key 是不保证顺序的,因为对于 number 是存放到 elements 中,会按照从小到大,对于字符串类型的是存放到 properties 中,会按照添加的顺。map 是保证顺序的,按照添加的顺序依次出来的。

当然如果想要创建一个干净的对象 从 ECMAScript 2015 开始,如果你坚持使用原生的对象, 你可以 Object.create(null) 来生成一个干净的 object

WeakMap 与 Map 区别

WeakMap 只接受对象作为键名 const map = new WeakMap(); map.set(1, 2); // TypeError: Invalid value used as weak map key map.set(null, 2); // TypeError: Invalid value used as weak map key

1、WeakMap 只接受对象作为 key,如果设置其他类型的数据作为 key,会报错。

2、WeakMap 的 key 所引用的对象都是弱引用,只要对象的其他引用被删除,垃圾回收机制就会释放该对象占用的内存,从而避免内存泄漏。

3、由于 WeakMap 的成员随时可能被垃圾回收机制回收,成员的数量不稳定,所以没有 size 属性。

4、没有 clear()方法

5、不能遍历

WeakMap 只有四个方法可用:get()、set()、has()、delete()。 无法被遍历,因为没有 size。无法被清空,因为没有 clear(),跟 WeakSet 相似

let wm = new WeakMap(), element = document.querySelector(".element");
wm.set(element, "data");
let value = wm.get('elemet');
console.log(value); // data
element.parentNode.removeChild(element);
element = null;

对象原型

普通对象和函数对象

var o1 = {};
var o2 =new Object();
var o3 = new f1();

function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');

console.log(typeof Object); //function
console.log(typeof Function); //function

console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function

console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的

原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。

在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。

当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。

虽然在脚本中没有标准的方式访问 [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每个对象上都支持一个属性proto ;而在其他实现中,这个属性对脚本则是完全不可见的。

不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

以前面使用 Person 构造函数和 Person.prototype 创建实例的代码为例

Person.prototype 指向了原型对象,而 Person.prototype.constructor 又指回了 Person 。

person1 和 person2 都包含一个内部属性,该属性仅仅指向了 Person.prototype ;换句话说,它们与构造函数没有直接的关系。

可以调用 person1.sayName() 。这是通过查找对象属性的过程来实现的。(会先在实例上搜索,如果搜索不到就会继续搜索原型。)

用 isPrototypeOf()方法判断实例与原型对象之间的关系 alert(Person.prototype.isPrototypeOf(person1)); //true alert(Person.prototype.isPrototypeOf(person2)); //true 用 Object.getPrototypeOf() 方法返回实例的原型对象 alert(Object.getPrototypeOf(person1) == Person.prototype); //true 使用 hasOwnProperty() 方法可以检测一个属性是存在于实例中,还是存在于原型中。 alert(person1.hasOwnProperty("name")); //false    alert(person1.hasOwnProperty("name")); //true

创建原型

function Person(){
}
Person.prototype = {
   name : "Nicholas",
   age : 29,
   job: "Software Engineer",
   sayName : function () {
     alert(this.name);
  }
};

在上面的代码中,我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外: constructor 属性不再指向 Person 了。

前面曾经介绍过,每创建一个函数,就会同时创建它的 prototype 对象,这个对象也会自动获得 constructor 属性。

var friend = new Person();
alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true

在此,用 instanceof 操作符测试 Object 和 Person 仍然返回 true ,但 constructor 属性则等于 Object 而不等于 Person 了。

如果 constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值。

function Person(){
}
Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};

原型模式的最大问题是由其共享的本性所导致的。 修改其中的一个,另一个也会受影响。

function Person(){
}
Person.prototype = {
constructor: Person,
name : "Nicholas",
age : 29,
job : "Software Engineer",
friends : ["Shelby", "Court"],
sayName : function () {
alert(this.name);
}
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true

原型链

其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。然后层层递进,就构成了实例与原型的链条,这就是所谓原型链的基本概念。

function SuperType(){
  this.property = true;
}
SuperType.prototype.getSuperValue = function(){
  return this.property;
};
function SubType(){
  this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
  return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 14 天,点击查看活动详情