构造函数-扩展

参考: https://juejin.im/post/5e707417e51d45272054d5d3
var a = {} ,是var a = new Object()的语法糖
var b= [], 是var a = new Array()的语法糖 ,
function Foo() , 是var a = new function()的语法糖

ES6前

没有class这个概念,它是借助于原型对象和构造函数来实现

私有属性和方法

只能在构造函数内访问不能被外部所访问(在构造函数内使用var声明的属性)

公有属性和方法(实例方法)

对象外可以访问到对象内的属性和方法(在构造函数内使用this设置,或者设置在构造函数原型对象上比如Cat.prototype.xxx)
(至于实例方法,想想push、shift,它们实际上不是存在于原型对象上的吗?Array.prototype.push

静态属性和方法

定义在构造函数上的方法(比如Cat.xxx),不需要实例就可以调用(例如Object.assign())
(也有小伙伴可能会有疑问,这个静态属性和方法是有什么用的啊,感觉我们编码的时候并没有用到过啊。Really? 哈哈 😄,Promise.all()、Promise.race()、Object.assign()、Array.from()这些不就是吗?)

总结

  • 在函数内用var定义的就是私有的
  • 在函数内用this承接的就是公有
  • 在构造函数上也就是使用Cat.xxx定义的是静态属性和方法
  • 在构造函数内使用this设置,或者设置在构造函数原型对象上比如Cat.prototype.xxx,就是公有属性和方法(实例方法)

定义在构造函数原型对象上的属性和方法虽然不能直接表现在实例对象上,但是实例对象却可以访问或者调用它们
既然我们已经知道了实例自身的属性定义在构造函数原型对象中的属性的区别,那么我们一般是如何区分它们的呢

  1. function Cat (name) {
  2. this.name = name
  3. }
  4. Cat.prototype.prototypeProp = '我是构造函数原型对象上的属性'
  5. Cat.prototype.cleanTheBody = function () {
  6. console.log('我会用唾液清洁身体')
  7. }
  8. var guaiguai = new Cat('guaiguai')
  9. for (key in guaiguai) {
  10. if (guaiguai.hasOwnProperty(key)) {
  11. console.log('我是自身属性', key)
  12. } else {
  13. console.log('我不是自身属性', key) }
  14. }
  15. console.log('-分隔符-')
  16. console.log(Object.keys(guaiguai))
  17. console.log(Object.getOwnPropertyNames(guaiguai))

实例的方法是否共享

不共享

  1. function Star() {
  2. this.sing = function () {
  3. console.log('我爱唱歌');
  4. }
  5. }
  6. let stu1 = new Star();
  7. let stu2 = new Star();
  8. stu1.sing();//我爱唱歌
  9. stu2.sing();//我爱唱歌
  10. console.log(stu1.sing === stu2.sing);//false

共享

  1. function Star(name) {
  2. this.name = name;
  3. }
  4. Star.prototype.sing = function () {
  5. console.log('我爱唱歌', this.name);
  6. };
  7. let stu1 = new Star('小红');
  8. let stu2 = new Star('小蓝');
  9. stu1.sing();//我爱唱歌 小红
  10. stu2.sing();//我爱唱歌 小蓝
  11. console.log(stu1.sing === stu2.sing);//true

原型上添加方法

  • 原型对象上直接添加方法,此时的原型对象是有constructor构造器的
    ```javascript function Star(name) {
    1. this.name = name;
    } Star.prototype.dance = function () {
    1. console.log(this.name);
    }; let obj = new Star(‘小红’); console.log(obj.proto); //{dance: ƒ, constructor: ƒ}
    1. console.log(obj.__proto__.constructor); // Star
  1. - Star.protoType = {}给原型重新赋值,此时会丢失构造器,需要手动定义构造器<br />
  2. ```javascript
  3. function Star(name) {
  4. this.name = name;
  5. }
  6. Star.prototype = {
  7. dance: function () {
  8. console.log(this.name);
  9. }
  10. };
  11. let obj = new Star('小红');
  12. console.log(obj.__proto__); //{dance: ƒ}
  13. console.log(obj.__proto__.constructor); // ƒ Object() { [native code] }
  14. Star.prototype.constructor = Star;

一般不允许改变prototype的指向
正常

  1. Array.prototype.getSum = function (arr) {
  2. let sum = 0;
  3. for (let i = 0; i < this.length; ++i) {
  4. sum += this[i];
  5. }
  6. return sum;
  7. };
  8. let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  9. console.log(arr.getSum());//45

报错- is not a function

  1. Array.prototype = {
  2. getSum: function (arr) {
  3. let sum = 0;
  4. for (let i = 0; i < this.length; ++i) {
  5. sum += this[i];
  6. }
  7. return sum;
  8. }
  9. };
  10. let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  11. console.log(arr.getSum());//45

构造函数总结:

把客观事物封装成抽象的类,隐藏属性和方法,仅对外公开接口
有私有属性,公有属性, 静态属性分概念和方法
实例对象上的属性和构造函数原型上的属性
遍历实例对象属性的三种方法
使用for...in...能获取到实例对象自身的属性和原型链上的属性
使用Object.keys()Object.getOwnPropertyNames()只能获取实例对象自身的属性
可以通过.hasOwnProperty()方法传入属性名来判断一个属性是不是实例自身的属性

ES6后

新增了class,并且类的数据类型就是函数,所以用法上和构造函数很像,直接用new命令来配合它创建一个实例。

类的所有方法都定义在类的prototype属性上面

  1. class Cat {
  2. constructor() {
  3. }
  4. toString () {}
  5. toValue () {}
  6. }

等同于

  1. function Cat () {}
  2. Cat.prototype = {
  3. constructor() {}
  4. toString () {}
  5. toValue () {}
  6. }