ES5的构造函数语法
- 创建对象的方法有两种:
-
字面量 const obj = {}
-
构造函数 const obj = new Object()
构造函数就是JavaScript程序定义好的构造函数,我们直接使用就可以了
构造函数是专门用于生成、定义对象的
-
通过构造函数生成的对象称为实例化对象
实例化对象就是通过构造函数,生成的对象,称为实例化对象
-
构造函数和普通函数的区别:
-
构造函数一定要和关键词 new一起使用。
new 关键词具有特殊的功能,会自动给构造函数中定义一个对象,并且返回这个对象;我们只要对这个对象设定属性和方法就可以
-
构造函数的语法规范规定:构造函数的函数名称,第一个字母必须大写,使用大驼峰命名法。
-
构造函数给对象定义属性和方法的语法与一般函数不同
代码展示:
function CrtObj(name,age,gender){
// 在构造函数中:使用this来指代对象
// 这个对象就是我们使用构造函数生成的实例化对象
// 定义属性
// 给实例化对象,添加name属性,属性值是输入的name参数
this.name = name;
this.age = age;
this.gender = gender;
// 定义方法
this.fun = function(){
console.log(this.name,this.age,this.gender )
}
}
// 通过自定义构造函数生成实例化对象
const obj = new CrtObj('王逸',20,'男');
console.log(obj);
// 调用 对象/实例化对象 中的方法
obj.fun();
输出结果:

函数的prototype属性
不同的实例化对象中,定义的是不同的方法、函数,会占用过多的内存空间。所以,一般将构造函数需要定义给实例化对象的方法,定义在函数的 prototype 属性中。
- 定义在 prototype 中的属性,就是写在 prototype 中的,不会写在实例化对象中。所以实例化对象中要添加属性,都是通过 this关键词来指向实例化对象。
- 在 prototype 中定义的方法/函数,也不会定义在实例化对象上,只会出现在函数的prototype 中。
代码展示:
function fun(){}
// 向 fun 函数 中的 prototype 中,添加属性 name 属性值 张三
fun.prototype.gender = '女';
// 向 fun 函数 中的 prototype 中,添加函数,函数名为f
fun.prototype.f = function(){console.log(年龄18)};
console.dir( fun );

实例化对象的__proto__属性
- 构造函数在生成实例化对象时,会将自己 prototype 这个空间的地址赋值给实例化对象 的__proto__来存储。 实际上,构造函数的 prototype和生成的实例化对象的__proto__指向的是同一个存储空间,可以相互调用数据。
- 当调用实例化对象中定义在函数本身上的函数/数据时,其实实例化对象本身中是没有这个函数的,会继续在 __proto__中寻找是否有这个方法函数 /数据。__proto__实际上指向的就是构造函数的 prototype。因为构造函数的 prototype 中是有这个方法函数/数据的,所以就可以正常调用。
原型对象、原型属性、原型链三者的联系
-
原型对象
每一个函数本身就存在的prototype 属性,称为原型对象;是一个专门用来存储数据、函数等内容的空间。
-
原型属性
每一个对象本身就存在的 __proto__属性,称为原型属性。实例化对象的原型属性指向的是创建实例化对象的构造函数的 prototype。
-
原型链
原型链就是将所有相互关联的变量使用__proto__ 属性串联起来, 在调用数据时,会通过__proto__ 将所有相互关联的变量串联,只要有一个变量中有相应的属性,就会调用成功。
图示:


ES5构造函数存在的一个问题
在ES5中定义 prototype是在函数之外定义的,并且调用构造函数、生成实例化对象时,一定要在定义 prototype之后;否则如果先调用构造函数,生成的实例化对象就只有属性没有函数方法,因为定义方法的步骤还没执行呢。
例如:
// 如果先调用构造函数,只有属性没有方法
// 因为定义方法的步骤还没执行
const obj1 = new Fun('王毅');
obj1.f() // 提前调用,执行结果是报错的
function Fun(name){
this.name = name;
}
// 在定义函数外,定义prototype
Fun.prototype.f = function(){
console.log(this.name)
}
const obj2 = new Fun('李明');
obj2.f();
以上代码的执行结果会报错。
ES6中新增语法形式: class 类
- 作用和原理与ES5语法完全相同,只是语法格式和书写方式不同
- ES5和ES6语法的对比
- ES5语法代码展示
function Fun1(name,age){
this.name = name;
this.age = age;
}
Fun1.prototype.f1 = function(){ //在构造函数之外定义prototype
console.log(this.name , this.age);
}
const obj1 = new Fun1('王毅',18);
console.log(obj1);
ES6代码展示
class Fun2{ //class后面的Fun2是类名,不是函数名,所以Fun2后面没有()
constructor(name,age){ //constructor是构造器,()中定义的是class类的参数
this.name = name;
this.age = age; //在构造器中定义实例化对象:this.属性=属性值;
//与ES5中定义实例化对象的属性和属性值的语法形式完全相同,只是书写格式和书写位置不同。
}
f2(){
console.log(this.name , this.age);
} //f2(){ }是函数方法,在ES6语法中:写在构造函数内,也是定义在函数的Protype中
}
const obj2 = new Fun2('李明',20);
console.log(obj2);
输出结果完全相同:

- 区别:
- ES6语法中定义的class类,不是function函数,不会被JavaScript程序与解析。所以class不能提前调用
- function可以提前调用,但是提前调用时,只有属性没有方法。