我们用class来定义一个函数,不在简简单单的使用function,好歹也应该让自己装装逼了eg:
class A {
// 构造方法
constructor(name) {
this.name = name; // 当使用new A()的时候回触发该构造方法,该方法可以有参数,参数便是在进行new操作构造函数时传递的参数
}
// 定义的实例方法
sayHello() {
console.log("my name is: " + this.name);
}
// 重写toString方法
toString() {
return this.name;
}
//这内部的方法就好比是在方法A的原型上添加的方法A.prototype.toString等等
}
var a = new A("jack"); // 将调用A中的constructor方法
a.sayHello(); // "my name is: jack"
console.log(a.toString()); // "jack" 可以调用上面A类下的方法
console.log(typeof A); // "function" A同样是一个function方法
console.log(A === A.prototype.constructor); // true A的原型prototype的constructor指向函数本身A
console.log(a.constructor === A.prototype.constructor); // true 实例的构造方法就是A类原型上的constructor。
console.log(Object.keys(A.prototype)); // [] 通过class这种方式定义的构造方法,其内部定义的所有实例方法都是不可枚举的
A.prototype.tell = () => {}; // 通过prototype重写toString方法,在ES5中是可枚举的
console.log(Object.keys(A.prototype)); // ["tell"] 可以之后通过prototype来定义的方法或属性可以遍历到
console.log(Object.getOwnPropertyNames(A.prototype));
// ["constructor", "sayHello", "toString", "tell"] 通过getOwnPropertyNames能获取到定义在类A中的所有属性名
let phone = "myPhone";
class A {
constructor(phone) {
this.phone = phone;
}
// 通过变量表达式来定义方法
[phone]() {
return this.phone;
}
}
let a = new A(110);
//调用表达式定义的方法
console.log(a[phone]()); // 110
考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式
//每个class类中都会有一个constructor构造方法,若没有显示提供该方法,则程序会默认在该类中添加一个空的constructor构造方法,并且在new操作的时候会主动调用该构造方法
class A {
constructor(name) {
return Object.create(null); // 返回了一个全新的对象
}
}
console.log(new A() instanceof A); // false
A(); // 直接以函数的形式调用会报错 TypeError: Class constructor A cannot be invoked without 'new'
constructor可以指定返回值,但是当指定返回值后会导致A的实例通过instanceof来判断返回false,当constructor没有返回值的时候,将默认返回实例对象this
class A {
constructor(name) {
this.name = name; // 只有通过this显示的定义属性,会在自身上,否则都将是在prototype原型上
}
toString() {
return this.name;
}
}
let a = new A("张三");
console.log(a.name); // "张三"
console.log(a.hasOwnProperty("name")); // true
console.log(a.hasOwnProperty("toString")); // false
console.log(a.__proto__.hasOwnProperty("toString")); // true
let b = new A("李四");
console.log(a.__proto__ === b.__proto__); // true a,b都是A的实例对象,他们的原型都是A.prototype
//当在其中一个实例对象上的__proto__添加方法,则该方法便是添加在类A的原型prototype上,故而所有实例将会共享该方法
a.__proto__.sayName = function() {
console.log(this.name);
};
a.sayName(); // "张三"
b.sayName(); // "李四"
只有显示定义在this上的属性都是实例对象自身的属性,其他定义的都将会通过原型去查找,同一个类构建出来的实例共享同一个原型对象
//通过表达式来定义class 其中类名应为A a只能是在类内部使用,相当于是匿名函数中的函数名
const A = class AA {
// 使用别名a来代指该类 返回该方法名
sayName() {
return AA.name;
}
};
let a = new A();
console.log(a.sayName()); // "AA"
console.log(AA.name); // AA is not defined
// ES5 就如下方式
const A = function AA() {};
A.prototype.sayName = function() {
return A.name;
};
let a = new A();
console.log(a.sayName()); // "AA"
// 在定义时便执行了,相当于函数自执行方式
let a = new class A {
constructor(name) {
this.name = name;
}
sayName() {
return this.name;
}
}("张三");
console.log(a.sayName()); // "张三"
//属性私有性
class A {
// 公有方法
f(baz) {
this._bar(baz);
}
// 私有方法
_bar(baz) {
return (this.b = baz);
}
}
let a = new A();
// 通过公有方法调用给值b赋值
a.f("b");
console.log(a.b); // "b"
// 实例a同样还是能够直接调用到_bar私有方法
a._bar("b");
console.log(a.b); // "b"
class A {
// 公有方法,通过call方法调用外部函数,使得实例无法直接调用来达到直接赋值操作
f(baz) {
bar.call(this, baz);
}
}
function bar(baz) {
return (this.b = baz);
}
let a = new A();
a.f("b");
console.log(a.b); // "b"
// 还有种方式是将私有方法名以表达式的形式定义为Symbol值 eg:
const bar = Symbol("bar");
const b = Symbol("b");
class A {
// 公有方法
f(baz) {
this[bar](baz);
}
// 私有方法
[bar](baz) {
this[b] = baz;
}
}
let a = new A();
// 调用公有方法
a.f("b");
console.log(a[b]); // "b"
class A {
init(name = "张三") {
// 调用sayHello方法
this.sayHello(`hello ${name}`);
}
sayHello(text) {
console.log(text);
}
}
let a = new A();
// 正常调用
a.init(); // "hello 张三"
// 赋值调用时
let { init } = a;
init(); // TypeError: Cannot read property 'sayHello' of undefined
此时this指向的是该方法的运行环境,此时在方法中this为undefined,故而无法找到sayHello方法,注意,只有在严格模式下this的值才有可能为undefined,在ES6中,使用class的方式,都是属于严格模式。
// 还有种方式,在定义constructor构造函数的时候就固定this eg:
百度未收录class A { // 在构造函数这儿将调用有使用到this的方法绑定this指向到A constructor() { this.init = this.init.bind(this); } init(name = "张三") { // 调用sayHello方法 this.sayHello(`hello ${name}`); } sayHello(text) { console.log(text); } } let a = new A(); let { init } = a; init(); // "hello 张三" 通过箭头函数的方式来固定this指向 class A { constructor() { // 通过箭头函数来固定this的指向,在箭头函数里,this的指向是定义时就固定了的 this.init = (name = "张三") => { this.sayHello(`hello ${name}`); }; } sayHello(text) { console.log(text); } } let a = new A(); let { init } = a; init(); // "hello 张三"
通过setter及getter来存取值class A { get f() { return "getter"; } set f(val) { console.log("setter: " + val); } } let a = new A(); a.f = "hello"; // "setter: hello" 设置值 console.log(a.f); // "getter" 取值 target new操作时,target会指向该类,若是继承的情况,将指向子类 class A { constructor() { console.log(new.target === A); // true // 当有继承关系时,将返回的是子类。 console.log(new.target); // "[(Function: B)]" } } class B extends A { constructor() { super(); } } let b = new B();