ES5
es5并没有类class,我们只能用构造函数来模拟类.
构造函数
构造函数用new操作符一起使用.new具体做了以下事情.
1.new在内存中创建了一个新的空对象.
2.让this指向了这个对象.
3.执行构造函数里的代码,给这个新的对象增加属性和方法.
4.返回这个新对象,隐式return.
//构造函数
function Animal(){
this.name='动物' //实例属性
}
//每个创建出的实例身上都带有name属性,this指向这个实例创建的对象.
let animal=new Animal();
animal.name='动物1'
let animal1=new Animal();
console.log(animal1.name) //动物
//如果手动返回一个引用类型this就会指向这个引用类型
function Animal(){
this.name='动物'
//this指向返回这个对象
return {
a:2
}
}
let animal=new Animal(); //{a:2}
console.log(animal.name) //undefined
静态属性
function Animal(){
}
//静态属性
Animal.attr='12'
//静态方法
Animal.say=function(){
return 11111
}
console.log(Animal.attr) //12
console.log(Animal.say()) //11111
原型prototype(每个类都有prototype,是一个对象)
function Animal(){
}
//公共方法 每个实例上都会带有这方法
Animal.prototype.say=function(){
return 'say'
}
Animal.prototype.attr='attr'
let animal=new Animal();
let animal1=new Animal();
console.log(animal.say===animal1.say) //true 所有的实例都指向这个地址
console.log(animal.say()) //say
console.log(Animal.prototype) //Animal { say: [Function], attr: 'attr' }
_ _proto _ _ (实例 _ _ proto _ _ 指向所属类的原型,用来查找属性和方法)
console.log('123'.__proto__)
console.log({}.__proto__)
let num=123
console.log(num.__proto__)
let bol=true;
console.log(bol.__proto__)
//结果
//[String: '']
//{}
//[Number: 0]
//[Boolean: false]
//null undefined error
function Animal(){
}
Animal.prototype.say=function(){
return 'say'
}
Animal.prototype.attr='attr'
let animal=new Animal();
console.log(animal.__proto__);// Animal { say: [Function], attr: 'attr' } 指向实例所属类的原型对象
// 查找顺序先找自身 自身没有再去查找所属类的原型对象
console.log(animal.__proto__===Animal.prototype); //true
构造函数constructor(prototype里包含一个constructor属性)
function Animal(){
}
let animal=new Animal()
console.log(animal.__proto__.constructor)//[Function: Animal]
console.log(Animal.prototype.constructor) //[Function: Animal]
原理
无标题.pngObject.prototype
无标题.pngclass Animal{
}
let animal=new Animal()
console.log(Animal.prototype.__proto__===animal.__proto__.__proto__) //true
console.log(Animal.prototype.__proto__===Object.prototype) //true
console.log(animal.__proto__.__proto__===Object.prototype) //true
console.log(Function.prototype.__proto__===Object.prototype) //true
console.log(Array.prototype.__proto__===Object.prototype) //true
console.log(Function.__proto__===Object.__proto__) //true
console.log(Object.prototype.__proto__) //null Object已经是顶层了
继承
1.实例属性继承
function Animal(name){
this.name=name
}
function Tiger(){
//this指向Tiger实例
Animal.call(this,'老虎')
}
let tiger=new Tiger();
console.log(tiger.name) //老虎
2.原型继承
function Animal(name){
this.name=name
}
Animal.prototype.say=function(){
return 'say'
}
function Tiger(){
//this指向Tiger实例
Animal.call(this,'老虎')
}
//这种方式不可采 把Tiget的指向Animal.prototype会造成子类和父类同引用一个内存地址 子类原型改变会影响父类
Tiger.prototype=Animal.prototype
//这样不会改变子类的原型 先从子类查找 子类查找不到再去父类原型查找 不会污染父类 可以在自己子类原型增加方法
Tiger.prototype.__proto__=Animal.prototype
let tiger=new Tiger();
console.log(tiger.__proto__) //Tiger {}
console.log(tiger.say()) //say
2.1 object.create继承
function Animal(name){
this.name=name
}
Animal.prototype.say=function(){
return 'say'
}
function Tiger(){
//this指向Tiger实例
Animal.call(this,'老虎')
}
//tiger.constructor指向的是父类
Tiger.prototype=Object.create(Animal.prototype)
//设置constructor tiger.constructor指向自己
Tiger.prototype=Object.create(Animal.prototype,{constructor:{value:Tiger}})
let tiger=new Tiger();
console.log(tiger.__proto__.constructor)
console.log(tiger.say())
2.2 模拟object.create
function Animal(name){
this.name=name
}
Animal.prototype.say=function(){
return 'say'
}
function Tiger(){
//this指向Tiger实例
Animal.call(this,'老虎')
}
function create(prototypes,constr){
function Fn(){
}
Fn.prototype=prototypes;
if(constr&&constr.constructor.value){
Fn.prototype.constructor=constr.constructor.value
}
return new Fn()
}
Tiger.prototype=create(Animal.prototype,{constructor:{value:Tiger}});
Tiger.prototype.say=function(){
return 'Tiger say'
}
let tiger=new Tiger();
console.log(tiger.__proto__.constructor) //[Function: Tiger]
console.log(tiger.say()) // Tiger say
console.log(Animal.prototype.say()) //say
object.create实现原理
无标题.pnges6类(class)
class Animal{
}
let animal=new Animal();
console.log(animal)
静态属性(通过类自身调用)
class Animal{
static attrs='attrs'
static say(){
return 'say'
}
}
console.log(Animal.attrs) //attrs
console.log(Animal.say()) //say
class Animal{
static attrs='attrs'
constructor(){}
say(){
return 'say'
}
}
class Tiger extends Animal{
constructor(){
}
}
console.log(Tiger.attrs) //attrs
实例属性
//没有写contructor情况下 增加属性 会默认执行constructor把属性添加到实例上
class Animal{
attrs='attrs' // 注意!!这里定义的不是在prototype上的属性,而是给实例初始化的 实例属性
}
let animal=new Animal();
console.log(animal.attrs)
class Animal{
constructor(){
this.attrs='attrs' //实例属性
}
}
let animal=new Animal();
console.log(animal.attrs)
prototype(定义在类里 es6的原型是不可枚举的)
class Animal{
constructor(){}
say(){
return 'say'
}
}
let animal=new Animal();
console.log(Animal.prototype.say) //[Function: say]
私有属性(ES2020实验草案中,增加定义私有类字段功能,使用# ,私有属性无法在类的外部调用)
//私有属性
class Animal{
#privateValue="私有"
}
//私有方法
class Animal{
#privateValue(){
return 'private'
}
}
//私有静态属性
class Animal{
statci #privateValue="私有"
}
//可以在类的内部使用,无法在类的外部使用
calss Animal{
#attrs='11111'
#bac(){
Animal.#attrs="22222"
}
}
console.log(Animal.#bac) //error
继承(extexds)
//子类不写constructor会默认执行父类的constructor
class Animal{
constructor(attrs){
this.attrs=attrs
}
say(){
return 'say'
}
}
class Tiger extends Animal{
}
let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
console.log(tiger.__proto__.say) //[Function: say]
//子类写constructor,默认走子类的构造函数
class Animal{
constructor(attrs){
this.attrs=attrs
}
say(){
return 'say'
}
}
class Tiger extends Animal{
constructor(attrs){
super(attrs) //等同于 Animal.call(this,attrs) 不调用super会报错
}
}
let tiger=new Tiger('tiger attrs');
console.log(tiger) //Animal { attrs: 'tiger attrs' }
console.log(tiger.__proto__.say) //[Function: say]
//子类和父类定义相同的方法,会先执行子类 子类没有才会向类查找
class Animal{
constructor(attrs){
this.attrs=attrs
}
say(){
return 'say'
}
}
class Tiger extends Animal{
constructor(attrs){
super(attrs) //等同于 Animal.call(this,attrs)
}
say(){
return 'tiger say'
}
}
let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
console.log(tiger.say()) // tiger say
//子类调用父类方法
class Animal{
constructor(attrs){
this.attrs=attrs
}
say(){
return 'say'
}
}
class Tiger extends Animal{
constructor(attrs){
super(attrs) //等同于 Animal.call(this,attrs)
}
say(){
return super.say() //等用于 Animal.prototype.say() //super===Animal.prototype
}
}
let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
console.log(tiger.say()) //say
//静态方法调用
class Animal{
constructor(attrs){
this.attrs=attrs
}
static say(){
return 'say'
}
}
class Tiger extends Animal{
constructor(attrs){
super(attrs) //等同于 Animal.call(this,attrs)
}
static say(){
return super.say() //super等用于Animal类 //super===Animal
}
}
console.log(Tiger.say()) //say
抽象类(只可继承,不可被实例化new)
1.new.target实现抽象类
class Animal{
constructor(){
//执行两次 1.new.target=[Function: Animal] 2.new.target[Function: Tiger]
if(new.target===Animal){
throw new Error('not new')
}
}
}
class Tiger extends Animal{
}
new Animal() //Error: not new
let tiger=new Tiger();
es5构造函数模拟实现es6(原型属性不可枚举)
function handleConstructor(Constructor,protoProperties){
for(let i=0;i<protoProperties.length;i++){
let property=protoProperties[i]
Object.defineProperty(Constructor,property.key,{
//是否可以删除
configurable:true,
//是否可以枚举
enumerable:false,
...property
})
}
}
// console.log(Eat.prototype) //不可枚举
function definePrototype(Constructor,protoProperties,staticPorto){
if(Array.isArray(protoProperties)){
handleConstructor(Constructor.prototype,protoProperties)
}
if(Array.isArray(staticPorto)){
handleConstructor(Constructor,staticPorto)
}
}
//es5的类 模拟es6的类 不可枚举 Object.definprototype
let Animate=(function(){
function Animate(){
if(!(this instanceof Animate)){
throw new Error('not new')
}
}
//改变原型不可枚举 babel编译出es6的类就是这样写的
definePrototype(Animate,[
{
key:'say',value:function(){
console.log('say')
}
}
],[
//静态属性
{
key:'eat',value:function(){
return 'eat'
}
}
])
return Animate
})()
console.log(Animate) //[Function: Animate]
console.log(Animate.prototype) //Animate {}
console.log(Animate.eat()) //eat
instanceof
instanceof运算符是用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上.
//obj instanceof Object 检测Object.prototype是否存在与参数obj的原型链上.
function Person(){}
let p=new Person();
//p.__proto__==Person.prototype
console.log(p instanceof Person) //true
hasOwnProperty()操作符
hasOwnProperty检查一个属性是否是实例属性.
//实例属性
function Animal(){
this.name='name'
}
let animal=new Animal();
console.log(animal.hasOwnProperty('name')) //true
//不查看原型属性,只看实例属性
function Animal(){
}
Animal.prototype.name='123'
let animal=new Animal();
console.log(animal.hasOwnProperty('name')) //false
in操作符
有两种方法能使用in操作符:单独使用for-in循环使用.在单独使用时,in操作符会通过对象能够访问给定属性返回true,无论属性存在(实例)还是(原型中).
function Animal(){
this.name='name'
}
let animal=new Animal();
console.log('name' in animal) //true
function Animal(){
}
Animal.prototype.name='123'
let animal=new Animal();
console.log('name' in animal) //true
function Animal(){
}
let animal=new Animal();
console.log('name' in animal) //false
网友评论