js面向对象编程
基本概念:原型链、继承
class Person {
// 这里定义固定的属性,该属性定义在每一个new出来的对象上面
canSpeak = true;
canSleep = true;
toFuck = ()=>{
// 箭头函数中的this会自动向外层寻找,外层的this指向的就是该实例(此处使用function则不行)
if( this.canSleep == true ){
this.speak();
}else{
return
}
};
// static关键字的使用使得defaultProps定义在了该类的原型对象上面,而不是存在于实例对象上,注意与上面的属性定义方式相区分
static defaultProps = {
sex: '男',
age: 18
}
// 定义构造器,传入参数
constructor(name,age){
this.name = name;
this.age = age;
}
// 思考: speak对象放在了哪里? ----类的原型对象(prototype)上(实例对象上面没有),供实例使用。
speak(){
console.log(`I am ${this.name}, ${this.age} years old.`);
}
}
// 继承
class Student extends Person {
// constructor也可以不写,如果写了就必须有super来继承父亲的属性
constructor(name,age,grade){
super(name,age); // 如果是继承,则必须有super继承父类当中的属性
this.grade = grade;
}
speak(){
console.log('重写了父类继承过来的方法!')
}
study(){
// 思考🤔 : study方法放在了哪里? --类的原型对象上,供实例使用
console.log('studying...');
}
}
// Instantiation
let p1 = new Person('Jone', 18);
let p2 = new Student('Mary',16, 3); // 如果调用了子类中的不存在方法,会顺着原型链查找,查找父亲节点有没有。
p1.speak();
p2.speak();
一些函数:
- call()函数
// p1.speak.call(someObject) // call()可以更改某个类的方法的this对象
- apply()函数
- bind()函数
// 改变某函数/对象方法的this指向(将函数绑定到某个对象上面)
function demo(){
console.log(this);
}
demo(); // output: window object
const x = demo.bind({a:1, b:2});
x(); // output : {a:1 , b:2}
典型问题
- 方法中的this
方法中调用this时候,通常情况下,调用的是实例对象,通俗来讲就是new出来的返回值。但是有一种情况,就是当我在另一个方法中调用本方法时候,这时候的this就不一定指向实例对象了!
来看一个react组件:
// create component
class Weather extends React.Component{
constructor(props){
super(props)
this.state = { isHot: false }
}
render(){
// 读取状态
const {isHot} = this.state;
return <h1 onClick={this.changeWeather}> 今天天气很{isHot?'炎热':'凉爽'}</h1>
}
changeWeather(){
// 我先检查下this对象
console.log(this); // ----> undefined
this.state.isHot = !this.state.isHot;
}
}
ReactDOM.render(<Weather/>, document.getElementById('test'))
注意: 类中的方法默认开启了局部的严格模式, this默认不是window而是undefined
通过上面的例子可以看出,这时候的调用仅仅是执行了计算机内存"堆"中的一个函数(这个函数是作为一个方法的),这时候不一样的地方就是我们进行了直接调用,没有通过实例调用方法的形式调用。所以该方法内的this就没有对象给它了,值为undefined
解决办法:
// create component
class Weather extends React.Component{
constructor(props){
super(props);
this.state = { isHot: false };
// 在实例化(new Weather)的时候,执行constructor函数,将对象上面的`changeWeather`方法绑定this对象,
// 然后在将该方法绑定到该对象(已经实例化)的`myChangeWeather`属性上面去(或者说给到了实例本身)
// 那么当我在调用的时候,是不是调用的是一个属性方法,而不是原形链上的方法。该属性方法能够直接获取this了(因为已经绑定了)
this.myChangeWeather = this.changeWeather.bind(this);
}
render(){
// 读取状态
const {isHot} = this.state;
return <h1 onClick={this.myChangeWeather}> 今天天气很{isHot?'炎热':'凉爽'}</h1>
}
changeWeather(){
// 我先检查下this对象
console.log(this);
this.setState({isHot: !isHot}); // diff后合并更新状态
}
}
ReactDOM.render(<Weather/>, document.getElementById('test'))