原型
定义:原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
// 所有函数都有原型对象
// 构造函数访问原型对象 prototype --- 存放公共方法
// 实力对象访问原型对象 __proto__ --- 存放公共方法
// constructor 构造方法(原型对象创建的构造函数)
// 构造函数 (首字母大写)
function Person(uname,age,sex){
this.uname = uname;
this.age = age;
this.sex = sex;
// this.fn = function(){
// console.log(this.uname+"今年"+this.age+"岁了-----" +this.sex);
// }
}
Person.prototype.fn = function(){
console.log("这是原型对象上的方法");
}
console.log("原型对象---prototype",Person.prototype);
let p = new Person("猿究院",18,"男"); // 实例化对象
let p1 = new Person("html",19,"女"); // 实例化对象
let p2 = new Person("css",20,"男"); // 实例化对象
console.log(p,p1);
// p.fn(); // 如果Person里面有fn就会调用Person里面的fn //如果Person没有fn 会去原型对象上找fn
// p1.fn(); // 如果Person里面有fn就会调用Person里面的fn //如果Person没有fn 会去原型对象上找fn
// console.log(p.fn === p1.fn === p2.fn);
// console.log(Person.prototype === p.__proto__); // 构造函数访问原型对象与实例对象访问原型对象是一样的 所以为true // 只能两两比较 不能多个比较
// console.log(p1.fn === p.fn);
// 两两比较为true 因为两个找的地方都是一样的 但是三个比较的话 前两个比较为true 在于第三个做比较就会为true
// console.log(Person.prototype.constructor === Person);
构造函数是用来生产对象的,用new来产生对象;
Person代表函数引用,函数也相当于一个对象,是对象就有相应的属性和方法,Person.prototype
的prototype是系统自带的属性,proson就是原型。
自己也有属性,原型上也有属性,两个都有则访问自己的属性;要是自己没有,则向上去继承父亲的属性。
原型链
原型链终端 --> Object.prototype null
每一个对象都有一个“proto”指针,指向实例化该对象的构造函数的原型对象,当该对象没有你想拿到的属性时,解释器会顺着指针不断向上找,直到这个结束为null。
所以 Object.prototype.__proto__
的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。
所以查找属性的时候查到 Object.prototype 就可以停止查找了。
总结:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
原型继承
子类继承父类如果父类里面有子类需要的属性可以直接调用父类里的属性使用,如果父类里面没有子类所需要的属性,在子类里面可以自身去创建它的这个属性使用(父类里有这些属性,继承就可以调用这些属性,没有锁需要的属性,子类自身去创建这个属性)。
// 利用原型及原型链实现继承【面向对象】
// 父 构造函数
function Father(name,age,sex){
// this指向创建它的实例对象 f
this.name = name;
this.age = age;
this.sex = sex;
}
function Son(name,age,sex,email){
// this指向创建它的实例对象 s
// 使用call()立即调用父类方法,并传递参数
Father.call(this,name,age,sex);
// 如果父类没有子类需要的属性 (自身创建这个属性)
this.email = email;
// 父类里面有这些属性,继承就可以调用这些属性
// this.name = name;
// this.age = age;
// this.sex = sex;
}
let f = new Father("猿究院",35,"男");
let s = new Son("html",18,"男","8468@qq.com");
console.log(f,s);
子类继承父类所有的属性,父类在公共方法上创建的所有属性子类都可以使用,但是在子类上创建的方法父类也可以去使用,这时候就需要父类创建一个新的实例对象让其变为子类构造函数的原型对象,其是父类的实例对象又是父类的原型对象所以子类的属性也会返回到父类上面,所以就要手动改变子类原型对象的指向的构造函数。
// 利用原型及原型链实现继承【面向对象】
// 父 构造函数
function Father(name,age,sex){
// 指向创建它的实例对象 f
this.name = name;
this.age = age;
this.sex = sex;
}
// Father构造函数的原型对象上的公共方法
Father.prototype.money = function(){
console.log(this.name+"----在挣钱");
}
// 子 构造函数
function Son(name,age,sex,email){
// 指向创建它的实例对象 s
// 使用call()立即调用父类方法,并传递参数【继承父类属性】
Father.call(this,name,age,sex);
// 子类 自身属性
this.email = email;
// this.name = name;
// this.age = age;
// this.sex = sex;
}
// 直接将父构造函数的原型对象赋值给子构造函数的原型对象
Son.prototype = Father.prototype;
// 通过new 将父构造函数 的 实例对象 赋值给 son 的 原型对象
Son.prototype = new Father;
// 利用 constructor 手动改变Son的原型对象的指向的构造函数
Son.prototype.constructor = Son;
// console.log("!!!",Son.prototype);
// 在Son 的 原型对象上添加 game 方法
Son.prototype.game = function(){
console.log(this.name+"---在玩游戏");
}
let f = new Father("猿究院",50,"男");
let s = new Son("heml",20,"女","468456@qq.com");
console.log(f,s);