es5中没有类,我们是用构造函数来模拟类
缺点:
es5中的类可以当做函数来调用,es6不行
属性:1、实例上的属性 2、公共属性
对象有自己的属性,属性的属性值可以为任何的内容,当属性值为函数的时候,我们称之为方法。当属性质为对象的时候,称之为子对象
使用构造函数模拟类
function Animal(){
if(!(this instanceof Animal)){ // 当前是不是通过new来调用的
throw new Error('NOT NEW')
}
this.name = {name:'zf'}; //实例上的属性
this.age = 10; // 实例上的属性
}
Animal.prototype.say =function(){ // 公共属性
console.log('say')
}
let a1 = new Animal();
let a2 = new Animal();
// // 一般情况下 最好不要直接操作__proto__
// console.log(a1.__proto__ === Animal.prototype);
// console.log(a1.__proto__.constructor === Animal);
// console.log(a1.__proto__.__proto__ === Object.prototype)
// console.log(Object.prototype.__proto__);
继承 ----- 继承实例上的属性 公共属性
function Animal(){
this.type = '哺乳类'
}
Animal.prototype.say = function(){
console.log('我是动物')
}
function Tiger(name){
this.name = name;
Animal.call(this); // 调用父类的构造函数 并且让this指向子类即可( 继承实例上的属性)
}
公共属性继承:
1、Tiger.prototype.__proto__ = Animal.prototype;
2、 Object.setPrototypeOf(Tiger.prototype,Animal.prototype); // es6语法:设置链的指向
3、Tiger.prototype = Object.create(Animal.prototype,{constructor:{value:Tiger}});// Object.create()使用指定的原型对象及其属性去创建一个新的对象,并使新对象的__proto_指向这个原型对象 ,想对于Object.setPrototypeOf唯一有些不同的是他在中间加了一层;
Tiger.prototype=create(Animal.prototype) // 自己实现有个缺点 constructor指向不对
// Object.create如何实现的?
function create(parentProto){
function Fn(){}
Fn.prototype = parentProto;
let fn = new Fn();
fn.constructor = Tiger
return fn;
}
4、Tiger.prototype = new Animal()
Tiger.prototype.proto = Animal.prototype 实现继承过程图:
Object.create如何实现过程图:使子类的原型指向某个类的实例,这个类的原型指向父类的原型
new 的原理
function A(){
this.name = 1;
this.age = 2;
return {c:1} // 如果一个类返回了一个引用空间 那么实例将这个空间
}
console.log(new A())
A.prototype.say = function(){
console.log('say')
}
new的大致实现原理
function mockNew(A){
let obj = {}
let returnVal = A.call(obj);
if((typeof returnVal === 'object' && returnVal !== null) || typeof returnVal === 'function'){
return returnVal;
}
obj.__proto__ = A.prototype
return obj;
}
let o = mockNew(A) // 1) 创建了一个一个对象,并且将对象传入到到函数中作为this
// o.say();
console.log(o);
es6中 类 class
class
声明创建一个基于原型继承的具有给定名称的新类
----声明式
class Polygon {
type='哈哈' // 也是实例上属性,但是没有this了
constructor(height, width) { // 声明实例上的属性
this.area = height * width;
}
say(){ // 放到了原型上 // Animal.prototype.say
console.log(this);
}
get a(){ // 定义原型上的属性 // 实现:Object.defineProperty(Animal.protoype,a)
return 1; // Animal.prototype.a = 1;
}
// 静态属性就是定义到类上的属性 es6中只有静态方法
// static flag = '动物' es7的静态属性
static get flag(){ // es6实现静态属性 (类属性)
return '动物'
}
static plant(){} // es6的静态方法 (类方法)
}
let a=new Polygon(4, 3)
a.area // 12
a.type // 哈哈
---使用类表达式
let Foo = class {
constructor() {}
bar() {
return "Hello World!";
}
};
let instance = new Foo();
instance.bar();
继承—类上的静态属性和静态方法也可以被继承
class Animal{
static flag = 1;
constructor(name){
this.name = name;
this.type = '哺乳类'
}
say(){
console.log('say')
}
}
// 在es5中实现继承:call + Object.create() || Object.setPrototypeOf
es6中:
es6的继承在原理上也是通过call + Object.create() || Object.setPrototypeOf 实现实例属性和公共属性继承,通过Object.defineProperty实现了 原型 + 静态方法属性的定义
class Tiger extends Animal{
constructor(name){
super(name); // 继承必须调用super // 调用super相当于Animal.call(tiger,name);
// super 指代的是父类
// constructor中的super指代的问题
console.log(this)
}
static getAnimal(){
console.log(super.flag,'---'); // 这个super指代的是父类
}
say(){
super.say(); // super 指向的是 父类的原型
}
}
let tiger = new Tiger('老虎');
tiger.say()