ES6class
该注意的细节
区分函数的多种的角色
// 函数/构造函数
function Fn(name) {
this.x = 100;
this.name = name;
}
// 作为原型,和「类/实例」有关
Fn.prototype.y = 200;
Fn.prototype.getX = function () {};
Fn.prototype.getName = function () {};
// 作为对象,和前面没有直接的关系
Fn.x = 1000;
Fn.getX = function () {};
Fn.getX();//对象的成员访问
new Fn().getX();//实例上的getX()方法
Fn(); //当做普通函数执行,返回undefined
上面是依据ES5的形式创造一个类
ES6中可以使用class
关键字创建类
class Fn {}
Fn();
报错,Uncaught TypeError: Class constructor Fn cannot be invoked without 'new'
基于class
声明的构造函数必须基于new
执行,不允许当做普通函数执行
如何在es5中模拟这种判断?
如果是new
执行,那么当前this
一定是当前构造函数的实例,如果不是构造函数的实例,就说明不是new
执行,就抛出错误
function Sum() {
if (!(this instanceof Sum)) throw new TypeError('constructor Sum cannot be invoked without new');
console.log('OK');
}
// Sum();//报错
new Sum();
构造函数
class Fn {
// 构造函数体
constructor(name) {
// this -> 创造的实例对象 「this.xxx=xxx设置的私有属性」
// this.x = 100;
this.name = name;
//如果返回对象,以返回的为主,否则返回实例对象
}
}
constructor
就是其构造函数体
私有属性简易写法
class Fn {
constructor(name) {
this.name = name;
}
x = 100; //等价于构造函数体中的“this.x=100”
}
但是构造函数中如果有了this.x=xxx
,那么以构造函数中的最终赋值为准
原型上的内容设置
class不能在原型上设置属性,只能设置函数,为什么会有这个特性,一会再说
class Fn {
constructor() {}
y = 200; //等价于构造函数体中的“this.x=100”,并不是在原型上设置属性y
getX() {}//这里的方法是设置在原型上的
getName() {}
}
Fn.prototype.y = 200
用这种方法设置在原型上的函数是没有prototype
的,类似于:obj={fn(){}}
如果想在原型上设置属性,只能用原来的方法写:Fn.prototype.y = 200
。
将类看做普通对象,设置私有属性
将类看做普通对象添加属性和方法,在class
中,叫做静态私有属性和方法
class Fn {
constructor() {}
y = 200; //等价于构造函数体中的“this.x=100”,并不是在原型上设置属性y
getX() {}//这里的方法是设置在原型上的
getName() {}
static x = 1000
static getX() {}
}
以上就是如何通过es6创造一个类的过程
区分原型上和实例上的方法
class Fn {
x = 100;
getX = function () {}
getY = ()=>{}
getZ(){
console.log(this)
}
}
注意:x
,getX
,getY
都属于一类,最后在实例的私有属性上,没有不同。而getZ
这种写法是声明在原型上的
const f = new Fn()
f.getZ()
Fn.prototype.getZ()
f.getZ.call(10)
所以getZ
函数有可能f.getZ()
执行,或者Fn.prototype.getZ()
这样执行,或者call
执行,其this
的指向会根据不同情况改变
那么如何让其中的this
不随便被改变而永远指向当前实例呢?答案是使用箭头函数的写法
class Fn {
getX1 = ()=>{console.log(this)}
}
const f = new Fn()
f.getX1()
f.getX1.call(10)
因为箭头函数没有this
,其中的this
是函数上下文中的this
,这个this
都是Fn
的实例,因为在 new
的时候,都将构造函数内部this
指向了返回的实例对象。
class Fn {
getX : function () {}
getY : ()=>{}
}
以上写法将报语法错误。不支持:
写法。
在react,以上特性有这样的应用:
点击按钮,输出的是undefined
,因为这是react 事件中,合成事件处理的,那我想让handle
上this
永远是实例,如何写呢?
使用箭头函数即可
handle = ()=>{
console.log(this)
}
此时handle
并不是原型上的函数了,而是私有属性,并且是箭头函数,所以this
永远是当前实例
使用Babel查看class
到底做了什么
我们打开Babel,将下面calss关键字语法糖代码转化为ES5,看看class语法糖到底是如何写的
class Fn{
constructor(){
this.name=1
}
name = 2
static name = 3
}
结果为:
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var Fn = function Fn() {
_classCallCheck(this, Fn);//判断是否用new执行,如果没有用new ,那就报错
_defineProperty(this, "name", 2);//先执行name=2,给实例赋值为2,并且有重名,会覆盖赋值
this.name = 1;//在执行构造函数
};
_defineProperty(Fn, "name", 3);//给构造函数添加属性,相当于静态属性
所以,构造函数中的this.name=1
后执行,name = 2
先执行
class Fn{
constructor(){
this.name=1
}
name = 2
name = 4
static name = 3
getName(){
return this.name
}
getX(){
return this.x
}
static getY(){
return 'static getY'
}
}
转化后:
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var Fn = /*#__PURE__*/function () {
function Fn() {
_classCallCheck(this, Fn);
_defineProperty(this, "name", 2);
_defineProperty(this, "name", 4);
this.name = 1;
}
_createClass(Fn, [{
key: "getName",
value: function getName() {
return this.name;
}
}, {
key: "getX",
value: function getX() {
return this.x;
}
}], [{
key: "getY",
value: function getY() {
return 'static getY';
}
}]);
return Fn;
}();
_defineProperty(Fn, "name", 3);
加入实例方法和静态方法后,发现其多了一个_createClass
函数,其中的逻辑是按照传入的参数的顺序不同 ,只是简单的分别向原型对象和构造函数上添加方法,分别成为实例的共有方法和构造函数上的方法。
注意:
看了转换后就解释一个我思考过的疑问:为啥没法向原型上绑定静态的变量,而只能区分原型上的共有方法和构造函数上的静态方法呢?
因为在转换代码里constructor(){this.name=1}
和直接写name = 1
是一样的作用,最终被转换成了相同意义的代码,而getName(){return this.name}
和getName=()=>{return this.name}
则是不同逻辑,不同意义的代码
举例如下:
class Fn{
constructor(){
this.name=1
}
name = 2
name = 3
static name = 4
getName(){
return this.name
}
static getStaticName(){
console.log(this)
return this.name
}
}
const x = new Fn()
x.getName()//返回1
x.getStaticName()//报错,x.getStaticName is not a function
Fn.getStaticName()//打印class Fn ,返回4
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!