要解析,就得先说明什么是构造函数? 就是你调用一个函数,然后它返回了对象这个函数就叫构造函数。 要求:创建一个有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)
}
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} 在跑步`)
}
}
这就是现在常用的构造函数,只要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 {...} 构造实际上做了如下的事儿:
- 创建一个名为 User 的函数,该函数成为类声明的结果。该函数的代码来自于 constructor 方法(如果我们不编写这种方法,那么它就被假定为空)。
- 存储类中的方法,例如 User.prototype 中的 sayHi。
- 人们常说 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 视为一种定义构造器及其原型方法的语法糖的理由。 但是它们之间存在着重大差异:
- 首先,通过 class 创建的函数具有特殊的内部属性标记 [[IsClassConstructor]]: true。因此,它与手动创建并不完全相同。编程语言会在许多地方检查该属性。例如,与普通函数不同,必须使用 new 来调用它
- 类方法不可枚举。 类定义将 "prototype" 中的所有方法的 enumerable 标志设置为 false。这很好,因为如果我们对一个对象调用 for..in 方法,我们通常不希望 class 方法出现。
- 类总是使用 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 的值总是正确的。