构造函数
构造函数的概念
在典型的oop的语言中(如:java),都存在类的概念,类就是对象的模板,对象就是类的实例,但是es6之前,js中并没有引入类的概念
创建对象的3种方式
1.利用new Object() 创建对象
var obj1 = new Object();
2.利用 对象字面量创建对象
var obj2 = {};
3.利用构造函数创建对象
function Star(uname,age) {
this.uname = uname;
this.age = age;
this.sing = function() { // 方法
console.log(‘我会唱歌’)
}
var ldh = new Star(‘刘德华’, 18) // 实例化
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋值初始值,它总是与new 一起使用,我们可以把对象中的一些公共的属性和方法抽取出来,然后封装到这个函数里
New 在执行时会做四件事情
1.在内存中创建一个新的内存空间
2.让this 指向这个新的对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4. 返回这个新对象(所以构造函数里面不需要 return)
构造函数中的属性和方法我们称为成员,成员可以添加
1.实例成员:构造函数内部通过this添加的成员(name,age,sing)
// 实例成员只能通过实例化的对象来访问的
console.log(ldh.uname);
ldh.sing();
// 不可以通过构造函数来访问实例成员
console.log(Star.uname); // undefined
2.静态成员: 在构造函数本身上添加的成员
Star.sex = ‘男’; // sex就是静态成员
// 静态函数只能通过构造函数来访问,同样也不能通过对象形式访问
console.log(Star.sex);
console.log(ldh.sex); // undefined
构造函数虽然很好用,但是还是存在内存浪费的问题
因为,每创建一次新的对象就会开辟一新的内存空间,来存放同一个函数
解决方法:让所有的对象使用同一个函数
构造函数原型prototype
构造函数原型prototype是构造函数通过原型分配的函数所有对象所共享的。
prototype:每一个构造函数都有一个prototype属性,指向另一个对象,(注意:prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数拥有)
在原型上添加一个方法:
Star.prototype.sing(){
console.log(‘我会唱歌’)
}
// 调用sing()方法
ldh.sing() // 我会唱歌
zxy.sing() // 我会唱歌
小结:一般情况下,我们的公共属性(uname,age)定义到构造函数里面,公共的方法(sing())我们放在原型对象身上
console.log(ldh) // 对象身上系统会给自己加一个__proto__指向我们构造函数原型对象prototype,
console.log(ldh.__proto__ === star.prototype) // true // __proto__ 和prototype 是等价的
方法查找规则:首先从ldh对象身上 查找是否有sing方法,有就执行这个对象身上的sing
没有就找自己身上的__proto__属性,然后从__proto__属性找到构造函数的原型对象prototype身上查找sing()这个方法
__proto__和prototype
我们为了区分__proto__和prototype,我们把__proto__称为对象原型,prototype称为原型对象
__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者就说是一个线路,是一个非标准属性,在实际开发中不能使用这个属性,它只是内部指向原型对象prototype
constructor 构造函数
对象原型(proto)和构造函数原型对象(prototype)里面都有一个constructor属性,constructor我们称为构造函数,因为它指回构造函数本身
costructor 的作用:
1.主要用于记录该对象引用哪个构造函数
2.它可以让原型对象重新指向原来的构造函数
如果构造函数里面有很多方法,那么可以通过对象形式赋值给构造函数原型,在对象里面添加方法,但是会覆盖原来的实例,所以此时我需要手动的利用constructor这个属性来值回原来的构造函数
Star.prototype = {
constructor:Star,
sing: function() {
console.log(‘我会唱歌’)
},
movie: function() {
console.log(‘我会唱歌’)
}
}
console.log(Star.prototype.constructor)
小结:如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数,这样就知道我们的对象是通过哪个构造函数来创建出来的了
构造函数,实例,原型对象三者之间的关系
原型链:
this的指向:
在构造函数中,里面的this→对象实例
原型对象函数中,this→实例化对象
普通函数中,this→window
定时器,this→window
立即执行函数: this→window
事件处理函数中:this→事件触发对象
对象方法调用: this→该方法所属对象
在js中一般理解就是谁调用这个this就指向谁
call()
调用这个函数,并且修改函数运行时的this指向
语法:
fun.call(thisArg, arg1, arg2, ...)
thisArg: 当前调用函数this的指向对象
Arg1, arg2: 传递的其他参数