es6 class定义类、单例类

es5 new 过程

  • 首先开辟内存空间,创建一个新的空对象
  • 然后将空对象的原型指向构造函数的原型
  • 调用构造函数并改变 this 的指向,指向空对象
  • 对构造函数的返回值做判断,如果返回类型为非对象则返回之前创建的对象,否则返回构造函数返回的对象
// 实现 new 操作符
function myNew(fn, ...args) {
  // 创建一个空对象
  const obj = {};
  // 将该对象的原型链接到构造函数原型对象
  Object.setPrototypeOf(obj, fn.prototype);
  const res = fn.apply(obj, args);
  // 如果返回值存在并且是引用数据类型,返回构造函数返回值,否则返回创建的对象
  return typeof res === "object" ? res : obj;
}

// TODO: 构造函数被执行
function Person(name) {
  console.log("constructor");
  this.name = name;
}Person.prototype.say = function () {
  console.log("My name is", this.name);
};const c = myNew(Person, "b");
c.say(); // "b"

语法

  • 一般方法会被放到类的原型上,实例的原型会指向(等于)类的原型
  • 静态方法或属性会放到类的属性上
class 类名{

	xx=2;	// xx 会被绑定到 this 上
	
	static fn=function(){} // 静态属性或方法
	
	//构造器
	constructor(params)
	{
		this.xx = xx;
	}
	
	fn(){
		...
	}
}
class Parent {
  constructor() {
    this.sex = "boy";
  }

  static s = "ww";

  getSex() {
    console.log(this.sex);
  }
}

const p =new Parent();
Object.getPrototypeOf(p) === Parent.prototype; // true

在这里插入图片描述

  • 构造函数有返回值

    • 如果 return 出去一个对象,则实例的属性只有该对象,且实例不再是该类的实例
    • 如果 return 其他类型,会返回一个空对象
class F {
  constructor() {
    return { name: "d" };
  }

  dd() {
    console.log("dd");
  }
}

const f = new F();
console.log(f); // { name: 'd' }
f.dd(); // 报错

  • 省略构造函数

class Child extends Parent {}

// 等同于
class Child extends Parent {
    constructor (...args) {
        super(...args)
    }
}
  • new.target

    • 构造函数中调用 new target 会返回当前类本身,子类 super 调用父类构造器中的 new target 会返回子类
class F{
	constructor(){
		if(new.target === F){ // true
			// ...
		}
	}
}

es6类创建私有属性

  • # 关键字

class X{
	#x(){}	通过#前缀声明私有属性
}

  • Symbol 声明属性

 const fn=Symbol('xx');
 class C{
 	[fn](){ // 在其他模块中,因为无法获取 Symbol 值,所以获取不到 C 中的 Symbol 属性或方法
 		...
 	}
 }
  • 缺点:可以通过 Object.getOwnPropertySymbols 获取到对象上的 symbol 属性
const fn = Symbol("xx");
class C {
  constructor() {
    this[fn] = "ww";
  }
}

const c = new C();

console.log(c[Object.getOwnPropertySymbols(c)[0]]); // "ww"

  • 闭包

class A{
	constructor(param){
		const privateA=param.a
		this.getPrivate=(){
			return privateA
		}
	}
}

cosnt a = new A('a');
a.privateA // undefined
a.getPrivate() // 'a'

继承

  • extends

    • 会将父类放在子类的原型上,所以子类也能调用父类的静态方法
    • extends 的目标只要是一个有 prototype 的函数就行,不一定要是个class
class Parent {
	static p ='w'
}

class Child extends Parent {}

Object.getPrototypeOf(Child) === Parent;	// true
Child.p; // 'w'
  • super

    • 当做函数使用:代表父类的构造方法
      • super 在构造函数中只能放在第一行且不能省略,因为是先构造父实例,再修改 this
      • super 内部的 this 指向子类,相当于是 Parent.constructor.call(this)
    • 当做对象使用
      • 普通方法中:指向父类原型对象,故只能调用一般方法,不能调用静态方法或属性
      • 静态方法中:在子类的静态方法中 super 对象指向父类
class Parent {
  constructor () {
    this.name = 'parent'
  }
}
class Child extends Parent {
  constructor () {
    // super(name) // Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor at new Child

  }
}
  • 报错原因:ES6 中实质是先创造父类的实例对象 this(也就是使用 super() ),然后再用子类的构造函数去修改 this

继承方法总结

创建只能继承,不能实现的父类

class F{
	constructor(){
		if(new target === F){
			throw new Error('xx')
		}
	}
}
class Z{
	constructor(){
		super();
	}
}
const z=new Z();

单例类

export default class Sc{

  static instance = null;
  
  static Instance() {
    if (!this.instance) {
      this.instance = new Sc()
    }
    return this.instance
  }

}

创建只能通过new 创建实例,不能通过()调用

function Vue (options) {
  // 保证了无法直接通过Vue()去调用,只能通过new的方式去创建实例
  if (!(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword');
  }
  this._init(options);
}

代码示例:

<html ng-app='app' ng-controller='main' >
<head>
	<meta charset="utf-8">
	<meta name='viewport' content='width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0'>

	<script src='jq/jquery-3.4.1.js'></script>

	<style>

	</style>
</head>
<body >


<script>
class Person
{
	//类的构造方法
	constructor(name,age)
	{
		this.name=name;
		this.age=age;
	}

	//类的一般方法
	show()
	{
		console.log(this.name);
	}
}

//子类
class Jeff extends Person{
	constructor(name,age,address){
		super(name,age);//调用父类的构造方法
		this.address=address;
	}

	show(){
		console.log(this.address+this.name);
	}

}
let person=new Person('jeff',18);
let jeff=new Jeff('jim',18,'where');
console.log(jeff);
jeff.show();



</script>
</body>
</html>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值