理解对象
ECMA-262 将对象定义为一组属性的无序集合
属性的类型
- 数据属性
- [[Configurable]] 表示能否通过 delete 删除属性、能否修改属性的特性
- [[Enumerable]] 目标属性是否可被枚举(遍历)
- [[Writable]] 表示能否修改属性的值,即值是可写的还是只读
- [[Value]] 包含这个属性的数据值。读取属性时从这个位置读取;写入属性时,把新值保存在这个位置
- 访问器属性
- [[Configurable]] 表示能否通过 delete 删除属性、能否修改属性的特性
- [[Enumerable]] 目标属性是否可被枚举(遍历)
- [[Get]] 在读取属性时调用的函数。默认值是 undefined。
- [[Set]] 在写入属性时调用的函数。默认值是 undefined。
创建对象
工厂模式 (没有解决对象标识问题)
function createPerson(name, age, job) {
let o = new Object()
o.name = name
o.age = age
o.job = job
o.sayName = function () {
console.log(this.name)
}
}
let c1 = createPerson("a", 22, "a")
let c2 = createPerson("b", 28, "b")
构造函数模式(所有定义的方法都会实例化一遍)
function Person(name, age, job) {
this.name = name
this.age = age
this.job = job
this.sayName = function () {
console.log(this.name)
}
}
let p1 = new Person("a", 22, "a")
let p2 = new Person("b", 28, "b")
原型模式(属性和方法所有实例共享)
let Per = function () {}
Per.prototype.name = "a"
Per.prototype.age = 22
Per.prototype.job = "a"
Per.prototype.sayName = function () {
console.log(this.name)
}
let per1 = new Per
let per2 = new Per
per1 与 per2 的 proto 属性指向原型 Per
对象迭代
-
Object.values() 返回对象值的数组
-
Object.entries() 返回键/值对的数组
-
Object.keys() 返回一个数组,包括对象自身的(不含继承的)
-
Object.getOwnPropertyNames() 包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)
-
for in 循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
继承
首先定义一个父类:
function Animal(name) {
this.name = name
}
Animal.prototype.eat = function (food) {
console.log(this.name + "正在吃" + food)
}
Animal.prototype.makeSound = function () {}
原型链
将父类的示例作为子类的原型实现继承
function Duck() {}
Duck.prototype = new Animal("鸭子")
Duck.prototype.makeSound = function () {
console.log("嘎嘎嘎")
}
let duck = new Duck()
duck.eat("小米")
duck.makeSound()
盗用构造函数
使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类
function Dog() {
Animal.call(this)
this.name = "狗"
this.makeSound = function () {
console.log("汪汪汪")
}
}
let dog = new Dog()
dog.makeSound()
注意:**这里 dog 无法拥有 eat 方法 **
组合继承
通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
function Chicken() {
Animal.call(this)
this.name = "鸡"
}
Chicken.prototype = new Animal()
Chicken.prototype.makeSound = function () {
console.log("咯咯咯")
}
let chicken = new Chicken()
chicken.eat("小米")
chicken.makeSound()
寄生组合继承
通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function Cow() {
Animal.call(this)
this.name = "牛"
}
(function () {
let Super = function () {}
Super.prototype = Animal.prototype
Cow.prototype = new Super()
Cow.prototype.constructor = Animal
})()
Cow.prototype.makeSound = function () {
console.log("哞哞哞")
}
let cow = new Cow()
cow.eat("草")
cow.makeSound()