一、object的简写

1、属性的缩写
let name = 'zhuangzhuang';
let age = 18;
let obj = {
    name:name,
    age:age
}

那么对于这种value为变量,key跟value名字相同的,那么可以简写成如下:

let name = 'zhuangzhuang';
let age = 18;
let obj = {
    name,
    age
}
2、方法的缩写
let obj = {
    say:function(){
        console.log('nihao');
    }
}

那么对于这种函数,可以简写成如下:

let obj = {
    say(){
        console.log('nihao');
    }
}
3、对象转成字符串
let name = 'zhuangzhuang';
let age = 18;
let obj = {
    name:name,
    age:age,
    say:function(){
        console.log('nihao');
    }
}
console.log(JSON.stringify(obj));//{"name":"zhuangzhuang","age":18}
let name = 'zhuangzhuang';
let age = 18;
let obj = {
    name,
    age,
    say(){
        console.log('nihao');
    }
}
console.log(JSON.stringify(obj));//{"name":"zhuangzhuang","age":18}

可见,不管是简写还是不简写,对象在转成字符串的时候,都会先将变量解析,然后再转成字符串。
但是,务必要注意一点,对于对象中的函数,JSON.stringify是直接忽略的,如下:

let obj = {
    say:function(){
        console.log('nihao');
    }
}
console.log(JSON.stringify(obj));//{}

let obj = {
    say(){
        console.log('nihao');
    }
}
console.log(JSON.stringify(obj));//{}

二、Object.setPrototypeOf(A,B)与Object.getPrototypeOf(A)

1、Object.setPrototypeOf(A,B)

作用:设置A的原型(proto)为B

let obj1 = {age:1};
let obj3 = {};
//如果希望obj3继承自obj1
Object.setPrototypeOf(obj3,obj1);
console.log(obj3);//{}
console.log(obj3.age);//1

为什么obj3是{},但是obj3.age却存在,为1?
其实大家知道原型链的同学应该很快就会发现,这个age虽然是obj3的属性,但是当无法从obj3上找到时,就会去查找原型链(注意:原型链的查找是根据proto查找的,而不是根据prototype查找的)。
那么,在原型链的哪里呢?
其实,只要知道setPrototypeOf是怎么实现的就能明白了,如下:

let obj1 = {age:1};
let obj3 = {};
//如果希望obj3继承自obj1
//Object.setPrototypeOf(obj3,obj1)就相当于如下:
obj3.__proto__ = obj1;
console.log(obj3);//{}
console.log(obj3.age);//1
2、Object.getPrototypeOf(A)

获取A的proto属性,与上面Object.setPrototypeOf(A,B)相反,在此不再赘述。

三、super

作用:继承被继承者的属性和方法

let obj1 = {age:1,getFood(){return '面包'}};
let obj3 = {};
obj3 = {
    __proto__:obj1,
    getFood(){

    }
}
console.log(obj3.getFood());//undefined

说明,虽然我obj3继承了obj1,但是根据原型链查找规则,先会找到自身的属性和方法,再会去proto上查找
那如果在obj3的getFood中想要调用obj1的方法,该如何实现呢?

let obj1 = {age:1,getFood(){return '面包'}};
let obj3 = {};
obj3 = {
    __proto__:obj1,
    getFood(){
        return '我今年'+super.age+'岁,我喜欢吃'+super.getFood();
    }
}
console.log(obj3.getFood());//我今年1岁,我喜欢吃面包  

可见,使用super,可以调用被继承者的属性和方法

四、类Class

大家应该都很熟悉ES5的面向对象的写法,那么针对ES6的面向对象,采用了Class类关键字,这种写法有什么好处呢?大家一起来感受下。

1、定义一个类

以前,JS里类和构造函数是一体的
类里面可以定义构造函数constructor,当创建一个类的实例的时候,就会调用构造函数

class Parent{
    constructor(name){
        this.name = name;//属于实例的私有属性
    }
    //以下是实例的共有属性,也就相当于原型上的属性
    getName(){
        console.log(this.name);
    }
}   
let p = new Parent('yuhua');
p.getName();

其实,这个如果转成es5,大家就能明白其原理:

"use strict";

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;
  };
})();

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var Parent = (function() {
  function Parent(name) {
    _classCallCheck(this, Parent);

    this.name = name; //属于实例的私有属性
  }
  //以下是实例的共有属性,也就相当于原型上的属性

  _createClass(Parent, [
    {
      key: "getName",
      value: function getName() {
        console.log(this.name);
      }
    }
  ]);

  return Parent;
})();

