构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
// 定义学生构造函数
function Student() {
// // 添加属性
this.school = '好好好学院'
this.age = 18
}
// 基于Student构造函数创建对象
const s1 = new Student()
const s2 = new Student()
在JS中,使用构造函数时需要注意以下两点:
??????? 1.构造函数用于创建某一类对象,其首字母要大写
??????? 2.构造函数要和new一起使用才有意义
new 在执行时会做四件事情:
??????? 1.在内存中创建一个新的空对象
??????? 2.让this指向这个新的对象
??????? 3.执行构造函数里面的代码,给这个新对象添加属性和方法
??????? 4.返回这个新对象所以构造函数里面不需要(return)
JavaScript 的构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的 this 上添加。通过这两种方式添加的成员,就分别称为静态成员和实例成员。
实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问。
静态成员:在构造函数本上添加的成员称为静态成员,只能由构造函数本身来访问 。
function A(uname,age){
this.uname = uname;
this.age = age;
this.say = function() {
console.log(this.uname+'你好');
}
}
var zs = new A('张三',18);
var ls = new A('李四',18);
在上述代码中,构造函数中通过this添加的name,age,say方法都是实例成员。只能由实例化的对象来访问。在构造函数本身上添加的成员叫静态成员
例如:
A.sex = '女'
构造函数通过原型分配的函数是所有对象共享的。JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。需要注意的是,这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
function Student(age,name){
this.age = age;
this.name = name;
this.score = function(){
console.log('孩子们成绩都很好!');
}
}
console.dir(Student);
打印该构造函数里面所有的方法,浏览器控制台:
可以找到prototype对象。
可以把一些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法了。
可以自己尝试打印一下下面的结果。
function Student(age,name){
this.age = age;
this.name = name;
}
Student.prototype.score = function(){
console.log('孩子们成绩都很好!');
}
console.dir(Student);
var xl = new Student(18,'小熊');
var wh = new Student(17,'王欢');
xl.score();
wh.score();
console.log(xl.score === wh.score);
需要注意的一点是:一般情况下,公共属性定义到构造函数里面,公共方法定义到原型对象身上。
对象都会有一个属性__proto__指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在。
function Student(age,name){
this.age = age;
this.name = name;
}
Student.prototype.score = function(){
console.log('孩子们成绩都很好!');
}
// console.dir(Student);
var xl = new Student(18,'小熊');
var wh = new Student(17,'王欢');
console.log(xl);
尝试打印实例对象查看它的原型(__proto__)
console.log(xl);//对象身上系统自己添加一个__proto__属性指向构造函数的原型对象
那么对象原型(__proto__)和原型对象(prototype)是否等价
我们不妨做个测试
console.log(xl.__proto__ === Student.prototype);
打印结果为:true
故:__proto__
对象原型和原型对象prototype
是等价的
我们来尝试分别打印一下原型对象和对象原型
console.log(Student.prototype);
console.log(xl.__proto__);
不难发现,它们都有一个属性叫constructor属性,这个属性指向构造函数本身。constructor
主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
?一般情况下,对象的方法都在构造函数的原型对象中设置。当给构造函数添加多个方法时,可以采用对象的方式。
__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
针对原型链的练习,加深印象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>原型链</title>
</head>
<body>
<script>
console.log(f.__proto__ === Function.prototype) // true
console.log(Function.__proto__ === Function.prototype) // true
console.log(Function.__proto__.__proto__ === Object.prototype)
// Object.prototype
console.log([].__proto__.__proto__ === Object.prototype) // true
console.log(Function.__proto__.__proto__ === [].__proto__.__proto__)
// const f = new Function('a', 'b', 'return a + b')
</script>
</body>
</html>