JS对象补充

一.工厂方法创建对象

1
2
3
4
5
6
var obj = {
name:,
age:,
sex:,
showMes:
};

  我们想要创建大量的上面的obj对象, 它们的属性名都一样, 但是值可能不一样, 这时, 为了"偷懒", 我们可以使用工厂方法创建对象. 批量生产对象.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function createPerson(name, age, sex) {
var obj = {
name: name,
age: age,
sex: sex,
showMes: function() {
alert(name);
}
};
return obj;
}
var per1 = createPerson("孙悟空", 500, "男");
console.log(per1);//Object {name: "孙悟空", age: 500, sex: "男", showMes: ƒ}
var per2 = createPerson("猪八戒", 300, "男");
console.log(per2);//Object {name: "猪八戒", age: 300, sex: "男", showMes: ƒ}
var per3 = createPerson("白骨精", 500, "女");
console.log(per3);//Object {name: "白骨精", age: 500, sex: "女", showMes: ƒ}
per1.showMes();//孙悟空
per2.showMes();//猪八戒
per3.showMes();//白骨精
function createDog(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.showMes = function(){
alert(this.name);
};
return obj;
}
var dog = createDog("哮天犬",3);
console.log(dog);//Object {name: "哮天犬", age: 3, showMes: ƒ}
dog.showMes();//哮天犬

二.构造函数

  • 从上面代码的注释中, 可以看见我们用工厂方法创建的对象都是Object类型的, 不易区分不同的对象(到底是Dog还是Person), 这时, 我们可以创建一个构造函数来专门创建某一类对象.
  • 构造函数是一类特殊的普通函数, 习惯上我们将构造函数的函数名首字母大写.
  • 构造函数与普通函数相比, 调用方式不同, 普通的直接调用即可, 构造函数需要在new关键字之后调用.
  • 使用同一个构造函数创建的对象, 我们称为一类对象, 也将构造函数称为类, 将它创建的对象称为类的实例.

构造函数的执行流程:

  1. 被调用时, 首先创建一个新的对象
  2. 将函数中的this指向新建的对象(即在构造函数中, 可以用this来引用正在新建的对象)
  3. 逐行执行构造函数中的代码
  4. 将新建的对象作为构造函数的返回值返回.

A.instanceof

用法: 对象 instanceof 构造函数, 检查一个对象是否为一个构造函数的实例, 是返回true, 不是返回false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.showMes = function(){
alert(this.name);
};
}
var per1 = new Person("孙悟空", 500, "男");
console.log(per1);//Person {name: "孙悟空", age: 500, sex: "男", showMes: ƒ}
var per2 = new Person("猪八戒", 300, "男");
console.log(per1);//Person {name: "猪八戒", age: 300, sex: "男", showMes: ƒ}
var per3 = new Person("白骨精", 500, "女");
console.log(per1);//Person {name: "白骨精", age: 500, sex: "女", showMes: ƒ}
console.log(per1 instanceof Person);//true

console.log(per1.showMes == per2.showMes);//false

上面的代码有一个弊端, 每一个由Person创建的对象都有一个自己的showMes()方法

console.log(per1.showMes == per2.showMes);//false

返回结果是false, 而这不是我们想要的, 这样的话会浪费很多的内存.故修改一下, 将该函数的声明放到外面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function showMes(){
alert(this.name);
}
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.showMes = showMes;
}
var per1 = new Person("孙悟空", 500, "男");
var per2 = new Person("猪八戒", 300, "男");
var per3 = new Person("白骨精", 500, "女");

console.log(per1.showMes == per2.showMes);//true

三.原型对象

注意: 上述改进, 将对象共有的方法showMes()直接声明在全局作用域中, 也是存在一些弊端, ①污染了全局作用域(在全局作用域中不能再添加同名函数)②不是很安全. 因此, 这次我们采用一个非常好的办法, 即解决多个同类对象创建多个公共的方法, 又不会对全局作用域造成污染.

原型: prototype

  • 我们创建的每一个函数, 解析器都会向函数中添加一个属性prototype, 这个属性对应着一个对象即原型对象
  • 如果函数作为普通函数调用prototype没有任何作用
  • 如果函数以构造函数的形式调用时,它创建的对象中都会有一个隐含的属性, 指向该构造函数的原型对象, 我怕们可以用对象的__proto__属性来访问该对象
  • 原型对象就相当于一个公共的区域, 所有同一个类的实例都能访问到这个对象, 我们可以将对象中共有的内容统一放到原型对象中.
  • 当我们访问一个对象的属性或方法时, 它会先在对象自身寻找, 如果有则直接使用, 若没有则会去原型对象中寻找, 如果原型对象中有则直接使用

prototype

改进如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.showMes = function(){
alert(this.name);
};
var per1 = new Person("孙悟空", 500, "男");
var per2 = new Person("猪八戒", 300, "男");
var per3 = new Person("白骨精", 500, "女");
console.log(Person.prototype == per1.__proto__);//true

console.log(per1.showMes == per2.showMes);//true

A.检查对象的属性

1.之前提到过用in运算符检查对象中是否包含某个属性, 但这样, 如果对象的原型对象中有这个属性, 也会返回true, 显然这不是我们想得到的结果.

2.我们只想在对象本身的属性中搜索. 这时候可以用对象的hasOwnProperty()方法检查. hasOwnProperty方法其实在原型对象的原型中

3.原型对象也是对象, 它也有原型. 我们调用一个对象的属性或方法时, 会先在对象自身寻找, 没有就去对象的原型中寻找, 还没有就去原型的原型中寻找, 直到找到Object对象的原型, 没有则返回undefined

4.Object对象的原型没有原型, 它的值为null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.showMes = function(){
alert(this.name);
};
Person.prototype.a = 123;
var per = new Person("孙悟空", 500, "男");
console.log("a" in per);//true
console.log(per.hasOwnProperty("a"));//false

console.log(per.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));//true

四.toString()

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.showMes = function() {
alert(this.name);
};
var per = new Person("孙悟空", 500, "男");
console.log(per);//输出:[object Object]

console.log(Object.__proto__.hasOwnProperty("toString"));//输出:true
  • 我们直接在页面打印对象的引用时, 实际上调用了对象的toString()方法, 打印的是toString()的返回值, 默认调用的是Object原型的toString()方法.
  • 假如我们想打印对象时, 按照我们自己的想法控制输出的内容, 我们就需要显示的添加一个toString()方法, 不让当前的对象向原型中搜寻方法.
1
2
3
4
5
6
7
8
9
10
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.toString = function() {
return "Person[name:"+this.name+",age:"+this.age+",sex:"+this.sex+"]";
};
var per = new Person("孙悟空", 500, "男");
console.log(per);//Person[name:孙悟空,age:500,sex:男]

五.垃圾回收(GC)

  1. 程序运行过程中也会产生垃圾, 若垃圾过多, 会使程序运行过慢, 因此我们需要一个垃圾回收机制来处理程序运行过程中产生的垃圾.
  2. 当一个对象没有任何变量或属性对它进行引用, 我们将永远无法操作该对象, 这种对象就是垃圾.
  3. 在JS中拥有自动的垃圾回收机制, 会自动将垃圾对象从内存中销毁, 我们不需要也不能进行垃圾回收的操作.
  4. 假如我们不再使用某个对象的引用, 将它设置为null即可

评论