创建对象的方式
1. 字面量
var o1 = { name: 'o1' };
var o2 = new Object({ name: 'o2' });
2. 通过构造函数
var M = function(name) { this.name = name;}
var o3 = new M('o3');
3. Object.create()
使用Object.create(p)方法创建的对象,原型对象是参数
var p = { name: 'o4' };
var o4 = Object.create(p);
三种创建方式的结果展示:

原型链
1. 构造函数、实例以及原型对象的关系
var M = function(name) {
this.name = name;
}
var o3 = new M('o3');
console.log(o3);
console.log(o3.constructor === M); // true
console.log(o3.__proto__ === M.prototype); // true
console.log(M.prototype.constructor === M) // true
2. instanceof
作用:检测原型
原理:判断实例对象的__proto__ 和 构造函数的prototype 是不是同一个引用
var M = function(name) {
this.name = name;
}
var o3 = new M('o3');
console.log(o3 instanceof M); // true
console.log(o3 instanceof Object); // true
console.log(o3.__proto__ === M.prototype); // true
console.log(M.prototype.__proto__ === Object.prototype); // true
3. constructor
作用:区分一个对象具体是谁实例化的
var M = function(name) {
this.name = name;
}
var o3 = new M('o3');
console.log(o3.constructor === M); // true
console.log(o3.constructor === Object); // false
类的声明
/** * 类的声明 */function Animal() { this.name = 'name';
}/** * ES6中class声明 */class Animal2 { constructor() { this.name = 'name'; }}
/** * 实例化 */
console.log(new Animal(), new Animal2())
类的继承
1. 借助构造函数实现继承
原理:改变了Parent1中的this指向
缺点:Parent1原型链上的方法并没有被Child1继承,只实现了部分继承
/**
* 借助构造函数实现继承(实现了部分继承)
* 原理:改变了Parent1中的this指向,
* 缺点:Parent1原型链上的方法并没有被Child1继承
*/
function Parent1() {
this.name = 'Parent1';
}
Parent1.prototype.say = function() {};
function Child1() {
Parent1.call(this); // apply 改变this指向
this.type = 'Child1';
}
var s1 = new Child1();
console.log(s1); // Child1 {name: "Parent1", type: "Child1"}
console.log(s1.constructor === Parent1) // true
2. 借助原型链实现继承
缺点:假如实例化两个对象,改变其中一个,另一个也会跟着变化
原因:因为原型链中的原型对象是共用的,s2_1.proto = s2_2.proto
/**
* 借助原型链实现继承
* 缺点:假如实例化两个对象,改变其中一个,另一个也会跟着变化
* 原因:因为原型链中的原型对象是共用的,s2_1.__proto__ = s2_2.__proto__
*/
function Parent2() {
this.name = 'Parent2';
this.play = [1, 2, 3];
}
function Child2() {
this.type = 'Child2';
}
Child2.prototype = new Parent2();
var s2_1 = new Child2();
var s2_2 = new Child2();
s2_1.play.push(4);
console.log('s2_1(push 4):', s2_1.play); // s2_1(push 4): [1, 2, 3, 4]
console.log('s2_2:', s2_2.play); // s2_1: [1, 2, 3, 4]
console.log(s2_1.__proto__ === Child2.prototype, Child2.prototype.__proto__ === Parent2.prototype); // true true
console.log(s2_1.constructor === Parent2); // trueconsole.log(s2_1.__proto__ === s2_2.__proto__); // true
3. 组合方式
缺点:
① 实例化子类时,父类执行了两次(new时、原型链上)
② 对象是由父类实例化的(使用constructor验证)
/**
* 组合方式
* 缺点:① 实例化子类时,父类执行了两次(new时、原型链上)
* ② 对象是由父类实例化的
*/
function Parent3() {
this.name = 'Parent3';
this.play = [1, 2, 3];
}
function Child3() {
Parent3.call(this); // apply 改变this指向
this.type = 'Child3';
}
Child3.prototype = new Parent3();
var s3_1 = new Child3();
var s3_2 = new Child3();
s3_1.play.push(4);
console.log('s3_1(push 4):', s3_1.play); // s3_1(push 4): [1, 2, 3, 4]
console.log('s3_2:', s3_2.play); // s3_1: [1, 2, 3]
4. 组合继承优化方式1
仍然存在的缺点:对象是由父类实例化的
/**
* 组合继承优化方式1
* 缺点:对象是由父类实例化的
*/
function Parent4() {
this.name = 'Parent4';
this.play = [1, 2, 3];
}
function Child4() {
Parent4.call(this); // apply 改变this指向
this.type = 'Child4';
}
Child4.prototype = Parent4.prototype;
var s4 = new Child4();
s4.play.push(4);
console.log('s4:', s4 instanceof Child4, s4 instanceof Parent4);
// 怎么区分一个对象是父类实例化的,还是子类实例化的
// 使用 constructor属性
console.log(s4.constructor == Parent4);
5. 组合继承优化方式2
注意事项:Object.create(Parent5.prototype) 创建的对象 原型对象是参数
/**
* 组合继承优化方式2
* Object.create(Parent5.prototype) 创建的对象 原型对象是参数
*/
function Parent5() {
this.name = 'Parent5';
this.play = [1, 2, 3];
}
function Child5() {
Parent5.call(this); // apply 改变this指向
this.type = 'Child5';
}
Child5.prototype = Object.create(Parent5.prototype);
Child5.prototype.constructor = Child5;
var s5 = new Child5();
console.log('s5:', s5 instanceof Child5); // true true
// 怎么区分一个对象是父类实例化的,还是子类实例化的
// 使用 constructor属性
console.log(s5.constructor == Parent5); // false
console.log(s5); // Child5 {name: "Parent5", play: Array(3), type: "Child5"}