var p = new Parent("yuhua");
p.getName();

这里用到了一个非常关键的技术点:defineProperties(>>关于defineProperties传送门<<)
对es5代码进行讲解:
6、ES6-object(含es5实现es6的类,未完待续)_object
这是整个代码的入口,仔细一看,其实就是返回了一个Parent,而这个Parent是什么?就是es5中的面向对象的形式——function Parent(){};那么,我们想要了解这个,就得了解这个Parent中的每一部分。
首先,我们来看function Parent中的内容
6、ES6-object(含es5实现es6的类,未完待续)_类_02
第一部分(先来看简单的):this.name = name这个就不需要解释了,将name通过Parent传入,并且挂在在this上,这是实例的私有属性。
第二部分:_classCallCheck()这个函数是什么作用呢?其实是做一个类的调用检查。具体如下:
6、ES6-object(含es5实现es6的类,未完待续)_class_03
参数:
instance 类的实例对象
Constructor 构造函数
关键语句:
instance instanceof Constructor 这个类的实例对象instance是否是构造函数Constructor的实例。确保它不被当做普通函数来调用。
整体:判定如果说这个传入的实例不是传入的这个构造函数的实例,那么就直接抛出错误。
然后,我们再来看看function Parent之外的_createClass
6、ES6-object(含es5实现es6的类,未完待续)_对象_04
这个其实就是添加了我们es6中的getName方法,方法名getName就是key,这个方法内容就是value。
那么这个方法是如何实现的呢?我们来看下es5的写法:
6、ES6-object(含es5实现es6的类,未完待续)_class_05
其中Object.defineProperty才是真正给类的原型对象上添加属性。


那么,这呢,就是通过es5来实现es6的类。不仅要学会es6的类的使用,更高明白这其中的原理。

2、类的静态属性和方法

es6明确规定,Class内部只有静态方法,没有静态属性。
在方法前添加static关键字,这是定义类的静态方法

class Parent{
    constructor(name){
        this.name = name;//属于实例的私有属性
    }
    //以下是实例的共有属性,也就相当于原型上的属性
    getName(){
        console.log(this.name);
    }
    static getAge(){
        console.log(18);
    }
}   
let p = new Parent('yuhua');
p.getName();

那么静态属性,在es5中是如何实现的?
其实很简单,上面所说的es5实现代码中,有一个_createClass方法,它的第三个参数就是静态方法

_createClass(
    Parent,
    [
      {
        key: "getName",
        value: function getName() {
          console.log(this.name);
        }
      }
    ],
    [
      {
        key: "getAge",
        value: function getAge() {
          console.log(18);
        }
      }
    ]
  );

五、类的继承

1、用extends和super关键字去继承
class Parent{
    constructor(name){
        this.name = name;
    }
    getName(){
        console.log(this.name);
    }
    static getAge(){
        console.log(18);
    }
}

class Child extends Parent{
    constructor(name,gender){
        super(name);
        this.gender = gender;
    }
    getGender(){
        console.log(this.gender);
    }
}

那么这个继承,是如何实现的呢?
咱们来看看es5的源码:

"use strict";

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;
  };
})();

function _possibleConstructorReturn(self, call) {
  if (!self) {
    throw new ReferenceError(
      "this hasn't been initialised - super() hasn't been called"
    );
  }
  return call && (typeof call === "object" || typeof call === "function")
    ? call
    : self;
}

function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError(
      "Super expression must either be null or a function, not " +
        typeof superClass
    );
  }
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
  if (superClass)
    Object.setPrototypeOf
      ? Object.setPrototypeOf(subClass, superClass)
      : (subClass.__proto__ = superClass);
}

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var Parent = (function() {
  function Parent(name) {
    _classCallCheck(this, Parent);

    this.name = name;
  }

  _createClass(
    Parent,
    [
      {
        key: "getName",
        value: function getName() {
          console.log(this.name);
        }
      }
    ],
    [
      {
        key: "getAge",
        value: function getAge() {
          console.log(18);
        }
      }
    ]
  );

  return Parent;
})();

var Child = (function(_Parent) {
  _inherits(Child, _Parent);

  function Child(name, gender) {
    _classCallCheck(this, Child);

    var _this = _possibleConstructorReturn(
      this,
      (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name)
    );

    _this.gender = gender;
    return _this;
  }

  _createClass(Child, [
    {
      key: "getGender",
      value: function getGender() {
        console.log(this.gender);
      }
    }
  ]);

  return Child;
})(Parent);
未完待续