导航
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.say = function(){
console.log(`My name is ${this.name}, age is ${this.age}`);
}
var person = new Person('lisi', 20);
// person 的原型
console.log(Object.getPrototypeOf(person));
console.log(Object.getPrototypeOf(person).constructor === Person);
console.log(Object.getPrototypeOf(person) === Person.prototype);
class Person{}
console.log(new Person())
class Person {
constructor(name = 'zhangsna', age = 18) {
// 实例化的属性配置: 私有属性
this.name = name;
this.age = age;
}
// 公有方法: 出现在原型上
say() {
console.log(`My name is ${this.name}, age is ${this.age}`);
}
eat() {
console.log('I can eat')
}
drink() {
console.log('I can drink')
}
}
console.log(new Person());
class Person {
constructor(name = 'Lance', age = 27) {
this.name = name
this.age = age
}
run() {}
say() {}
}
console.log(Object.keys(Person.prototype));
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.say = function(){
console.log(`My name is ${this.name}, age is ${this.age}`);
}
Object.assign(Person.prototype, {
eat: function() {
console.log('I can eat')
},
drink: function() {
console.log('I can drink')
}
})
// 这种方式添加的方法是可枚举的
console.log(Object.keys(Person.prototype));
class Person {}
console.log(new Person());
console.log(new Person());
class Person {}
const eat = Symbol();
class Person {
constructor(name = 'zhangsna', age = 18) {
// 实例化的属性配置: 私有属性
this.name = name;
this.age = age;
}
// 公有属性
say() {
console.log(`My name is ${this.name}, age is ${this.age}`);
}
[eat]() {
console.log('I can eat')
}
}
console.log(new Person().say());
console.log(new Person().eat());
console.log(new Person()[eat]()); // 可以这样访问
class Person {
constructor(name = 'zhangsan', age = 18) {
// 实例化的属性配置: 私有属性
this.name = name;
this.age = age;
}
// 公有属性
say(baz) {
children.call(this, baz);
}
}
function children(baz) {
return this.bar = baz;
}
class Person {
static a = 10;
static say(){
console.log('say....')
}
}
var per = new Person();
Person.say();
console.log(Person.a);
per.say();
console.log(per.a);
var obj = {
get a(){
console.log(1)
},
set b (val){
console.log(2)
}
}
obj.a;
obj.b = 1;
class Person {
get a() {
console.log(1)
}
set b(val) {
console.log(2)
}
}
var person = new Person()
person.a;
person.b = 1;
var Person = class {
say() {
console.log('say')
}
}
new Person().say();
var Person = class {
say(){
console.log('say')
}
}();
Person.say();
var Person = new class {
say(){
console.log('say')
}
}();
Person.say();
class Parent {
constructor(name = 'zhangsna') {
this.name = name;
}
say() {
console.log(1);
}
// 静态方法无法被继承
static a() {
console.log(2)
}
}
// 派生类
class Child extends Parent {
}
console.log(new Child());
class Parent {
constructor(name = 'zhangsan') {
this.name = name;
}
say() {
console.log(1);
}
// 静态方法无法被继承
static a() {
console.log(2)
}
}
// 派生类
class Child extends Parent {
constructor(name = 'lisi', age = 20){
super(name);
this.type = 'child';
this.age = age;
}
}
console.log(new Child());
var proto = {
y: 20,
z: 40
}
var obj = {
x: 10,
foo() {
console.log(super.y);
}
}
Object.setPrototypeOf(obj, proto);
obj.foo();
"use strict"
function _classCallBack(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function')
}
}
var _createClass = 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)
}
return function(Constructor,protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps)
if (staticProps) defineProperties(Constructor, staticProps)
return Constructor;
}
}
}();
var Person = function() {
function Person() {
var name = arguments[0] !== undefined && arguments.length > 1 ? arguments[0]:'xx';
var test = arguments[0] !== undefined && arguments.length > 1 ? arguments[1]:'dd';
_classCallBack(this, Person)
this.name = name
this.age = age
}
_createClass(Person,[{
key:"test",
value:function test(){
console.log('hahahahahha');
}
}],[{
key:'fuck',
value:function fuck(){
console.log(2);
}
}])
return Person;
}();
首先,ES6 的 class
属于一种“语法糖”,所以只是写法更加优雅,更加像面对对象的编程,其思想和 ES5 是一致的。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return '(' + this.x + ',' + this.y + ')';
}
等同于
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ',' + this.y + ')';
}
}
其中 constructor
方法是类的构造函数,是一个默认方法,通过 new
命令创建对象实例时,自动调用该方法。一个类必须有 constructor
方法,如果没有显式定义,一个默认的 consructor
方法会被默认添加。所以即使你没有添加构造函数,也是会有一个默认的构造函数的。一般 constructor
方法返回实例对象 this ,但是也可以指定 constructor
方法返回一个全新的对象,让返回的实例对象不是该类的实例。
super
这个关键字,既可以当做函数使用,也可以当做对象使用。这两种情况下,它的用法完全不用。
class A {}
class B extends A {
constructor() {
super(); // ES6 要求,子类的构造函数必须执行一次 super 函数,否则会报错。
}
}
注:在 constructor
中必须调用 super
方法,因为子类没有自己的 this 对象,而是继承父类的 this 对象,然后对其进行加工, 而 super 就代表了父类的构造函数。super 虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指的是 B,因此 super() 在这里相当于:
A.prototype.constructor.call(this, props)
class A {
constructor() {
console.log(new.target.name); // new.target 指向当前正在执行的函数
}
}
class B extends A {
constructor() {
super();
}
}
new A(); // A
new B(); // B
可以看到,在 super()
执行时,它指向的是 子类 B 的构造函数,而不是父类 A 的构造函数。也就是说,super()
内部的 this 指向的是 B。
在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
class A {
c() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.c()); // 2
}
}
let b = new B();
上面代码中,子类 B 当中的 super.c()
,就是将 super
当作一个对象使用。这时,super
在普通方法之中,指向 A.prototype
,所以 super.c()
就相当于 A.prototype.c()
。
通过 super 调用父类的方法时,super 会绑定子类的 this。
class A {
constructor {
this.x = 1;
}
s() {
console.log(this.x);
}
}
class B extends A {
constructor {
super();
this.x = 2;
}
m() {
super.s();
}
}
let b = new B();
b.m(); // 2
上面代码中,super.s()
虽然调用的是 A.prototytpe.s()
,但是 A.prototytpe.s()
会绑定子类 B 的 this
,导致输出的是 2,而不是 1。也就是说,实际上执行的是 super.s.call(this)
。
由于绑定子类的 this
,所以如果通过 super
对某个属性赋值,这时 super
就是 this
,赋值的属性会变成子类实例的属性。
class A {
constructor {
this.x = 1;
}
}
class B extends A {
constructor {
super();
this.x = 2;
super.x = 3;
console.log(super.x); // undefined
console.log(this.x); // 3
}
}
let b = new B();
上面代码中,super.x
赋值为 3,这时等同于对 this.x
赋值为 3。而当读取 super.x
的时候,调用的是 A.prototype.x
,但并没有 x
方法,所以返回 undefined。
注意,使用 super
的时候,必须显式指定是作为函数,还是作为对象使用,否则会报错。
class A {}
class B extends A {
constructor() {
super();
console.log(super); // 报错
}
}
上面代码中,console.log(super);
的当中的 super
,无法看出是作为函数使用,还是作为对象使用,所以 JavaScript 引擎解析代码的时候就会报错。这时,如果能清晰的表明 super
的数据类型,就不会报错。
最后,由于对象总是继承其他对象的,所以可以在任意一个对象中,使用 super
关键字。
为对象添加新的功能,而不改变原有的结构和功能
解决痛点:
package.json
{
"name": "decorators-in-nodejs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"index": "babel-node index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.17.6",
"@babel/core": "^7.17.5",
"@babel/node": "^7.16.8",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-decorators": "^7.17.2",
"@babel/preset-env": "^7.16.11",
"babel-node": "0.0.1-security"
}
}
.babelrc
{
"presets": [
"@babel/preset-env"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
运行方式:npm run index
接收的参数:
@testable
class Person {
constructor(name='lisi', age='19') {
this.name = name;
this.age = age;
}
say() {
console.log('hello world')
}
eat() {
console.log('eat')
}
}
var person = new Person();
function testable(target) {
console.log('target', target)
}
// target [Function: Person]
接收的参数:
class Person {
constructor(name='lisi', age='19') {
this.name = name;
this.age = age;
}
@readOnly
say() {
console.log('hello world')
}
eat() {
console.log('eat')
}
}
function readOnly(target, name, descriptor) {
console.log(target, name, descriptor)
descriptor.writable = false
}
var person = new Person()
person.say()
// hello world
var log = (type) => {
return function(target, name, descriptor) {
let src_method = descriptor.value
descriptor.value = (...arg) => {
src_method.apply(target, arg);
console.log(type);
}
}
}
class AD {
@log('show')
show() {
console.log('ad show')
}
@log('click')
click() {
console.log('ad click')
}
}
const ad = new AD();
ad.show();
// ad show
// show