函数的prototype属性。
1 每个函数都有prototype属性,它默认指向一个空的Object实例对象。
function Fn(){
}
console.log(Fn.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) //false
console.log(Function.prototype instanceof Object) // true
2 所有函数都是Function的实例(包括Function)
console.log(Function.__proto__ = Function.prototype) // true
3 Object的原型对象是原型链的尽头
console.log(Fn.prototype.__proto__ == Object.prototype) // true
console.log(Object.prototype.__protpo__) // null
4 每个函数的原型对象默认都有一个constructor属性
每个函数的原型对象(Fn.prototype) 默认都有一个constructor属性 指向构造函数本身(Fn)
5 每个实例都有一个隐式原型(proto)指向构造函数的原型对象(Fn.prototype)
6 当实例调用一个属性或者方法的时候,先在本身查找,如果本身没有查找到,就顺着实例的隐式原型__proto__的指向一直往上查找。
7 每个函数的原型对象(Fn.prototype)上面也有隐式原型(proto)
fn.__proto__ = Fn.prototype //true
8 原型链上也有隐式原型__proto__,这个隐式原型指向 Object.protype
Fn.prototype.prpto == Object.prototype
9 原型对象有一个属性construcoter,它指向函数对象。
(Date.prototype.constructor == Date //true
原型链继承 通过new Father()方式
让sun.prototype 成为Father的实例。
function Father() {
this.name = 'father'
}
Father.prototype.fatherShow = function () {
console.log('father show')
}
function Sun() {
this.name = 'sun'
}
Sun.prototype.showSun = function () {
console.log('sun show')
}
Sun.prototype = new Father();
//new Father之后Sun.prototype.consturctor指向Father,所以需要把
consturctor 在指到Sun上。
Sun.prototype.consturctor = Sun;
var sun = new Sun();
sun.fatherShow()
我们通过Sun.prototype = new Father(); 让Sun.prototype是 Father的实例。这样就能访问到 Father的原型对象。
首先我们sun.fatherShow()
1 先在sun实例对象上找 fatherShow方法
2 如果没有找到,通过sun.__proto__在sun的prototype原型链上找fatherShow方法
3 如果没有找到,因为sun.prototype上没有,因为Sun.prototype = new Father();在Father.prototype上找这个方法。
原型链继承 直接继承
Sun.prototype = Father.prototype;我们相当于跳过了Father这个构造函数,直接让Sun.prototype跟Father.protype建立联系。
缺点:
- 但是这样sun上以前挂载showSun()就调用不到了。
- 任何对sun.prototype的修改都会反映到father.prototype上 。 优点:
- 不用和Father()建立联系,节省了内存。
function Father() {
this.name = 'father'
}
Father.prototype.fatherShow = function () {
console.log('father show')
}
function Sun() {
this.name = 'sun'
}
Sun.prototype.showSun = function () {
console.log('sun show')
}
Sun.prototype = Father.prototype;
Sun.prototype.play =function () {
console.log('sun play')
}
var sun = new Sun();
sun.fatherShow()
console.log(Sun.prototype)
console.log(Father.prototype.constructor)
原型链继承 通过new Father()
Sun.prototype = new Father(); 让Sun的原型对象是 Father的实例对象,这样Sun.prototype就可以顺着__proto__找到Father.prototype.
function Father() {
this.name = 'father'
}
Father.prototype.fatherShow = function () {
console.log('father show')
}
function Sun() {
this.name = 'sun'
}
Sun.prototype.showSun = function () {
console.log('sun show')
}
Sun.prototype = new Father();
Sun.prototype.play =function () {
console.log('sun play')
}
var sun = new Sun();
sun.fatherShow()
//console.log(Sun.prototype)
console.log(Father.prototype)
通过call()或者apply() 方法实现继承。
这种通过call或者apply的继承,只能访问到Father上的属性,要是访问Father原型链上的方法是做不到的。
function Father(name) {
this.name = name
}
Father.prototype.fatherShow = function () {
console.log('father show')
}
function Sun() {
Father.call(this,'kira')
Father.apply(this,['kira'])
}
var sun = new Sun();
console.log(sun.name)
Class的本质
- 1 class本质是function
- 2 类的所有方法都定义在类的prototype属性上
- 3 类创建的实例里也有__proto__ 指向类的prototype原型对象
- 4 ES6的类其实就是语法糖。
使用 class 和 extends
class Father {
constructor(name,age) {
this.name = name
this.age = age
}
info(){
return `名字${this.name},年龄${this.age}`
}
say(){
return 'fatherSay'
}
}
class Sun extends Father{
constructor() {
// 通过super()关键字可以调用父类的constructor构造函数,给name 和 age赋值。
super调用父类,可以调用父类的普通函数,也可以调用父类的构造函数。
super('kira',25);
}
say() {
return super.say();
}
}
const sun = new Sun();
console.log(sun.info())
static 静态方法和属性
定义在类上,而不是定义在类的原型上,类可以调用,类的实例不能调用的方法就叫做静态方法
var Animal = function(){};
//该name为静态属性,只能通过Animal来访问,不能通过实例访问。
Animal.name = "dog";
var a = new Animal();
console.log(a.name)
// 打印 underfind
console.log(Animal.name)
// 打印 dog
ES2015规定使用static关键字即可定义一个静态方法
- 使用实例对象调用方法,方法中的this指向此实例对象。
- 如果使用类调用静态方法,那么静态方法中的this指向类本身。
class Antzone{
static show(){
console.log("蚂蚁部落");
}
}
let ant=new Antzone();
Antzone.show(); // 打印 蚂蚁部落
ant.show();// typeError is not a function
ES2015新增extends关键字,可以实现类之间的继承。
不但可以继承父类的实例属性与实例方法,静态属性与静态方法也会被继承。
class Father{
static func(){
console.log("蚂蚁部落");
}
}
Father.address="青岛市南区";
class Sun extends Father{
}
Sun.func();
console.log(Sun.address);
//打印结果
蚂蚁部落
青岛市南区
var sun = new Sun();