简单理解ES5原型

150 阅读4分钟

这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

1.为什么要有原型?

function Student(name,age){
    this.name=name;
    this.age=age;
​
    this.commonTeacher=["李四","张三","王二麻子"];
    this.showName=function(){
        console.log("我的名字是",this.name)
    }
​
    this.showCommonTeacher=function(){
        console.log("我的老师有",this.commonTeacher)
    }
}
​
 const student1=new Student("学生1",18)
 const student2=new Student("学生2",19)
​
 student1.showCommonTeacher();//我的老师有 [ '李四', '张三', '王二麻子' ]
 student2.showCommonTeacher()//我的老师有 [ '李四', '张三', '王二麻子' ]

可以看出通过构造函数(使用了new的函数就是构造函数)创建的实例,他们的公共属性commonTeacher是完全一样的属性,分开创建实例的话,会开辟两个堆空间,那么使用原型的话,可以使用同样的堆地址赋值不同的实例,通过堆地址寻址找到同一个堆空间(commonTeacher)

image.png

2.如何使用原型?

原型上的方法和属性都可以被构造函数的实例所共享。原型可以理解为是一个共用对象,被现有对象所继承了

function Student(name,age){
    this.name=name;
    this.age=age;
    this.showName=function(){
        console.log("我的名字是",this.name)
    }
}

Student.prototype.commonTeacher=["李四","张三","王二麻子"];
Student.prototype.showCommonTeacher=function(){
    console.log("我的老师有",this.commonTeacher)
}

 const student1=new Student("学生1",18)
 const student2=new Student("学生2",19)

 student1.showCommonTeacher();//我的老师有 [ '李四', '张三', '王二麻子' ]
 student2.showCommonTeacher();//我的老师有 [ '李四', '张三', '王二麻子' ]

每创建一个实例就会默认给他添加一个__proto__属性,这个属性装了一个堆地址,指向构造函数的原型对象

image.png

那也就是说Student.prototype===student1.__ proto__===student2.__ proto__

经典例子1表现堆地址的考题

解释:地址的转移,并不是空间内容的覆盖,相当于obj变量的地址分给objnew变量,现在objnew指向obj的堆地址,实际堆内容为{username:'u',age:20}。后面obj变量又被赋与了一个新的对象堆地址,内容为{username:'a',age:18}。

let obj={username:'u',age:20}; 
const objnew=obj;
obj={username:'a',age:18}; 
console.log("obj",obj);//{username:'a',age:18}
console.log("objnew",objnew);//{username:'u',age:20}

经典例子2 原型对象的覆盖

function F(a,b,c){ this.a=a; this.b=b; this.c=c } 
F.prototype.common=[1,2,3,4];
F.prototype.common.push(5) 
const f=new F(1,2,3); 
F.prototype={a:"a",b:"b"}; 
console.log(f.common)//[ 1, 2, 3, 4, 5 ]

解释:实例化在前,先创建的实例对象f,里面有一个__proto__指向目前F.prototype地址指向的堆空间,这个时候F.prototype地址变量被替换成新地址了,也就是指向变了,那么原来的f.__ proto__指向的空间不会被垃圾回收掉,因为实例化有变量指向了它。

3.ES6类

写在一个类上的属性一定要设计为和类强关联的,给对象赋值的方法,属性(public)或者方法,构造器

在类中一共做了三件事

第一件事:在堆中为类的实例分配一个内存空间

第二件事:调用对应的构造函数【构造器】。会自动匹配几个参数的构造器,否则报错提示(有重载除外)

第三件事:把对象赋值给对象变量

"use strict";
class Person {
    constructor(name, age) {
        this.name = "name";
        this.age = 23;
        this.strArray = ["12", "23"];
        this.strArray2 = [1, "2"];
        this.f = () => { };
        this.name = name;
    }
    doEat(a, b) {
        console.log("a", "b", a, b);
    }
}
const p = new Person("神说要有光_zy", 23);
let a = { username: "神说要有光_zy2", age: 321 };

4.TS类

由3中Es6中类可以延伸出来TS的类,主要是在Es6上面做了属性修饰,类型控制,借鉴了java的很多强类型的特性过来,这样极大的丰富了类。可以是开发者在开发的时候规避很多错误

class Person {
  private name: string = "name";
  public age: number = 23;

  public strArray: string[] = ["12", "23"];
  public strArray2: Array<string | number> = [1, "2"];

  public f: () => void = () => {};

  public doEat(a: string, b: string): void {
    console.log("a", "b", a, b);
  }
  constructor(name: string, age: number) {
    this.name = name;
  }
}

const p = new Person("神说要有光_zy", 23);

let a = { username: "神说要有光_zy2", age: 321 };

5.配置TS和ES6和ES5同代码的对比环境

5.1 使用pracel打包工具

pracel打包工具配置相比于webpack及其简单

1.全局安装

> npm install -g parcel-bundler

2.新建一个index.html,引入一个index.ts文件

3.配置npm script工作流命令"build": "parcel ./index.html"

4.运行npm run build就成功进行打包,并且index.html打包后直接加载的js文件,可以进行网页调试

5.2 配置Ts环境

1.使用tsc --init配置基本的Ts环境目录,生成tsconfig

2.关注rootDir(输入目录),outDir(输出目录),target:'es6',等等都可以更改打包后的代码相对比,在ts.config同级目录下进行tsc,会根据ts.config自动将输入目录中打包成js文件

3.使用nodemon监听,ts-node配置dev环境,下面这命令的意思是监听src下面的改变,就是用ts-node执行index.ts

"nodemon --watch src/ -e ts --exec ts-node src/index.ts"