创建对象方式
工厂模式 无法正确识别出对象类型
function createObject(color, start){
const obj = new Object();
obj.color = color;
obj.start = start;
}
createObject('white');
createObject('red');
构造函数模式
function createObject(color){
this.color = color;
this.start = function(){}
}
const white = createObject('white');
const black = createObject('black');
优点:改变对象的属性和方法,不会影响到其他对象;
缺点:this上挂载的对象都是面向对象的,当新建一个对象的时候,this上的属性都可以复制一份,浪费空间;
原型模式
function createObject(color){
this.color = color;
}
createObject.prototype.start = function(){ console.log('原型上的方法');};
const white = createObject('white');
const black = createObject('black');
优点:start方法只会在内存中存一份,调用同一函数
静态属性
绑定在构造函数上的属性,通过构造函数访问
function createObject(color){
this.color = color;
if(!createObject.total){
createObject.total = 0;
}
createObject.total++;
}
const white = createObject('white');
const black = createObject('black');
console.log(createObject.total);
原型链
原型链
function Player(color){
this.color = color;
}
Player.prototype.start = function() {};
var white = new Player('white');
var black = new Player('black');
console.log(white.__proto__);
console.log(Object.getPrototypeOf(white));
console.log(Player.prototype);
new
new关键字做了什么
- 一个继承Player.prototype的新对象white/black被创建
- white._ proto_ 指向 Player.prototype
- 将this指向新创建的对象
- 返回这个对象
-
- 如果构造函数没有显示的返回值,则返回this
-
- 如果构造函数有显示的返回值,返回值是基本类型,则返回this
-
- 如果构造函数有显示的返回值,返回值是对象类型,则返回这个对象,null除外。
function NewOption(){
var obj = new Object();
constructor = [].shift.call(arguments);
obj.__proto__ = constructor.prototype
var retrunObj = constructor.apply(obj,arguments);
if(typeof returnObj === 'object' && returnObj !== null){
return returnObj;
}
return obj;
}
继承
1、原型链继承
function Parent(){
this.name = "parent"
}
Parent.prototype.getName = function (){
console.log(this.name);
return this.name;
}
function Child(){}
// 原型链继承
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const child1 = new Child();
var child2 = new Child();
child1.getName();
隐含的问题:
1、如果属性是引用类型,一旦其中一个实例更改了其值,那么所有实例都会受影响。
2、创建child的时候无法传参。
2、构造函数继承
function Parent(name,actions){
this.action = actions;
this.name = name;
this.eat = function(){
console.log(`${name}-eat`)
}
}
function Child(name, actions){
Parent.call(this, name, actions);
}
const c1 = new Child('c1', ['eat']);
const c2 = new Child('c2', ['eat', 'sleep']);
c1.action.pop();
console.log(c1.action);
console.log(c2.action);
属性和方法被继承的话,只能在构造函数中定义
如果方法都在构造函数定义了,那么每次创建实例都会见一份,多占内存
3、组合继承
function Parent(name, actions){
this.name = name;
this.action = actions;
}
Parent.prototype.eat = function(){
console.log(`${this.name}---eat`);
console.log(`${this.action}-----`)
}
function Child(id){
Parent.apply(this, Array.from(arguments).slice(1));
this.id = id;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const c1 = new Child(1, 'c1', 'hahahha');
const c2 = new Child(2, 'c2', 'xixixixi');
console.log(c1.name);
console.log(c2.name);
c1.eat();
c2.eat();
调用了2次构造函数Parent,做了重复操作
4、寄生组合继承
function Parent(name, actions){
this.name = name;
this.action = actions;
}
Parent.prototype.eat = function(){
console.log(`${this.name}---eat`);
console.log(`${this.action}-----`)
}
function Child(id){
Parent.apply(this, Array.from(arguments).slice(1));
this.id = id;
}
// Child.prototype = new Parent();
// 寄生式函数组合调用
// let tmpFunction = function() {}
// tmpFunction.prototype = Parent.prototype;
// Child.prototype = new tmpFunction();
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const c1 = new Child(1, 'c1', 'hahahha');
const c2 = new Child(2, 'c2', 'xixixixi');
console.log(c1.name);
console.log(c2.name);
c1.eat();
c2.eat();
5、class
class Parent{
constructor(name){
this.name = name
}
eat(){
console.log(`${this.name}----eat`);
}
}
class Child extends Parent{
constructor(name){
super(...arguments);
}
}
const c1 = new Child('c1');
const c2 = new Child('c2');
c1.eat();
c2.eat();