理解JavaScript对象
- JavaScript创建对象的方法
// new Object()
let obj1 = new Object()
// 对象字面量
let obj2 = {
name1: "name1",
sayName: function() {
return this.name
}
}
- 在JavaScript对象中每个属性都有4个特性, 可以用defineProperty来修改
- [[Configurable]] (默认为true,能否删除,修改,一旦将其设置为false,将不能再设置为true)
- [[Enumerable]] (能否通过for in 循环获取,默认为true)
- [[Writable]] (能否修改属性的值,默认为true)
- [[Value]] (读取和写入属性的时候对应这个位置)。
Object.defineProperty(obj2, 'name1', {
writable: false,
value: 'wang'
})
obj2.name1 = "!23"
console.log(obj2.name1); // wang
在调用defineProperty创建一个新属性的时候,Configurable, Enumerable, Writable 默认都为false
- 访问器属性
- [[Configurable]] (默认为true,能否删除,修改,一旦将其设置为false,将不能再设置为true)
- [[Enumerable]] (能否通过for in 循环获取,默认为true)
- [[Get]] 默认undefined
- [[Set]] 默认undefined
var book = {
_year : 2004,
edition : 1
};
Object.defineProperty(book,"year",{
get : function () {
return this._year;
},
set : function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
book.year = 2005;
console.log(book.edition); // 2
- 读取属性特性 Object.getOwnPropertyDescriptor()
创建对象
创建工厂模式(设计模式)
- 优点:解决创建多个重复对象的问题
- 缺点:没办法识别person对象属于哪个类型
// 工厂模式
function createPerson(name, age, job) {
let obj = new Object();
obj.name = name;
obj.age = age;
obj.job = job;
obj.sayName = function() {
return this.name;
}
return obj;
};
let person1 = createPerson("name1", 11, "Engineer");
let person2 = createPerson("name2", 12, "Student");
构造函数模式
- 优点: 工厂模式优点 + 可以识别对象的类型
- 缺点: 不能重用function属性,每个对象都新建一遍function
// 构造函数模式
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
return this.name;
}
};
let person3 = new Person("name1", 11, "Engineer");
let person4 = new Person("name2", 12, "Student");
alert(person4.sayName == person3.sayName); // false
new 的过程
- 创建一个新的对象
- 将构造函数的作用域赋值给新对象(this指向了新对象)
- 执行构造函数中的代码(为这个新对象[this]添加属性)
- 返回新对象(返回this)
原型模式
- 原型上的属性和方法在实例上可以共享
- 优点:共享
- 缺点:方法适合共享,但属性不适合共享
// 原型模式
function Person() {
};
Person.prototype.name = "Name1";
Person.prototype.age = 11;
Person.prototype.job = "students";
Person.prototype.sayName = function() {
return this.name;
}
let person3 = new Person();
person3.sayName(); // Name1
let person4 = new Person();
person4.sayName(); // Name1
alert(person4.sayName == person3.sayName); // true
组合使用构造函数和原型模式(推荐使用)
- 原则: 共享属性在prototype中定义,实例属性在构造函数中定义
// 组合使用构造函数和原型模式
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
};
Person.prototype = {
constructor: Person,
sayName: function() {
return this.name;
}
};
let person1 = new Person("name1", 11, "Engineer");
let person2 = new Person("name2", 12, "Student");
alert(person1.name == person2.name) // false
alert(person1.sayName == person2.sayName) // true
动态原型模式
- 简介:用构造函数的样子实现 “组合使用构造函数和原型模式(推荐使用)”。类似语法糖。
- 注意:动态原型模式不能重写构造函数的原型,会切断构造函数中原型操作
// 动态原型模式
// 在第一次new时候将共享属性添加到构造函数的原型(prototype)中
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
if (typeof this.sayName != "function") {
Person.prototype.sayName = function() {
return this.name
}
}
};
寄生构造函数模式
我觉得不用了解了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。简直疑难杂症
稳妥构造函数模式
- 简介:通过闭包实现私有变量的构造函数,
- 与工厂模式的区别:工厂模式将属性挂在return的对象上return出去,稳妥构造函数没有将属性挂在object上直接return出去
function Person(name) {
var o = new Object;
let _name = name;
o.sayName = function() {
return _name;
}
return o;
}
let person = Person("Wang");
alert(person.sayName()) // Wang
alert(person.name) // undefined
继承
原型链(一般不用)
- 实现方式: 子类的原型指向父类的实例
- 子类的prototype === 子类实例化的__proto__属性
- 缺点:
- 属性也被继承
- 子类没办法传值给父类的同时不影响其他对象实例
/// prototype
function SuperType() {
this.superString = "superString";
}
SuperType.prototype.getSupertring = function() {
return this.superString;
}
function SubType() {
this.subString = "subString"
}
SubType.prototype = new SuperType();
SubType.prototype.getSubString = function() {
return this.subString;
}
let sub = new SubType();
sub.getSubString() // "subString"
sub.getSupertring() // "superString"
SubType.prototype === sub.__proto__ // true
借用构造函数(经典继承)
- 优点: 解决原型链继承缺点
- 缺点: function都在父类中定义的化,每次都会新建而不是复用
// 解决原型链继承缺点1
function SuperType() {
this.color = ['red', 'blue', 'yellow']
}
function SubType() {
// 继承SuperType
SuperType.call(this);
}
let ins1 = new SubType();
ins1.color.push("green");
alert(ins1.color) // red, blue, yellow, green
let ins2= new SubType();
alert(ins2.color) // red, blue, yellow
- 传递参数
function SuperType(args) {
this.color = args
}
function SubType(args) {
// 继承SuperType,同时还传递了参数,可以将公共类的属性放到父类
SuperType.call(this, args);
// 特有属性放在子类
this.age = 12
}
let ins1 = new SubType("green");
alert(ins1.color) // green
alert(ins1.age)
let ins2 = new SubType("green2");
alert(ins1.color) // green2
alert(ins1.age)
组合继承(最常用)
- 简介:结合借用构造函数继承和原型链继承两种方式实现
// 1. 父类构造函数 存储属性
function SuperType(name) {
this.name = name || "no name";
this.colors = ["red", "blue"];
}
// 2. 父类原型 存储公用方法
SuperType.prototype.sayName = function() {
return this.name;
}
// 3. 子类构造函数
function SubType(name, age) {
// 4. 继承SuperType构造函数中的属性,同时还传递了参数,可以将公共类的属性放到父类
SuperType.call(this, name);
// 特有属性放在子类
this.age = age;
}
// 5. 建立supertype的原型方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
// 6. 子类公共方法
SubType.prototype.sayAge = function() {
return this.age;
}
let ins1 = new SubType("name11", 23);
ins1.colors.push("testColor");
alert(ins1.colors) // red, blue, testColor
alert(ins1.sayName()) // name11
alert(ins1.sayAge()) // 23
let ins2 = new SubType("name22", 22);
alert(ins2.colors) // red, blue
alert(ins2.sayName()) // name22
alert(ins2.sayAge()) // 22
原型式继承
object.create() 原理