文章目录
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
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)
}
}
class F{
constructor(){
if(new.target === F){ // true
// ...
}
}
}
es6类创建私有属性
class X{
#x(){} 通过#前缀声明私有属性
}
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'
继承
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>