类与对象
创建类与对象
- 通过class 关键字创建类, 类名我们还是习惯性定义首字母大写
- 类里面有个constructor 函数,可以接受传递过来的参数,同时返回实例对象
- constructor 函数 只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个函数,类也会自动生成这个函数
<script>
// 1. 创建类 class 创建一个 明星类
class Star {
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
}
// 2. 利用类创建对象 new
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 20);
console.log(ldh);
console.log(zxy);
</script>
在类中添加方法
<script>
// 1. 创建类 class 创建一个 明星类
class Star {
// 类的共有属性放到 constructor 里面
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
sing(song) {
// console.log('我唱歌');
console.log(this.uname + song);
}
}
// 2. 利用类创建对象 new
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 20);
console.log(ldh);
console.log(zxy);
// (1) 我们类里面所有的函数不需要写function
//(2) 多个函数方法之间不需要添加逗号分隔
ldh.sing('冰雨');
zxy.sing('李香兰');
</script>
类的继承
- super调用父类的构造函数
<script>
// 父
class Father {
// 父的构造器
constructor(x, y) {
this.x = x;
this.y = y;
}
// 父的方法
sum() {
console.log(this.x + this.y);
}
}
// 子继承父
class Son extends Father {
// 子的构造器
constructor(x, y) {
// 通过super调用父的构造函数
super(x, y);
}
}
var son = new Son(1, 2);
var son1 = new Son(11, 22);
son.sum(); // 3
son1.sum(); // 33
</script>
- super 关键字调用父类普通函数
继承中的属性或者方法查找原则: 就近原则
- 先去查看子类中是否有方法
- 如果子类没有,再去父类中查看是否有方法
<script>
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
say() {
// console.log('我是儿子');
console.log(super.say() + '的儿子');
// super.say() 就是调用父类中的普通函数 say()
}
}
var son = new Son();
son.say();
</script>
- 子类继承父类方法,同时扩展自己的方法
<script>
// 父类有加法方法
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
// 子类继承父类加法方法 同时 扩展减法方法
class Son extends Father {
constructor(x, y) {
// 利用super 调用父类的构造函数
// super 必须在子类this之前调用。
super(x, y);
this.x = x;
this.y = y;
}
subtract() {
console.log(this.x - this.y);
}
}
var son = new Son(5, 3);
son.subtract();
son.sum();
</script>
类里面this的指向问题
- constructor 里面的this 指向的是 创建的实例对象
- 类中的方法里面的this指向的 谁调用这个方法,指向谁
<button>点击</button>
<script>
var that;
var _that;
class Star {
constructor(uname, age) {
// constructor 里面的this 指向的是 创建的实例对象
that = this;
console.log(this);
this.uname = uname;
this.age = age;
// this.sing();
this.btn = document.querySelector('button');
this.btn.onclick = this.sing;
}
sing() {
// 这个sing方法里面的this 指向的是 btn 这个按钮,因为这个按钮调用了这个函数
console.log(this);
console.log(that.uname); // that里面存储的是constructor里面的this
}
dance() {
// 这个dance里面的this 指向的是实例对象 ldh 因为ldh 调用了这个函数
_that = this;
console.log(this);
}
}
var ldh = new Star('刘德华');
console.log(that === ldh); // true
ldh.dance();
console.log(_that === ldh); // true
// 1. 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象
// 2. 类里面的共有的属性和方法一定要加this使用.
</script>
构造函数和原型
创建对象的三种方式
- 使用构造函数的注意事项
- 构造函数用于创建某个对象, 其首字母要大写
- 构造函数要与new用在一起才有意义
- 使用new创建构造函数所做的事情
- 在内存中创建一个新的空对象
- 让this指向这个空对象
- 执行构造函数的代码,给这个新对象添加属性和方法
- 返回这个新对象(所以构造函数里面不需要return)
<script>
// 1. 利用 new Object() 创建对象
var obj1 = new Object();
// 2. 利用 对象字面量创建对象
var obj2 = {};
// 3. 利用构造函数创建对象
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(ldh);
ldh.sing();
zxy.sing();
</script>
实例成员和静态成员
<script>
// 构造函数中的属性和方法我们称为成员, 成员可以添加
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 18);
// 1.实例成员就是构造函数内部通过this添加的成员 uname age sing 就是实例成员
// 实例成员只能通过实例化的对象来访问
console.log(ldh.uname);
ldh.sing();
// console.log(Star.uname); // 不可以通过构造函数来访问实例成员
// 2. 静态成员 在构造函数本身上添加的成员 sex 就是静态成员
Star.sex = '男';
// 静态成员只能通过构造函数来访问
console.log(Star.sex);
console.log(ldh.sex); // 不能通过对象来访问
</script>
构造函数原型prototype
构造函数存在的一个问题:每次new对象(创建实例)的时候,就会在内存中开辟一片空间,如果需要创建100个实例,那么就会在内存中开辟100个空间,这样做,就会浪费内存空间
为了解决这个问题,引入了原型对象prototype
- 构造函数通过原型分配的函数是所有对象所共享的
- js规定,每一个构造方法都有一个prototype属性,指向另外一个对象。
<script>
// 1. 构造函数的问题.
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
// 通过prototype共享sing方法
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(ldh.sing === zxy.sing); // true
ldh.sing();
zxy.sing();
// 2. 一般情况下,我们的公共属性定义到构造函数里面, 公共的方法我们放到原型对象身上
</script>
对象原型 proto
- 如下代码,思考为什么可以通过ldh调用sing方法
(ldh.sing())
?
我们在创建实例的时候,js会自动给实例添加一个 __proto__
对象,这个对象指向的是 Star.prototype
构造函数的原型,所以 ldh.__proto__ === Star.prototype
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
ldh.sing();
console.log(ldh); // 对象身上系统自己添加一个 __proto__ 指向我们构造函数的原型对象 prototype
console.log(ldh.__proto__ === Star.prototype); // true
// 方法的查找规则: 首先先看ldh 对象身上是否有 sing 方法,如果有就执行这个对象上的sing
// 如果么有sing 这个方法,因为有__proto__ 的存在,就去构造函数原型对象prototype身上去查找sing这个方法
</script>
数组
遍历数组
const arr = []
arr.forEach((item)=>{
// item表示数组中元素
})
评论区