Class
基本用法
class n {
constructor(x,y) {
this.x = x;
this.y = y;
console.log(x,y)
}
proint() {
console.log(' this is proint ')
}
}
var newObject = new n(1,2);
// c {x: 1, y: 2}
newObject.proint();
// this is proint
现在不用像以前.
function o(x,y) {
this.x = x;
this.y = y;
console.log(x,y)
}
o.prototype.proint = function() {
console.log(' this is proint ');
};
var oldObject = new o(1,2); //1,2
oldObject.proint() //this is proint
书中说这是语法糖.
也就是说。本质上依旧使用的是
ES5 版本的创建对象.
Class
不过一种简化的写法.
不过需要验证一下。 接下来的例子都会同时有两个版本.
n === n.prototype.constructor //true
o === o.prototype.constructor
newObject.constructor === n.prototype.constructor //true
oldObject.constructor === o.prototype.constructor //true
也就是这样.
为了说明他是语法糖.
Object.assign(n.prototype,{
mytest:function() { console.log('mytest') }
});
n.mytest() //mytest
n.prototype.proint //proint() { console.log(' this is proint ') }
constructor
你不写那么 javascript
就会为你自动创建一个空的
constructor() {}
new n()
就是调用 constructor
返回一个实例.
所以你可以改变返回的实例.
class foo {
constructor() {
return { y : 1 };
}
}
new foo() // { y : 1 }
类的实例对象
基本和ES5原型链基本一样.
this
, prototype
以及
类的所有实例共享一个原型对象
完全是ES5的老内容.
不存在变量提升
我一直认为变量提升这种东西.
是你写代码不规范导致的.
不存在也就不存在吧.
Class的表达式
几种写法.
let n = class c { } //只有在class 内部调用才能调用C
let n1 = class { }
let n2 = new class { } //自执行相当于马上实例化.
私有方法
书中提到了3种方式.
- 前面加 **_** 下划线
- 将私有方法移出模块
- 用Symbol
前两种我表示都太垃圾..
第三种还有些意思
const bar = Symbol('bar');
const snaf = Symbol('snaf');export default class myClass{
// 公有方法
foo(baz) {
thisbar;
}// 私有方法
bar {
return this[snaf] = baz;
}// ...
};
这样确实可以私有。
百度了一波。 发现大部分都是使用 Symbol
例子中 bar 依然暴露在外.
没办法彻底的私有. 因为 Symbol
你如何防止随意的使用呢?
这样反而不如。 function
来的ok
function() {
var a1 = function() {};
return {
a : function() {
return a1();
}
}
}
继承
基本用法
class c1n extends n {}
基本的继承就是这样。 啥都不写。 完全照搬父类方法.
继承父类的一切。 this & prototype
你也可以自己写点儿啥.
具体的跟 ES5 并没有什么区别
需要注意的点在于 super
,这个关键字.
它在 构造函数(constructor) 中,就是直接调用父类的构造函数.
它在普通的方法中,就是想到父类的this
class c1n extends n {
constructor(x,y,z) { super(x,y); this.z = z }
print() {
super.proint();
console.log('child print')
}
}
var o = new c1n(1,2,3);
o.print();
// this is proint
// child print
不调用父类的构造函数是无法创建自己的this
所以 super
是必须在构造函数中调用的。
当然如果你忘记了。 浏览器会自动为你调用。
前提是你参数没有问题.
类的prototype属性和__proto__属性
class c1n extends n { };
c1n.__proto__ === n;
c1n.prototype.__proto__ === n.prototype;
这种继承你完全可以自己模拟
Object.setPrototypeOf(c1n.prototype, n.prototype);
c1n.__proto__ = n;
就可以继承了.
Object.getPrototypeOf(c1n) === n
这样也可以获取父类.
super 关键字
super.
上面说过。 首先需要再 构造函数调用 super
,调用父类的构造函数。
然后 super
会转变模式.
super
会指向父类的原型对象. 可以调用父类的方法.
super
引用当前子类的引用(this)
class a1 {
constructor(x,y) {
this.x = x;
this.y = y;
}
p() { console.log(this.x,this.y); }
}
class a2 extends a1 {
constructor(x,y) {
super(x,y);
this.x = 33;
}
p1() { super.p(); }
}
var o = new a2()
o.p1(); //33 undefined
所以 this.y
是 undefined
.
Extends 的继承目标
上面代码的A,只要是一个有prototype属性的函数,就能被B继承。由于函数都有prototype属性(除了Function.prototype函数),因此A可以是任意函数。
也就是说
只要你有 prototype
属性. 且是一个函数,那就可以被继承.
书中讲了3个特殊情况.
继承
Object
相当于Object 的一个复制class a {}
这种情况下,A作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承Funciton.prototype。但是,A调用后返回一个空对象(即Object实例),所以A.prototype.__proto__指向构造函数(Object)的prototype属性。
class a extends null
class C extends null {
constructor() { return Object.create(null); }
}
3.原生构造函数的继承
ES6 以前你并不能继承一些原生的对象.
Boolean()
Number()
String()
Array()
Date()
Function()
RegExp()
Error()
Object()
你并不能继承,去模拟它。
因为你不能继承到对象的构造函数 constructor
.
但是 extends
可以
所以你可以完全继承一个 Array
来改造他.
class nArray extends Array {
constructor(...args) {
super(...args); //调用构造函数.
}
push(obj) {
//可以开始改造.
}
}
就是这样.
4. Class的取值函数(getter)和存值函数(setter)
可以有 get set. 虽然ES5 也有
class testClass {
get p() { console.log('b') }
set p(value) { console.log('a') }
}
5. Class的Generator方法
class testClass {
* [Symbol.iterator]() { }
}
6. Class的静态方法
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
就是静态类。 不用实例化就可以调用。
不过不能访问内部的东西。 可以用于某些设计模式.
ES6 不支持静态属性。 书中说 ES7 支持
8. new.target属性
new.target
能返回实例化的对象.
如果不是 new
实例化,就是 undefined
.
function Person(name) {
if (new.target === Person) {
this.name = name;
} else {
throw new Error('必须使用new生成实例');
}
}
这就是一个例子。
必须是 Person
实例化.
利用这个特点,可以写出不能独立使用、必须继承后才能使用的类。
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error('本类不能实例化');
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
// ...
}
}
var x = new Shape(); // 报错
var y = new Rectangle(3, 4); // 正确
就是这样.
大概了解了一下。 基本是以前就有的概念。当然也有一些没有的概念.
可以在实际中运用一下再来复盘一下.