JavaScript 进阶 33 - 用ES5的代码模拟ES6的类的特性
es6类的特性
- 不能直接调用类,必须通过new 来调用,不使用new调用会报错的
- 有些属性是不可枚举的 ,es5的原型上的方法或属性是可以枚举的
- 使用Object.defineProperty()方法给 原型 添加自定义的属性或方法(给原型上加属性方法)
构造函数
简单来说呢,构造函数就是:通过 new 的方式调用一个函数,该函数就是构造函数。
构造:就是---- 新创建一个具体的对象
自定义构造函数
//自定义构造函数
function Person(){
//函数体
}
let per = new Person();
console.log(per)//Person
一个方法 通过new 来实例化,被实例化的的函数就是构造函数 ,就是 通过new来实例出一个对象,就是构造函数
实例和对象的区别,从定义上来讲:
1、实例是类的具象化产品,
2、而对象是一个具有多种属性的内容结构。
实例都是对象,而对象不全是实例。比如:动物 --就是- 对象。 狗 --就是- 实例(具体对象)。
this的指向问题
//this的指向问题
function Person(name,age){
console.log(this);//Person{} 相当于 this ==={}
this.name = '中国人';
}
let per = new Person();
console.log(per);//Person{}
new Person()做了什么事情:
- 在函数内部创建一个空对象,
- 让this指向此空对象
- 把函数执行完,
- 返回这个对象
function Person(name,age){
this.name = name;
this.age = age;
}
let per = new Person('lily','33');
console.log(per);//Person { name: 'lily', age: '33' }
【例 3 】模拟es6类的特性 必须用new才能调用类
//【例 3 】模拟es6类的特性 必须用new才能调用类
let Person =(function(){
function Person(){
if(!(this instanceof Person)){
//如果 this不是person的实例对象,就抛出错误
throw new Error('can not call class as a function');
}
this.name = 'zhongguoren';
}
return Person;
})();
//Person();//can not call class as a function 不能将class作为函数直接调用
let per = new Person();
console.log(per);//Person { name: 'zhongguoren' }
再来看一个例子
【 例4 】
function Person(){
this.name = 'zhongguoren';
this.eat = function(){
console.log('eating');
}
}
let p = new Person();
p.eat();//eating
let p2 = new Person();
p2.eat();//eating
console.log(p.eat === p2.eat);//false 每个对象都有自己的成员,
上面代码中的 第7行 p 和第 10行的 p2 两家是一模一样的,那就把这种公共的方法定义在原型上,看下面例子
【例5】
function Person(){
this.name = 'zhongguoren';
}
Person.a = 10;//静态属性,直接给类增加的属性、方法等等 ,不用通过new来实例的
console.log(Person.a);//通过构造函数直接访问 就像 Math.max(),max()方法是构造函数Math的静态方法
//原型的属性或方法是公用的,解决了代码复用的问题,这样写 es5的原型是暴露的,且能修改
Person.prototype.eat = function(){
console.log('eat')
}
//在原型上定义,可以上每个实例都能使用
let p = new Person();
let p2 = new Person();
console.log(p.eat === p2.eat)//true
上面的【例4】【例5】 两个例子 属性都是在原型上直接定义的,可以被迭代的。直接加载原型上那就把原型暴露了。说明一个问题:es5的原型是暴露的。为了防止此问题,我们可以使用defineProperty() 如下代码:
因为es6的原型是不允许被访问的,所以,我们可以使用defineProperty() 自定义属性,给原型设置属性或方法。如下代码:
【例6】用es5的代码模拟es6的类的特性 (特性:只能通过new来调用) 用自定义属性的方法在原型上定义属性和方法。
function defineProperty(Constructor,protoProperties){
//判断一下是不是数组
if(Array.isArray(protoProperties)){
for(let i = 0; i < protoProperties.length; i++){
let protoProperty = protoProperties[i];
//代码的核心就是Object.defineProperty()这个方法,构造函数的原型
Object.defineProperty(Constructor.prototype,protoProperty.key,{
configurable:true,
enumerable:false,
...protoProperty
})
}
}
}
let Person =(function(){
function Person(){
//通过new 和不通过new 函数里的this的指向是不同的,所以通过判断this到底是new还是直接去引用的
if(!(this instanceof Person)){
//如果 this不是 构造函数person 的实例对象,就抛出错误(如果不是实例对象,说明是直接调用的,就抛个错误
throw new Error('can not call class as a function');
}
this.name = 'zhongguoren'; //如果是实例,就给这个实例 加一个属性name
}
//定义原型属性,在原型上定义属性 都放在数组中。
// 第一个参数:给谁定义,给构造函数的原型
// 第二个参数:公共参数,公共的方法或者属性 这里是个数组,里面有许多的属性和属性名
defineProperty(Person,[
{
key:'eat',
value:function(){
console.log('eating')
}
},{
key:'sing',
value:function(){
console.log('singing')
}
}
])
return Person;
})();
let per = new Person();
console.log(Person.prototype);//Person {} 不能被访问时是空的,但是可以被调用
per.eat();//eating
per.sing();//singing
【例 7 】es6类的特性 给类增加静态属性 如:Person.aa 。就像我们常用到的 函数 Math.max()。.max()可以说是构造函数Math的静态属性
//定义属性 target:给谁定义,props:加哪些属性
function _definepts(target,props){
for(let i = 0; i < props.length; i++){
let protoProperty = props[i];
//代码的核心就是Object.defineProperty()这个方法,构造函数的原型
Object.defineProperty(target,protoProperty.key,{
configurable:true,
enumerable:false,
...protoProperty
})
}
}
function defineProperty(Constructor,protoProperties,staticProperties){
//判断一下数组 是不是 在原型上定义的 方法
if(Array.isArray(protoProperties)){
_definepts(Constructor.prototype,protoProperties)
}
//判断数组 是不是 在类上直接添加的 静态属性
if(Array.isArray(staticProperties)){
_definepts(Constructor,staticProperties)
}
}
let Person =(function(){
function Person(){
//通过new 和不通过new 函数里的this的指向是不同的,所以通过判断this到底是new还是直接去引用的
if(!(this instanceof Person)){
//如果 this不是 构造函数person 的实例对象,就抛出错误(如果不是实例对象,说明是直接调用的,就抛个错误
throw new Error('can not call class as a function');
}
this.name = 'zhongguoren'; //如果是实例,就给这个实例 加一个属性name
}
//定义原型属性,在原型上定义属性 都放在数组中。
// 第一个参数:给谁定义,给构造函数的原型
// 第二个参数:公共参数,公共的方法或者属性 这里是个数组,里面有许多的属性和属性名
// 第三个参数:静态属性或者方法(私有的 )
defineProperty(Person,[
{
key:'eat',
value:function(){
console.log('eating')
}
},{
key:'sing',
value:function(){
console.log('singing')
}
}
],[
{
key:'aa',
value:100
}
])
return Person;
})();
let per = new Person();
console.log(Person.aa)//100
per.eat();//eating
per.sing();//singing
好啦 这一篇先到这里。我的文章都是学习过程中的总结,如果发现错误,欢迎留言指出,我及时更正
本文地址:https://blog.csdn.net/dingdinglaila/article/details/112546725
上一篇: MySQL使用聚合函数进行单表查询