在寫這個問題之前,我們先要學習2個知識點;
- 1 ES6 Class的基本語法
- 2 React創建組件的方法;
ES6 Class的基本語法
在ES6 引入了 Class(類)這個概念,作爲對象的模板。通過class關鍵字,可以定義類。
我這裏不做過多的介紹,具體請參考ECMAScript 6 入門(阮一峯)
(1) ES6 Class 編寫對象
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
以上的代碼等價於:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
在這裏會有2個概念: 類的實例和對象的屬性;
接下來我們用一段代碼解釋這兩個東西;
//定義類
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
// 實例化Point Class
var point = new Point(2, 3);
console.log(point.toString()) // (2, 3)
console.log(point.hasOwnProperty('x')) // true
console.log(point.hasOwnProperty('y')) // true
// 判斷對象的實例上是否有 toStirng 屬性
console.log(point.hasOwnProperty('toString')) // false
// 判斷對象的屬性上是否存在 toString 屬性
console.log(point.__proto__.hasOwnProperty('toString')) // true
基於上面的代碼我們可以得知:
- 實例的屬性除非顯式定義在其本身(即定義在this對象上),否則都是定義在原型上(即定義在class上)
- 上面代碼中,x和y都是實例對象point自身的屬性(因爲定義在this變量上),所以hasOwnProperty方法返回true,而toString是原型對象的屬性(因爲定義在Point類上),
- 所以hasOwnProperty方法返回false。這些都與 ES5 的行爲保持一致。
(2) this的指向
類的方法內部如果含有this,它默認指向類的實例;但是,必須非常小心,一旦單獨使用該方法,很可能報錯。
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
// ES6 解構
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
上面代碼中,printName方法中的this,默認指向Logger類的實例。但是,如果將這個方法提取出來單獨使用,this會指向該方法運行時所在的環境(由於 class 內部是嚴格模式,所以 this 實際指向的是undefined),從而導致找不到print方法而報錯。
因此在如果這個方法被單獨提出來使用,我們的通常的做法就是在構造方法中綁定this,這樣就不會找不到print方法了。
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
// ...
}
另一種方法是使用箭頭函數
class Obj {
constructor() {
this.getThis = () => this;
}
}
const myObj = new Obj();
myObj.getThis() === myObj // true
箭頭函數內部的this總是指向定義時所在的對象,
它的定義生效的時候,是在構造函數執行的時候。
這時,箭頭函數所在的運行環境,肯定是實例對象,所以this會總是指向實例對象
第三種是使用還有一種解決方法是使用Proxy,獲取方法的時候,自動綁定this。具體請看:ES6 Class Proxy
那麼以上就是this在ES6中Class的基本介紹;詳細的學習請參考ECMAScript 6 入門(阮一峯),那麼接下來我們就來看看React中如何使用this;首先會從組件的創建開始來說;
React創建組件的寫法
1.函數組件(無狀態組件)
定義組件最簡單的方式就是編寫 JavaScript 函數:
(1) 語法
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
(2) 特點
- 它是爲了創建純展示組件,這種組件只負責根據傳入的props來展示,不涉及到state狀態的操作。
- 組件不能訪問this對象
無狀態組件由於沒有實例化過程,所以無法訪問組件this中的對象,例如:this.ref、this.state等均不能訪問。若想訪問就不能使用這種形式來創建組件 - 它不能訪問生命週期方法
2 es5方式React.createClass組件(有狀態組件)
React.createClass是react剛開始推薦的創建組件的方式,這是ES5的原生的JavaScript來實現的React組件
(1)語法
var myCreate = React.createClass({
defaultProps: {
//code
},
getInitialState: function() {
return {
//code
};
},
render: function() {
return (
<div>
//code
</div>
);
}
});
(2) 特點
與無狀態組件相比,React.createClass和後面要描述的React.Component都是創建有狀態的組件,這些組件是要被實例化的,並且可以訪問組件的生命週期方法。但是隨着React的發展,React.createClass形式自身的問題暴露出來:
- React.createClass會自綁定函數方法(不像React.Component只綁定需要關心的函數)導致不必要的性能開銷,增加代碼過時的可能性。
- React.createClass的mixins不夠自然、直觀;React.Component形式非常適合高階組件(Higher Order Components–HOC),它以更直觀的形式展示了比mixins更強大的功能,並且HOC是純淨的JavaScript,不用擔心他們會被廢棄。HOC可以參考無狀態組件(Stateless Component) 與高階組件。
3.Class組件(有狀態組件)
React.Component是以ES6的形式來創建react的組件的,是React目前極爲推薦的創建有狀態組件的方式,最終也會取代React.createClass形式;
它相比較於 React.createClass可以更好實現代碼複用。將上面React.createClass的形式改爲React.Component形式如下:
class InputControlES6 extends React.Component {
constructor(props) {
super(props);
// 設置 initial state
this.state = {
text: props.initialValue || 'placeholder'
};
// ES6 類中函數必須手動綁定
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange}
value={this.state.text} />
</div>
);
}
}
InputControlES6.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
initialValue: ''
};
(2)優點:
- 成員函數不會自動綁定this,需要開發者手動綁定,否則this不能獲取當前組件實例對象。
- 狀態state是在constructor中像初始化。
- props屬性類型和組件默認屬性作爲組件類的屬性,不是組件實例的屬性,所以使用類的靜態屬性
- 能很好的實現代碼複用
- 能很好的管理組件的生命週期
React.createClass與React.Component區別
(1) 函數的this綁定
React.createClass創建的組件,其每一個成員函數的this都有React自動綁定,任何時候使用,直接使用this.method即可,函數中的this會被正確設置。
const Contacts = React.createClass({
handleClick() {
console.log(this); // React Component instance
},
render() {
return (
<div onClick={this.handleClick}></div>
);
}
});
而用React.Component創建的組件,其成員函數不會自動綁定this,需要開發者手動綁定,否則this不能獲取當前組件實例對象。
class Contacts extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
console.log(this); // null
}
render() {
return (
<div onClick={this.handleClick}></div>
);
}
在這裏就可以看到;因爲我們使用了ES6的Class方式來創建組件,那麼如何在內部去訪問屬性方法;就需要顯式的在需要綁定的地方綁定this;
當然,React.Component有三種手動綁定方法:
- 可以在構造函數中完成綁定,
- 在調用時使用method.bind(this)來完成綁定,
- 還可以使用箭頭函數來綁定
那麼我們以上面的handleClick函數爲例子;
在構造函數中綁定;
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this); //構造函數中綁定
}
在調用時候的進行綁定
<div onClick={this.handleClick.bind(this)}></div> //使用bind來綁定
使用箭頭函數來綁定
<div onClick={()=>this.handleClick()}></div> //使用arrow function來綁定
基本上就這些吧;以後碰上了再寫;