构造函数中的属性和方法 称为成员,成员可以添加
function Star(name,age){
this.name = name;
this.age = age;
this.sing = function(){
console.log("我会唱歌");
}
}
// 通过new 创建对象 ---实例化对象
var s = new Star('小小',12);
1:实例成员就是构造函数内部通过this添加的成员 name ,age ,sing就是实例成员
实例成员只能通过实例化对象来访问,不可以通过构造函数来访问实例成员
console.log(s.name);// 小小
console.log(Star.name);//Star
2:静态成员 在构造函数本身上添加的成员 sex就是静态成员
Star.sex = "男";
静态成员只能通过构造函数来访问,不能通过实例对象来访问
console.log(Star.sex)//男
console.log(s.sex) //undefined
我们希望所有的对象使用同一个函数,这样节省内存,如何使用同一个函数呢?
js规定,每一个构造函数都有一个prototype属性,指向另一个对象。
这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有
我们可以把哪些不变的方法,定义在prototype对象上,这样所有对象的实例就可以共享这些方法
function Star(name,age){
this.name = name;
this.age = age;
}
// 往构造函数的原型对象中添加方法
Star.prototype.sing = function(){
console.log("我会唱歌");
}
var s1 = new Star('张三',12);
var s2 = new Star('李四',23);
console.log(s1.sing === s2.sing); //true
s1.sing(); //s1实例调用构造函数原型的方法
s2.sing(); //s2实例调用构造函数原型的方法
每一个构造函数都有一个属性prototype
构造函数.prototype
指向构造函数的原型;
构造函数.prototype
就是一个对象,这个对象的属性和方法 ,都会被构造函数所拥有
所以构造函数的实例对象 可以访问构造函数的原型对象中的成员
- 对象都会有一个属性 proto 指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在;
- proto 对象原型和原型对象 prototype 是等价的
- proto 对象原型的意义在于为对象的查找机制提供了一个方向,但是它是一个非标准属性,因此在实际开发中,不可以使用这个属性,它只是内部指向原型对象prototype
function Star(name,age){
this.name = name;
this.age = age;
//this.sing = function(){
//console.log(123)
//}
}
// 给构造函数原型添加成员
Star.prototype.sing = function(){
console.log("唱歌");
}
var s1 = new Star("张三",12);
var s2 = new Star('李四',13);
s1.sing(); //实例对象可以访问原型对象成员
// 对象身上系统自己添加一个__proto__指向我们构造函数的原型对象 prototype
console.log(s1)
console.log(s1.__proto__ === Star.prototype); //true
实例对象调用方法 查找规则:
首先先看 s1对象上是否有sing方法 如果有就执行对象上的sing,如果没有就去它的构造函数的原型上查找。
总结:
- 原型就是原型对象
构造函数.prototype
就是原型实例对象.__proto__
===构造函数.prototype
每一个实例对象有__proto__
属性,指向的是构造函数的原型对象,构造函数的原型对象也是一个对象,也有__proto__
属性,这样一层一层往上找就形成了原型链
function Star(name,age){
this.name = name;
this.age = age;
}
// 原型对象
Star.prototype.sing = function(){
console.log("我会跳舞");
}
// 实例化对象
var s = new Star('张三',12);
1.只要是对象就有 __proto__
指向原型对象
console.log(Star.prototype === s.__proto__);//true
2.我们Star原型对象的__proto__
指向的是Object.prototype
// Star的原型对象 是 Object的实例化对象
console.log(Star.prototype.__proto__ === Object.prototype); //true
3.我们Object.prototype原型对象的__proto__
指向为null
console.log(Object.prototype.__proto__); //null
对象 proto 和构造函数prototype 里都有一个属性 constructor
constructor 我们称为构造函数,因为他指回构造函数本身
constructor 主要用来 记录对象引用于哪个构造函数
function Star(name,age){
this.name = name;
this.age = age;
}
Star.prototype.sing = function(){
console.log("我会跳舞")
}
var s = new Star('李四',45);
console.log(s.constructor)
/*
ƒ Star(name,age){
this.name = name;
this.age = age;
}
*/
constructor 指向的是 自身的构造函数;
我们修改了原来的原型对象,给原型对象赋值的是一个对象:
function Star(name,age){
this.name = name;
this.age = age;
}
Star.prototype = {
// 需要我们手动的给constructor 指回原来的构造函数
// constructor:Star,
sing:function(){
console.log("我会跳舞")
},
movie:function(){
console.log("我爱看电影")
}
}
var s = new Star('李四',45);
console.log(s.constructor)
// ƒ Object() { [native code] }
都说要手动指回原来的构造函数,但我不知道为什么,或这个说 记录下对象引用于哪个构造函数 有什么用,,我就只能先记下,日后知道的时候再回来补充。。
- 当访问一个对象的属性或者方法时,首先查找这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
- 如果还没有查找到就查找原型对象的原型 (Object的原型对象)
- 类推 一直找到Object位置 null
function Star(name,age){
this.name = name;
this.age = age;
}
Star.prototype.sing = function(){
console.log("我回唱歌");
}
Star.prototype.sex = "女";
var s = new Star('小小',34);
console.log(s.sex); //女
console.log(Object.prototype);
console.log(s);
console.log(Star.prototype);
console.log(s.toString());//[object Object]
构造函数中的this 和 原型对象中的this 都指向我们new出来的实例对象
function Star(name,age){
this.name = name;
this.age = age;
}
var that;
Star.prototype.sing = function(){
console.log("我会唱歌");
that = this;
}
var s = new Star('小妞',12);
s.sing();
console.log(that === s); //true
数组.push
数组.splice
数组.shift
…
都是定义在
Array.prototype原型对象上的
// 为数组扩展内置方法
Array.prototype.sum = function(){
// this 指向arr
var sum = 0;
for(var i = 0; i <this.length;i ++){
sum += this[i]
}
return sum
}
var arr = new Array(23,45,1,2,4,5,7)
// arr.push(23,45,1,2,4,5,7)
// console.log(arr)
console.log(arr.sum())
call() 可以调用函数
call()可以修改this的指向,使用call()的时候,参数1是修改后的this指向,参数2,参数3 使用逗号隔开
构造函数继承:
只能继承父类的实例属性和方法 ,不能继承 原型属性或者方法
// 父构造函数
function Parentl(){
this.name = 'parentl'
}
Parentl.prototype.getName = function(){
return this.name
}
// 子构造函数
function Child(){
// this指向子构造函数的对象实例
Parentl.call(this); //c
this.type = "child"
}
var c = new Child();
console.log(c); //继承了Parentl的name属性
console.log(c.getName())//报错
// 父类原型对象中一旦存在父类之前自己定义的方法,那么子类将无法继承这些方法
// 1:父构造函数
function Parentl(name,age){
// this指向父构造函数的对象实例
this.name = name;
this.age = age;
}
Parentl.prototype.money = function(){
console.log(1000000);
}
// 子构造函数
function Child(name,age,score){
// this指向子构造函数的对象实例
Parentl.call(this,name,age); //c
this.score = score;
}
Child.prototype = new Parentl()
// 利用对象的形式修改了原型对象,手动设置constructor
Child.prototype.constructor = Child
Child.prototype.exam = function(){
console.log("要考试了")
}
var c = new Child('小明',20,98);
console.log(c);
console.log(c.money);
console.log(Parentl.prototype);
console.log(Child.prototype.constructor)