(三)创建对象

2017-02-09  本文已影响19人  一只环环环

0.注

本文代码来自于《JavaScript高级程序设计》一书,非原创,算是小弟读书笔记。而且我也不认为自己写的实例代码能比Zakas的更清晰易懂。主要记录下自己认为干货的部分以及加入自己的理解。文中示意图等均为原创。

1.对象?

ECMA的定义:无序属性的集合,其属性可以包含基本值、对象或者函数。
我自己的理解,对象就是一个包含了若干键值对的无序列表。

2.创建对象的方式

  //代码来自《JavaScript高级程序设计》
   function createPerson(name,age,job) {
       var o = new Object();
       o.name = name;
       o.age = age;
       o.job = job;
       o.sayName = function () {
           alert(this.name);
       };
       return o;
   }
   var person1 = createPerson('gordenZ','24','front-end engineer');
     ```

* 构造函数模式(问题也大,不会直接用)
  ```javascript
   //代码来自《JavaScript高级程序设计》
   function Person(name,age,job) {
       this.name = name;
       this.age = age;
       this.job = job;
       this.sayName = function () {
           alert(this.name);
       };
   }
   var person1 = new Person('gordenZ','24','front-end engineer');
     ```
这个例子中,创建了一个构造函数`Person`,并使用`new`操作符实例化了一个对象`person1`。
**为何要使用new 操作符?**
想像一下不使用new的情况:
```javascript
var person1 = Person('gordenZ','24','front-end engineer');
 console.log(name);//gordenZ

如果不使用new操作符,相当于在当前环境下直接执行Person这个函数(构造函数也是函数,仅仅是第一个字母大写了)。这里的执行环境是window,那么Person中的this就指向了全局的window对象,所以nameagejobsayName等属性都被创建在了全局对象上,可以直接被访问到。
new操作符干的事情
1.创建一个新对象
2.将构造函数的this指向这个对象(这样就不再是创建到window上了)
3.执行构造函数
4.返回新对象
其实跟工厂模式没有什么区别嘛
构造函数模式问题:
构造函数模式创建的每个对象的实例都是完全独立的,意味着每个实例中的属性都是不同的,这对于值是基本数据类型的属性来说还好,但是对于值是一个实现同一功能的函数的属性来说就显得冗余了,每一个实例都会有一个自己的函数,有多少个实例就会创建多少个相同的函数(不要忘了,每个函数都是一个对象)。

function Person() {
}
Person.prototype.name = "gordenZ";
Person.prototype.age = "24";
Person.prototype.job = "front-end engineer";
Person.prototype.sayName = function () {
    alert(this.name);
};
 var person1 = new Person();
 var person2 = new Person();

  console.log(person1.sayName === person2.sayName); //true

其中,Person构造函数Person.prototype原型对象person1person2Person实例,这三者的关系如下图:

构造函数、原型对象、实例之间的关系
每一个函数(也就包括了构造函数)在创建都会获得一个prototype属性,指向了这个函数的原型对象。所有的原型对象都默认有一个constructor·属性,指向构造函数(Person.prototype.constructor == Person //true)。在根据构造函数创建的实例中,有一个__proto__指针,指向了该类型的原型对象
可以看到,现在的nameagejobsayName被所有实例共享了。
1.每个实例又可以添加自己独立的属性
person1.sex = "man"

2.可以在实例中添加与原型中属性相同的属性,这样会屏蔽掉原型中的同名属性。寻找属性的方式是,首先在实例本身找,找到了就返回,如果没有找到,则到__proto__指针指向的原型对象上寻找。

person1.name = "grey"
console.log(person1.name) //grey 

3.其他实例若没有添加,则不受影响

console.log(person2.name) //gordenZ。

4.判断是原型属性还是实例属性:hasOwnProperty()

console.log(person1.hasOwnProperty('name'));//true
console.log(person2.hasOwnProperty('name'));//false

5.判断对象是否是一个实例的原型:isPrototypeOf()

console.log(Person.prototype.isPrototypeOf(person1));//true
console.log(Person.prototype.isPrototypeOf(person1));//true

6.获取一个实例的原型:Object.getPrototypeOf()

console.log(Object.getPrototypeOf(person1) == Person);//true

原型模式的问题
高度共享带来问题,在共享的属性中,如果是数据属性,可以用在实例上添加同名属性来屏蔽,但如果某个属性是一个引用类型,那么在任何一个实例上对其进行修改,都会影响到所有实例。

function Person(name,age,job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = ["aa","bb"];
}
Person.prototype = {
    //补全constructor属性
    constructor:Person,
    sayName:function () {
       alert(this.name)
    }
};
var person1 = new Person();
var person2 = new Person();
上一篇下一篇

猜你喜欢

热点阅读