构造函数

Posted lailailee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构造函数相关的知识,希望对你有一定的参考价值。

构造函数就是初始化一个实例对象,对象的prototype属性是继承一个实例对象

下面两个例子:

 1 function creatPerson(name,age,job){
 2     //工厂模式创建对象
 3     var o=new Object();
 4     o.name=name;
 5     o.age=age;
 6     o.job=job;
 7     o.sayName=function(){
 8         alert(this.name);
 9     };
10     return o;
11 }
12 var person1=creatPerson(‘LiMing‘,29,‘Doctor‘);
13 var person1=creatPerson(‘Greg‘,17,‘Teacher‘);
 1 function Person(name,age,job){
 2     //构造函数模式创建对象
 3     var o=new Object();
 4     this.name=name;
 5     this.age=age;
 6     this.job=job;
 7     this.sayName=function(){
 8         alert(this.name);
 9     };
10 }
11 var person1=Person(‘LiMing‘,29,‘Doctor‘);
12 var person1=Person(‘Greg‘,17,‘Teacher‘);

Person()中的代码除了与creatPerson()中相同的部分外,还存在以下不同之处:

1.没有显式地创建对象;

2.直接将属性和方法赋给了this对象;

3.没有return语句;

4.函数名以大写字母开头。

要创建Person新实例,,必须使用new操作符。

使用new调用构造函数实际会经历以下四个步骤:

1.创建一个新对象;

2.将构造函数的作用域赋给新对象(this指向这个对象);

3.执行构造函数中的代码(为这个新对象添加属性);

4.返回新对象(返回this)。

Person()中的两个实例person1和person 2都有一个constructor(构造函数)属性,该属性指向Person:

alert(person1.constructor==Person);   //true
alert(person2.constructor==Person);   //true

 对象的constructor属性最初是用来表示对象类型的,但要检测对象类型,还是用instanceof操作符。

我们在这个例子中创建的所有对象既是Object的实例,同时也是Person的实例:

alert(person1 instanceof Object);   //true
alert(person1 instanceof Person);   //true
alert(person2 instanceof Object);   //true
alert(person2 instanceof Person);   //true

 

1.将构造函数当做函数

构造函数与其他函数的唯一区别,就在于他们的调用方式不同。

不过,构造函数毕竟也是函数,不存在定义构造函数的特殊语法。

任何函数,只要通过new操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过new操作符调用,那它跟普通函数也没什么两样。

//当作构造函数使用
var person=new Person(‘LiMing‘,29,‘Doctor‘);
person.sayName();  //LiMing

//作为普通函数使用
Person(‘LiMing‘,29,‘Doctor‘);  //添加到window
window.sayName();  //在全局作用域 中调用一个函数时,this对象总是指向Global对象(在浏览器中就是全局对象)

//在另一个对象的作用域中调用
var o=new Object();
//可以使用call()(或者apply())在某个特殊对象的作用域中调用Person()函数
Person.call(o,‘LiMing‘,29,‘Doctor‘);  
o.sayName();

 

2.构造函数的问题

构造函数模式虽然方便好用,但使用构造函数还有一个主要问题,就是每个方法都要在每个实例上重新创建一遍。

在前面的例子中,person1和person2都有一个名为sayName()的方法,但那两个方法不是同一个Function的实例。

此时的构造函数相当于:

 1 function Person(name,age,job){
 2     //构造函数模式创建对象
 3     var o=new Object();
 4     this.name=name;
 5     this.age=age;
 6     this.job=job;
 7     this.sayName=new Function(alert(this.name)); 
10 }
alert(person1.sayName == person2.sayName);    //false

 

然而,创建两个完成同样任务的Function实例的确没有必要;况且有this对象在,根本不用在执行代码前就把函数绑定到特定对象上面。因此,可以通过把函数定义转移到构造函数外部来解决这个问题。

 1 function Person(name,age,job){
 2     //构造函数模式创建对象
 3     var o=new Object();
 4     this.name=name;
 5     this.age=age;
 6     this.job=job;
 7     this.sayName=sayName; 
 8 }
 9 
10 function sayName(){
11     alert(this.name);
12 }
13 
14 var person1=Person(‘LiMing‘,29,‘Doctor‘);
15 var person2=Person(‘Greg‘,17,‘Teacher‘);

 

这样,sayName()函数就成为了全局函数,Person()函数中的sayName就是一个指向函数sayName()的指针,person1,person2对象就共享了在全局作用域中定义的同一个sayName()函数。

那么新问题又来了:如果对象需要定义很多方法,那么就要定义很多全局函数,于是这个自定义的引用类型就毫无封装性可言了。

这个问题可以通过原型模式来解决......

 

以上是关于构造函数的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段

防止 Proguard 删除片段的空构造函数

无法解析片段中的 ViewModelProvider 构造?

为啥要避免片段中的非默认构造函数?

片段真的需要一个空的构造函数吗?

这个嵌套类构造函数片段可以应用于泛型类吗?