|
3.类和对象
3.1面向对象
这里顺带提一句学习JAVA时,老师说的面向对象和面向过程的区别:
面向过程:强调做什么事情,具体什么步骤。举个把大象放进冰箱的例子:
面向对象:强调的是做动作的主体(称之为对象)
- 冰箱:打开操作
- 冰箱:放的操作(放的可以是大象也可以是老鼠)
- 冰箱:关闭的操作
面向对象的思维特点:
- 抽取(抽象)对象共用的属性和行为封装成一个类(模板)
- 对类进行实例化,创建类的对象(具体的东西)
3.2对象
现实中:对象是一个具体的事物,比如一本书、一辆车、一个人。
在js中:对象是一组无序的相关属性和方法的集合,所有的事物都是对象,如:字符串、数组、数值、函数等。
对象是由属性和方法组成的:
- 属性:事物的特征,在对象中用属性来表示
- 方法:事物的行为,在对象中用方法来表示
3.3 类
ES6中新增了类的概念,可以使用class关键字来声明一个类,之后以这个类来实例化对象。
类抽象了对象的公共部分,它泛指某一大类,
对象特指**某一个,通过类实例化一个具体的对**象。
类的本质:
- class本质还是function
- 类所有的方法都定义在类的prototype属性上
- 类创建的实例里面也有__ proto__ 指向类的prototype原型对象
- 所以ES6的类的绝大部分功能。ES5都可以做到,新的class的写法只是让对象原型的写法更加清晰、更面向对象编程的语法。
- 所以ES6的类其实就是语法糖
- class Father {
-
- }
- console.log(Father instanceof Function); //true
- //(1)类有原型对象prototype
- console.log(Father.prototype);
- //(2)类的原型对象prototype 里面有 constructor 指向类本身
- console.log(Father.prototype.constructor);
- //(3)类可以通过原型对象添加方法
- Father.prototype.speak = function () {
- console.log("speak");
- };
- //(4)类创建的实例对象有 __proto__ 指向类的原型对象
- const zooey = new Father();
- console.dir(zooey.__proto__ === Father.prototype); //true
复制代码 3.4创建类和实例化对象
- //创建类
- class Star {
- //共有属性放在constructor中
- constructor(uname, age) {
- this.name = uname;
- this.age = age;
- }
- }
- // 利用类实例化对象
- const ldh = new Star("刘德华", 19);
- const syz = new Star("孙燕姿", 18);
- //打印查看
- console.log(ldh);
- console.log(syz);
复制代码
- 通过class关键字创建类,类名首字母大写。
- 类里面有一个constructor函数,可以接收传递过来的函数,同时返回实例对象。
- 只要使用new生成实例时,就会调用constructor函数,如果我们不写这个函数, 类也会自动生成这个函数。
3.5类中添加方法
- //创建类
- class Star {
- //共有属性放在constructor中
- constructor(uname, age) {
- this.uname = uname;
- this.age = age;
- }
- sing(song) {
- //方法中可以this.使用实例属性
- console.log(this.uname + "会唱" + song);
- }
- }
- // 利用类实例化对象
- const ldh = new Star("刘德华", 19);
- const syz = new Star("孙燕姿", 18);
- //打印查看
- console.log(ldh);
- console.log(syz);
- ldh.sing("忘情水");
- syz.sing("遇见");
复制代码
注意:
- 类里面的所有函数(方法)不需要写function
- 多个函数方法(包括构造函数)之间不需要用 ',' 分割
4 类的继承
现实中的继承:子承父业,比如我们都继承了父亲的姓。
程序中的继承:子类可以继承父类的一些属性和方法。
4.1使用extends关键字实现继承
- //创建父类类
- class Father {
- constructor(name, sex) {
- this.name = name;
- this.sex = sex;
- }
- money() {
- console.log(1000);
- }
- }
- // 创建子类并继承父类
- class children extends Father {
- }
- const oldestSon = new children("伯邑考", "男");
- const middleSon = new children("姬发", "男");
- son.money();
复制代码 4.2super关键字
一个错误使用案例:
- class Father {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- total() {
- return this.x + this.y;
- }
- }
- class Son extends Father {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- }
- const son = new Son(1, 1);
- console.log("结果:" + son.total());
复制代码
此时希望调用父类中的构造函数则需要使用到super- class Father {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- total() {
- return this.x + this.y;
- }
- }
- class Son extends Father {
- constructor(x, y) {
- super(x, y);
- }
- }
- const son = new Son(1, 1);
- console.log("结果:" + son.total()); //结果:2
复制代码
思考:看到这里不知道你会不会和我有一样的困惑,此时没有super也可以实现 total方法的调用,所以 super存在真正的意义是什么呢
思考案例1:
- class Father {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- total() {
- return this.x + this.y;
- }
- }
- class Son extends Father {
- }
- const son = new Son(1, 1);
- console.log("结果:" + son.total());
复制代码
那么就让我们停下来思考一下:
当我们给Son构造函数传递多个参数的时候,这时,输出的结果就不是我们想要的结果了,此时就必须使用super才能传递正确的参数了。
思考案例2:
- class Father {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- total() {
- return this.x + this.y;
- }
- }
- class Son extends Father {
-
- }
- const son = new Son(1, "女", "zooey", 1);
-
- console.log("结果:" + son.total());//结果:1女
复制代码 真正意义上:
利用Son类创建实例son时,我们将实例son的参数传递给Son类的构造函数,
构造函数通过super()调用Father 的构造函数从而给this.x,this.y赋值,
从而使Father类中的total的方法能够找到 this.x,this.y,
从而实现了思考案例1的结果。
没有super时:
super关键字用于访问和调用对象父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数。
super调用父类的方法:
- class Father {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- total() {
- return this.x + this.y;
- }
- }
-
- class Son extends Father {
- constructor(x, y, z) {
- super(x, y);
- this.z = z;
- }
- total() {
- //子类方法中调用父类方法
- return this.z + super.total();
- }
- }
- const son = new Son(1, 1, 1);
- console.log("结果:" + son.total());//3
复制代码
注意:子类的this赋值操作要放在super之后
注意事项:
- 在 ES6 中类没有变量提升,必须先定义类,再实例化对象
- 类里面共有是属性和方法一定要加this使用。
- class Star {
- constructor(name, age) {
- this.name = name;
- this.age = age;
- this.btn = document.querySelector("button");
- this.btn.onclick = this.sing;
- }
- sing() {
- console.log(this.name);
- }
- }
- const ldh = new Star("刘德华", 18);
复制代码
4.3类中this指向
函数中的this一般指向调用者
下面的代码debug执行下,可以看到,sing()方法执行时,this是指向button的。
那么正确的做法是什么呢?
- let _this;
- class Star {
- constructor(name, age) {
- _this = this;
- this.name = name;
- this.age = age;
- this.btn = document.querySelector("button");
- //注意:因为这里是点击之后再调用,不是立即执行,所以是sing不是sing()
- this.btn.onclick = this.sing;
- }
-
- sing() {
- //使用 _this
- console.log(_this.name);
- }
-
-
- }
- const ldh = new Star("刘德华", 18);
复制代码
总结:在全局声明一个this,然后调用后将它赋值给调用对象。
举一反三:在react中,常用的另一个方法是使用bind绑定this。
- class Star {
- constructor(name, age) {
- this.name = name;
- this.age = age;
- this.btn = document.querySelector("button");
- this.btn.onclick = this.sing.bind(this);
- }
-
- sing() {
- console.log(this.name);
- }
- }
- const ldh = new Star("刘德华", 18);
复制代码 来源:https://www.cnblogs.com/zry123/p/17701706.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|