JS-学习笔记-面向对象

js 面向对象

类和对象:

对象:对象是由属性和方法组成的:是一个无序键值对的集合,指的是一个具体的事物
对象的创建:

// 1. 字面量
var zhang = {
    name : 'zhang',
    age : 18
}
// 2. 构造函数创建对象
function Stu(name, age) {
    this.name = name;
    this.age = age;
}
var zhang = Stu('zhang' , 18);

类:ES6新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象。类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个,通过类实例化一个具体的对象

// 创建类
class Stu {
    // 构造函数
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    // 类方法
    eat() {
        console.log("在吃饭");
    }
}

// 实例化
var student = new Stu('zhang' , 18);
继承

用extends关键字,子类可以继承父类的属性和方法
super关键字,可以访问父类的属性和方法

class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    add() {
        console.log(this.x + this.y);
    }
    print() {
        console.log("输出");
    }
}
class Son extends Father {
    constructor(x, y) {
        super(x, y);  // 调用父类的构造函数 super必须放在this之前
        this.x = x;
        this.y = y;
    }
}
var son = new Son(1, 2);
son.add(); // 继承父类的add方法
this指向问题

注意,在类中谁调用了函数,this指向调用函数的对象

  • constructor中的this指向的是new出来的实例对象
  • 自定义的方法,一般也指向的new出来的实例对象
  • 绑定事件之后this指向的就是触发事件的事件源

构造函数和原型

在ES6之前没有类,通过构造函数和原型可以模拟类

构造函数

通过构造函数创建对象,用new,实际上是先创建了一个空对象,然后另this指向这个空对象,执行构造函数的语句,给这个空对象添加属性和方法,返回对象

// 构造函数
function Star(name, age) {
    this.name = name; 
    this.age = age;
    this.sing = function() {  
        console.log("我唱歌超好听");
    }
}
// 实例化 对象
var angela = new Star('Angela Zhang', 18);
console.log(angela.name);
angela.sing();
静态成员和实例成员
  • 实例成员是用this.添加的属性和方法,是属于实例化对象的,通过实例化对象去调用,比如上面程序中的sing方法,name属性都是实例成员
  • 静态成员是通过 构造函数名.成员名 添加,属于构造函数,通过 构造函数 调用
Star.sex = '女'; // 给Star构造函数添加属性sex
console.log(Star.sex); // 调用静态成员
原型

构造函数存在空间浪费的问题,因为对于复杂数据类型的成员,在实例化对象时,会为每一个对象都开辟一块空间,存放相同的函数
在这里插入图片描述
解决方法:原型prototype。原型是一个对象,构造函数中有一个属性prototype,即构造函数的原型对象,可以将实例化对象共有的方法放在原型对象中,解决空间浪费的问题。

function Star(name, age) {
    this.name = name;
    this.age = age;
}
Star.prototype.sing = function() { // 将sing方法放在原型对象中
    console.log("我唱歌超好听");
}
// 实例化
var angela = new Star('angela zhang', 18);
var zsh = new Star('zhang shaohan', 18);
console.log(angela.sing === zsh.sing); // true
angela.sing(); // 实例化对象可以访问构造函数原型对象中的方法

####### 实例化对象的__proto__属性
实例化对象中有一个属性__proto__,该属性是一个对象,指向的是构造函数的原型对象prototype

console.log(zsh.__proto__ === Star.prototype);// ture
原型对象中的constructor属性

原型对象中有一个属性constructor指向的是构造函数

console.log(Star.prototype.constructor); // Star

在赋值修改了原型对象时,可以利用constructor手动使原型对象指向构造函数

// 这样修改原型对象,会使之前的内容被覆盖,原型对象中就没有的了constructor属性,需要手动添加constructor属性,让他指向构造函数
Star.prototype = {
    constructor: Star,
    sing: function() {
        console.log("唱歌");
    },
    dance: function() {
        console.log("跳舞");
    }
}
原型链

原型对象也是一个对象,也有__proto__属性,指向Object构造函数的prototype原型对象,Object的原型对象的__proto__属性为null
在这里插入图片描述
原型链及成员查找方法:
实例化对象先查找自己有没有该成员
若没有,则查找__proto__原型对象是否有该成员
若没有,则查找原型对象的__proto__,即Object的prototype原型对象是否有该成员
若没有,则返回undefined

关于构造函数和原型对象中的this指向问题

构造函数的this,指向实例化对象
原型对象中的函数的this,也指向实例化对象

function Star(uname, age) {
    this.uname = uname;
    this.age = age;
}
var that;
Star.prototype.sing = function() {
    console.log('我会唱歌');
    that = this;
}
var ldh = new Star('刘德华', 18);
// 1. 在构造函数中,里面this指向的是对象实例 ldh
console.log(that === ldh);//true
// 2.原型对象函数里面的this 指向的是 实例对象 ldh
继承

####### call()方法

  1. call() 可以用来调用函数
function fn() {
}
fn.call(); // 调用函数 等同于fn()
  1. call(targetThis, args) 可以用来手动修改函数的this指向
function fn() {
    console.log(this); // this 为 window
}
fn.call();  // 调用函数
var obj = {
    name: 'hhh';
}
function fn(x,y) {
    console.log(this); // this指向obj
    console.log(x+y);//  3
}
fn.call(obj,1,2); // 修改fn中的this指向
用call() 来继承父构造函数中的成员
// 父构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
}
// 子构造函数
function Son(name, age){
    // 用call调用父亲的构造函数,并修改this指向为儿子的实例化对象
    Father(this, name, age);
}
// 实例化
var son = new Son('zhang',18);
console.log(son.name);
继承父类的prototype中的公共方法

思路:让子类Son的prototype原型对象拥有父类的prototype中的方法。
注意:不能另子类的prototype直接等于父类的prototype,即
Son.prototype = Father.prototype, 因为这样其实是二者指向了同一个对象,修改子类的prototype也会影响父类的prototype
解决方法:Son.prototype = new Father()
即让子类的原型对象是父类的实例化对象,这样子类的实例化对象就能通过__proto__查找到父亲的实例化对象,而父亲的实例化对象又能通过它的__proto__访问到父亲原型对象中的方法,从而实现继承
注意:在给Son.prototype赋值之后,还应手动添加constructor属性,指向Son构造函数

// 父构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
}
Father.prototype.sing = function() {
    console.log("唱歌");
};
// 子构造函数
function Son(name, age){
    // 用call调用父亲的构造函数,并修改this指向为儿子的实例化对象
    Father(this, name, age);
}
Son.prototype = new Father(); // 继承父亲的方法
Son.prototype.constructor = Son; // 手动添加constructor
// 实例化
var son = new Son('zhang',18);
son.sing(); // 成功继承父亲的sing方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值