1.类
<!-- 类是对象的模版定义一个对象有哪些属性和方法 -->
<script>
class Person {
//直接在类中定义属性
// name = 'www';
// age = 12;
//这里写死了 我们可以构造函数
//构造函数当我们通过new创建对象时,实际上就是在调用类的构造函数
constructor(name, age) {
//参数赋值给属性 通过this引用当前对象
this.name = name;
this.age = age
} //方法也是直接定义
//1.定义实例方法
run() {
console.log('iam running');
}
}
const per = new Person('孙', 18)//以Person为模版创建一个对象
// const per2 = new Person()
console.log(per);
// console.log(per === per2);//输出false ,属性一样
// per.run()
</script>
</body>
首先类就是我们用class声明,然后定义的对象模板,我们直接在类中定义属性,编辑但是这样会写死,我们在用new Person()去创建对象的时候,我们创建的对象name和age都是这个,这显然不符合我们的需求,但是我们在用new Person去创建对象的时候,实际上调用的是类模板对象中的constructor构造函数,它去帮我们引用类里面的对象赋值给我们的per,所以我们只需要写consrtuctor构造函数去获取参数,然后用this实例对象(指向new生成的那个对象)去添加name age 值为参数。这样就可以动态的去定义对象了,方法也是我们定义方法其实是在this实例对象定义的,都会赋值给per这个对象。
2.类的this
class MyClass {
//类中的所有代码都会在严格模式下进行
//严格模式下的一个特点就是函数的this不再是window,而是undefined
fn() {
console.log(this);
}
// fn = () => {
// console.log(this);
// }
}
const mc = new MyClass()
mc.fn()//这里的this指向mc因为mc调用类
const TEST = mc.fn
TEST()//undefined 因为类里面的方法中的this不是固定的,方法形式调用就是当前实例 函数形式调用就是undefined
//开发的时候我们可以用 this.fn = this.fn.bind(this)去给fn添加一个方法bind绑定this
//也可以直接使用箭头函数,如果类中的方法以箭头函数定义的,this永远都是当前实例,不会改变
//所以尽量用箭头函数去定义方法
const a = function () {
console.log(this);
}
console.log(a());//这里是window因为不是严格模式
因为类的所以代码都是严格模式进行,所以this指向的是undefined,但是如果我们通过new生成的对象,会把this指向mc,因为mc调用类去给自己赋值。如果用普通函数就会一直undefined,严格模式下会是undefined,但是如果用箭头函数的话本身没有this而且指向外层作用域(构造函数),那么this就会始终是当前实例,new给谁赋值就指向谁。
3.类的继承
<script>
//希望将多个类重复代码提取出来
class Animal {
constructor(name, age) {
this.name = name,
this.age = age
}
say = () => {
console.log('???');
}
}
//通过继承可以使类中拥有其他类的属性和方法
//使用extends继承,相当于把该类的代码复制到当前类中
//当我们继承之后,被继承的类是父类,继承的子类
class Dog extends Animal {
// constructor(name, age) {
// this.name = name,
// this.age = age
// }
// say = () => {
// console.log('wwww');
// }
//可以创造同名的属性和方法进行重写
say = () => {
console.log('wawawa');
}
}
class Snake extends Animal {
// constructor(name, age) {
// this.name = name,
// this.age = age
// }
// say = () => {
// console.log('sss');
// }
//当在子类重写父类构造函数时,必须在子类构造函数第一时间调用父类构造函数
constructor(name, age, length) {
super(name, age);
this.length = length
}
say = () => {
console.log('sisiis');
}
}
const dog = new Dog('忘', 5)
const snake = new Snake('she', 4, 3)
console.log(dog.name, dog.age);//输出的是忘 5
console.log(snake.name, snake.age, snake.length);
dog.say()
snake.say()
</script>
我们这里的类 dog和snake有大量重复的地方,比如构造函数,我们就给他们搞一个父类把一样的内容定义好然后子类继承就可以了。子类如果继承之后想改变就需要去重新定义,比如snake我们希望添加一个新的属性length那么就需要去用super调用父类构造函数,然后在添加新的length属性。
4.类的静态方法和属性
// 直接通过类调用方法和属性称呼静态属性和方法
class Myclass {
// name = 'hah';
// fn = () => {
// console.log('hah');
// }
//类里面都是实例对象和方法必须通过new才能叫做实例比如mc
//我们用静态属性和静态方法
static name = 'hah'
static fn = () => {
console.log(hah);
}
//静态属性和方法可以直接用类调用但是静态方法就this不是实例对象了而且当前的类对象
}
// const mc = new Myclass()
// console.log(mc.name);
console.log(Myclass.name);
当我们希望通过类调用方法和属性的时候,我们就需要用static去声明这是一个静态属性和方法,但是这就不是this实例对象了而是当前的类对象。
5.模块化
//这就是一个模块
const a = 'm1中的变量a'
export const b = 19 //命名导出b
export const obj = {
name: 's'
}
export const fn = () => {
console.log('我是一个module');
}
// 作为一个模块,不是所有内容都需要暴露给外部
//作为导入方 希望导入无用的变量
//export 导出
//决定一个模块中那些内容可以被外部查看
//默认导出 export default xxx 一个模块中只能有一个默认导出和命名导出
export default a;
//命名导出 直接在想要导出的内容前加export
//或者一起导出 export {fn,b,obj}
//变量a默认导出暴露
//导入 import 导入默认模块时,可以自主指定变量名,无需和模块中的变量名对应
//在网页中导入模块,模块的路径必须写完整 ./或者../开头扩展名也需要写上
//导入外部模块中的内容到当前模块中
<!-- <script src="./m1.js"></script> -->
<!-- 直接引入相当于复制过来了意味着这个模块所有的代码都暴露所有内容给web -->
<!-- 默认情况下 sc标签不能使用import语句,如果想要支持模块化,必须设置type为module -->
<script type="module">
//导入m1中的默认模块
// import a from './m1.js'
// //导入指定内容,导入b和obj 也可以加as改名字
// import { b as ooo, obj } from './m1.js'
import a, { b, obj, fn } from './m1.js'
console.log(a, b, obj, fn);
</script>
<!-- //Cannot use import statement outside a module 报错因为不能在模块外面使用导入 -->
</head>
这里的js就是一个模块,我们在里面定义的变量和方法都可以通过默认暴露和命名暴露的方式去暴露,然后我们在html就可以用import去引入然后就可以使用暴露的变量和方法,命名暴露引入需要{},默认暴露不用{}而且可以随意命名,命名暴露需要用as去更改变量名。而且我们要引入js之前需要声明js的类型是module。