构造函数
在ES6中,JavaScript引入了类的概念,可以基于类创建一个对象,但在ES6之前,对象不是基于类创建的,而是通过构造函数和其他方法来创建的。
构造函数是一种特殊的函数。构造函数可以定义属性的特征和方法。构造函数可以理解为对象的模板。
构造函数创建对象
在ES6之前,创建对象的方法有三种:
1. 对象字面量
var objname={
属性名:属性值
};
2. new Object()
var objname=new Object()
objname.属性名=属性值
3. 自定义构造函数
注意:构造函数的首字母要大写
function Person(uname, age) {
this.uname = uname;
this.age = age;
}
然后通过new关键字创建一个Person的实例对象
var student= new Person('张三', 18);
new关键字创建实例对象的过程
1.在内存中创建一个新对象。
2.将构造函数中的this指向这个新对象。
3.将构造函数的prototype属性赋值给新对象内部的[[prototype]]
4.执行构造函数内部的代码,给新对象添加属性。
5.如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
构造函数成员
构造函数成员分为静态成员和实例成员
实例成员
在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问
function Person(uname, age) {
this.uname = uname; //实例成员
this.age = age;
}
静态成员
在构造函数本上添加的成员称为静态成员,只能由构造函数本身来访问
function Person(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function () { //实例成员
console.log("我会唱、跳、rap");
}
}
Person.sex = "男"; //静态成员
构造函数问题
当new一个构造函数对象时,构造函数就会执行一遍,开辟一个新的内存空间,每次都创建一些新的属性和方法function,每次都指向一个新的对象,这样占用内存消耗非常大。而构造函数原型对象Prototype可以解决这样的方法。因为对象的方法或属性可以从构造函数的原型对象prototype上获取。
。function Person(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌'); }
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
构造函数(原型对象Prototype)
JavaScript 规定,所有的函数,包括构造函数都有一个 prototype 属性,指向另一个对象(原型链上面的),注意这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。我们把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
function Person(uname, age) {
this.uname = uname;
this.age = age;
}
Person.prototype.sing = function () {
console.log("我会唱、跳、rap");
}
var person1= new Person('张三', 18);
var person2= new Person('李四', 20);
console.log(person1.sing === person2.sing);
person1.sing();
person2.sing();
对象原型 __proto__
JS 在创建对象的时候,都有一个__proto__
的内置属性,用于指向创建它的构造函数的原型对象。
function Fruit(name, price) {
this.name = name
this.price = price
}
var apple = new Fruit('apple', 10)
console.log(apple.__proto__ === Fruit.prototype);
//excepted output:true
constructor 构造函数
对象原型( __proto__)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
实例对象使用constructor属性指回构造函数。
原型对象prototype使用constructor只会构造函数。
constructor的应用场景
一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。
示例:
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
/* Star.prototype.sing = function () {
console.log("我会唱、跳、rap");
}
Star.prototype.movie = function () {
console.log("我会跳舞");
} */
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
constructor: Star,
sing: function () {
console.log("我会唱、跳、rap");
},
movie: function () {
console.log("我会跳舞");
}
}
继承与原型链
继承
JavaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
原型链
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
JavaScript成员 查找机制
①当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
②如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。
③如果还没有就查找原型对象的原型(Object的原型对象)。
④依此类推一直找到 Object 为止(null)。
⑤__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
由于原型链的存在,因此我们可以调用一些不存在与该对象属性的方法,因为这些方法存在于原型链的Object的原型对象上。