创建对象
1. Object构造函数和对象字面量方法
const person = new Object() // 构造函数方法
person.name = 'tom'
const person = { // 对象字面量方法
name: 'tom'
}
2. 工厂模式
工厂模式是一种众所周知的设计模式,广泛的应用在软件工程领域, 用于抽象创建特性对象的过程。
function createPerson (name, age, job) {
let o = new Object()
o.name = name
o.age = age
o.job = job
o.sayName = function () { // 不能使用 箭头 函数,this的指向会有问题
console.log(this.name)
}
return o
}
const person = createPerson('tom', 27, 'student')
person.sayName() // tom
3. 构造函数模式(自定义)
ECMAScript中的构造函数就是用来穿件特性类型的对象的。
// function Person (name, age, job) {} 可以是函数声明式
const Person = function (name, age, job) { // 也可以是变量表达式
this.name = name
this.age = age
this.job = job
this.sayName = function () {
console.log(this.name)
}
}
const person = new Person('tom', 17, 'student') // 如果不传参数,Person的括号可以不写, 只要有 new 就能正常调用
person.sayName() // tom
/*
这里使用 Person()构造函数代替了上面 createPerson() 工厂函数
Person() 和 createPerson() 内部基本一样,只有以下区别
1. 没有显式的创建对象
2. 属性和方法直接赋值给this
3. 没有 return
4. Person 首字母大写了, 从面相对象借鉴,构造函数首字母大写,非构造函数首字母小写
*/
创建 Person实例时候的 new, 构造函数执行了一下操作:
- 在内存中创建一个新对象
- 这个新对象的内部的[[Property]]特性被赋值为构造函数的 property 属性
- 构造函数内部的 this 被赋值为这个新对象(this指向新对象)
- 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数返回非空对象, 则返回该对象,否则返回刚创建的新对象
上面的person对象保存着Person的实例, 所以 person 的constructor指向Person
person.constructor === Person // true
person instaceof Object // true
person instaceof Person // true
// instaceof 运算符用于检测 构造函数的 property 属性是否出现在某个实例对象的原型链上
1. 构造函数也是函数
构造函数与普通函数的区别就是调用方式的不同。任何函数只要能 new 就是构造函数, 不能 new 的函数就是普通函数
// 作为构造函数
const person = new Person('tom', 19, 'student')
person.sayName() // tom
// 作为普通函数调用
Person('jerry', 18, 'player') // 添加到 window 对象
window.sayName() // jerry
// 在调用一个函数而没有明确指出 this 的情况下(即没有作为对象的方法调用,或者没有使用call()/apply()调用),this始终指向 Global 对象
// 在另一个对象作用域中调用
let o = new Object()
Person.call(o, 'tommy', 28, 'cooker')
// 将 o 对象指定为 Person() 内部的 this, 所以 Person()的属性和方法都会添加到 o 对象上
o.sayName() // tommy
call、apply、bind
call和apply都是指定this指向。 apply接收两个参数:函数内this的值和一个参数数组。call与apply的不同只是参数的形式不同。call接收第一个参数this的值,后面剩下的参数是逐个传递。 两个都可以将任意对象设置为任意函数的作用域。
function sum (num1, num2) {
return num1 + num2
}
function callSum1 (num1, num2) {
return sum.apply(this, arguments)
}
function callSum2 (num1, num2) {
return sum.apply(this, [num1, num2])
}
console.log(callSum1(10, 10)) // 20
console.log(callSum2(10, 10)) // 20
function callSum3 (num1, num2) {
return sum.call(this, num1, num2)
}
console.log(callSum3(10, 10)) // 20
bind方法会创建一个新的函数实例,其this值为被绑定到传给bind()的对象
window.color = 'red'
const o = {
color: 'blue'
}
function sayColor () {
console.log(this.color)
}
const objSayColor = sayColor.bind(o)
objSayColor() // blue
2. 构造函数的问题
参考 红宝书 233页 第四版
4. 原型模式
每个函数都会创建一个property属性,这个属性是一个对象, 包含应该由特定引用类型的实例共享的属性和方法。这个对象就是通过构造函数创建的对象的原型。 在property上定义的属性和方法可以被对象实例共享
const Person = function () {}
Person.prototype.name = 'tom'
Person.prototype.age = 20
Person.prototype.job = 'student'
Person.prototype.sayName = function () {
console.log(this.name)
}
const person1 = new Person()
person1.sayName() // tom
const person2 = new Person()
console.log(person1.sayName === person2.sayName) // true 解决了构造函数每次实例化都会创建新的函数的问题
网友评论