1. 静态成员和实例成员
静态成员在构造函数本身上添加的成员,静态成员只能通过构造函数来访问。
function Person(name,age){
this.name = name;
this.age = age;
}
Person.sex = '男';//sex就是静态成员
var one = new Person('小明',12);
console.log(Person.sex); //静态成员只能通过构造函数来访问
2. 实例成员
实例成员就是构造函数内部通过this添加的成员,实例成员只能通过实例化的对象来访问。
//nam,age,study就是实例成员
function Person(nam,age){
this.nam = nam;
this.age = age;
this.study = function(){
console.log('我再认真学习js');
}
}
var one = new Person('小明',12);
console.log(one.study); //实例成员只能通过实例化对象来访问
3. prototype
,__proto__
,constructor
三者关系
prototype
每创建一个函数就会自动带有一个 prototype
属性。可以为其添加函数供实例访问,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性。
__proto__
- 对象都会有一个属性
__proto__
指向构造函数的prototype
原型对象,之所以我们对象可以使用构造函数prototype
原型对象的属性和方法,就是因为对象有__proto__
原型的存在。 -
__proto__
对象原型和原型对象prototype是相等的。 -
__proto__
对象原型的意义就是在于为对象查找机制提供一个方向,但是它是一个非标准属性,实际开发中不可以使用这个属性,它只是内部指向原型对象prototype
。
constructor
- 对象原型
__proto__
和构造函数prototype
原型对象里面都有一个属性constructor
属性,constructor
称为构造函数,因为它指回构造函数本身; -
constructor
主要是用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。 - 一般情况下,对象的方法都在构造函数的原型对象中设置,如果有多个对象方法,我们可以给对象采用对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,修改后的原型对象
constructor
就不在指向当前构造函数,此时可以在修改后的原型对象中,添加一个constructor
指向原来的构造函数。

三者的关系是,每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。通俗点说就是,实例通过内部指针可以访问到原型对象,原型对象通过 constructor
指针,又可以找到构造函数。
//函数名和实例化构造名相同且大写(非强制,但这么写有助于区分构造函数和普通函数)
function Person(name,age) {
this.name = name;
this.age=age;
}
Person.prototype.say = function(){
return "我的名字叫" + this.name+"今年"+this.age+"岁了";
}
var obj=new Person("laotie",88);//通过构造函数创建对象,必须使用new 运算符
console.log(obj.say());//我的名字叫laotie今年88岁了
构造函数生成实例的执行过程(new
实例过程):
1.创建空对象。
2.设置空对象的__proto__
属性继承构造函数的原型对象,原型对象中的属性,新对象可以直接使用,不用重复定义。
3.调用构造函数为新对象添加属性和方法。
4.返回新对象地址保存在变量中;
4. 原型链
任何对象都有原型对象,也就是 prototype
属性,任何原型对象也是一个对象,该对象有 __proto__
属性,这样一层一层往上找,就会形成一条链就是原型链。
1.当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
2.如果没有就查找它的原型(也就是 __proto__
指向的 prototype
原型对象)。
3.如果还没有就查找原型对象的原型( Object
的原型对象)。
4.依此类推一直找到 Object
为止( null
)。
5.__proto__
对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。

代码示例
//定义一个 Animal 构造函数,作为 Dog 的父类
function Animal () {
this.superType = 'Animal';
}
Animal.prototype.superSpeak = function () {
alert(this.superType);
}
function Dog (name) {
this.name = name;
this.type = 'Dog';
}
//改变Dog的prototype指针,指向一个 Animal 实例
Dog.prototype = new Animal();
//上面那行就相当于这么写
//var animal = new Animal();
//Dog.prototype = animal;
Dog.prototype.speak = function () {
alert(this.type);
}
var doggie = new Dog('jiwawa');
doggie.superSpeak(); //Animal
解释一下。以上代码,首先定义了一个 Animal
构造函数,通过 new Animal()
得到实例,会包含一个实例属性 superType
和一个原型属性 superSpeak
。另外又定义了一个Dog
构造函数。然后情况发生变化,代码中加粗那一行,将 Dog
的原型对象覆盖成了 animal
实例。当 doggie
去访问 superSpeakv
属性时,js
会先在 doggie
的实例属性中查找,发现找不到,然后,js
就会去 doggie
的原型对象上去找,doggie
的原型对象已经被我们改成了一个 animal
实例,那就是去 animal
实例上去找。先找 animal
的实例属性,发现还是没有 superSpeack
, 最后去 animal
的原型对象上去找,诶,这才找到。
网友评论