0-_1解析构造函数

70 阅读4分钟

要解析,就得先说明什么是构造函数? 就是你调用一个函数,然后它返回了对象这个函数就叫构造函数。 要求:创建一个有name和age的对象

function Person(name, age) {
  name = name || '匿名'
  age = age || 0
  const obj = {
    name: name,
    age: age
  }
  return obj
}


用ES6改造

function Person(name = "匿名",age = 0){
	return {name,age)
}

image.png f是由Person构造出来的对象 简称 f是Person对象 要求2:所有的Person对象都能 sayHi

function Person(name = '匿名', age = 0) {
  return {
    name,
    age, 
    sayHi() {
      console.log(`你好,我是 ${name}`)
    }
  }
}

要求3:将f1.sayHi和f2.sayHi合2为1

const sayHi = function(){
  console.log(`你好,我是 ${this.name}`)
}
function Person(name = '匿名', age = 0) {
  return { name, age, sayHi }
}

要求4:增加run函数

const sayHi = function () {
  console.log(`你好,我是 ${this.name}`)
}
const run = function () {
  console.log(`${this.name} 在跑步`)
}
function Person(name = '匿名', age = 0) {
  return { name, age, sayHi, run }
}

一个毛病:全局变量太多 要求5:尽量少的全局变量

const Person共有属性 = {
  sayHi: function () {
    console.log(`你好,我是 ${this.name}`)
  },
  run: function () {
    console.log(`${this.name} 在跑步`)
  }
}
function Person(name = '匿名', age = 0) {
  return { 
    name, 
    age, 
    sayHi: Person共有属性.sayHi, 
    run: Person共有属性.run 
  }
}

要求6:只能用一个变量名

function Person(name = '匿名', age = 0) {
  return { 
    name, 
    age, 
    sayHi: Person.共有属性.sayHi, 
    run: Person.共有属性.run 
  }
}
Person.共有属性 = {
  sayHi() {
    console.log(`你好,我是 ${this.name}`)
  },
  run() {
    console.log(`${this.name} 在跑步`)
  }
}

要求7:用隐藏属性

function Person(name = '匿名', age = 0) {
  const obj = Object.create(Person.共有属性);
  // 相当于 obj = {隐藏属性: Person.共有属性}
  // Object.create()创建一个空对象,指导一个现有对象作为空对象的原型
  obj.name = name
  obj.age = age
  return obj
}
Person.共有属性 = {
  sayHi() {
    console.log(`你好,我是 ${this.name}`)
  },
  run() {
    console.log(`${this.name} 在跑步`)
  }
}

image.png 这就是现在常用的构造函数,只要new一下,前面操作就帮你做了

function Person(name = '匿名', age = 0) {
  // person的自有属性
  this.name = name
  this.age = age
}
Person.prototype = {
  // person的共有属性
  constructor: Person,
  sayHi() {
    console.log(`你好,我是 ${this.name}`)
  },
  run() {
    console.log(`${this.name} 在跑步`)
  }
}
const f1 = new Person('fang', 18)
f1.sayHi()
f1.run()

ES6增加了class写法

class Person {
  constructor(name = '匿名', age = 0) {
    this.name = name
    this.age = age
  }
  sayHi() {
    console.log(`你好,我是 ${this.name}`)
  }
  run() {
    console.log(`${this.name} 在跑步`)
  }
}

对于构造函数来说共有属性不一定是函数,自有属性也不一定不是函数 对于class来说共有属性一定是函数,自有属性可以写函数


class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// 佐证:User 是一个函数
alert(typeof User); // function

class User {...} 构造实际上做了如下的事儿:

  1. 创建一个名为 User 的函数,该函数成为类声明的结果。该函数的代码来自于 constructor 方法(如果我们不编写这种方法,那么它就被假定为空)。
  2. 存储类中的方法,例如 User.prototype 中的 sayHi。
  3. 人们常说 class 是一个语法糖,因为我们实际上可以在不使用 class 的情况下声明相同的内容:
function User(name) {
  this.name = name;
}
// 函数的原型(prototype)默认具有 "constructor" 属性,
// 所以,我们不需要创建它

// 2. 将方法添加到原型
User.prototype.sayHi = function() {
  alert(this.name);
};

// 用法:
let user = new User("John");
user.sayHi();

这个定义的结果与使用类得到的结果基本相同。因此,这确实是将 class 视为一种定义构造器及其原型方法的语法糖的理由。 但是它们之间存在着重大差异:

  1. 首先,通过 class 创建的函数具有特殊的内部属性标记 [[IsClassConstructor]]: true。因此,它与手动创建并不完全相同。编程语言会在许多地方检查该属性。例如,与普通函数不同,必须使用 new 来调用它
  2. 类方法不可枚举。 类定义将 "prototype" 中的所有方法的 enumerable 标志设置为 false。这很好,因为如果我们对一个对象调用 for..in 方法,我们通常不希望 class 方法出现。
  3. 类总是使用 use strict。 在类构造中的所有代码都将自动进入严格模式。

class 字段 类字段是最近添加到语言中的,之前我们的类仅具有方法,类字段是一种允许添加任何属性的语法。 例如在class User 中添加 name 属性

class User {
  name = "John";

  sayHi() {
    alert(`Hello, ${this.name}!`);
  }
}

new User().sayHi(); // Hello, John!

注:旧的浏览器不支持 可以使用类字段制作绑定方法: 比如对函数的this进行绑定

class Button {
  constructor(value) {
    this.value = value;
  }

  click() {
    alert(this.value);
  }
}

let button = new Button("hello");

setTimeout(button.click, 1000); // undefined

解决方法:

class Button {
  constructor(value) {
    this.value = value;
  }
  click = () => {
    alert(this.value);
  }
}

let button = new Button("hello");

setTimeout(button.click, 1000); // hello

类字段 click = () => {...} 是基于每一个对象被创建的,在这里对于每一个 Button 对象都有一个独立的方法,在内部都有一个指向此对象的 this。我们可以把 button.click 传递到任何地方,而且 this 的值总是正确的。