View on GitHub

baidu-ife

百度前端学院的练习及笔记

1 面向对象

1.1 创建对象

1.1.1 工厂模式

function createNewPerson(name) {
    var obj = {};
    obj.name = name;
    obj.greeting = function () {
        alert('Hi! I\'m ' + this.name + '.');
    }
    return obj;
}
var person = createNewPerson("Lee");

缺点: 不能识别对象

1.1.2 构造函数模式

function Person(name) {  //构造函数用大写开头
  this.name = name;
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name + '.');
  };
}
var person1 = new Person("Lee");  
//若不使用new,this将会指向window

使用 new 时:

  1. 创建新对象;
  2. 新对象的__proto__指向了父类的prototype成员对象
  3. this指向新对象;
  4. 为新对象增加属性
  5. 返回新对象

constructor属性: 标识对象类型(指向创建该实例的构造器函数)
但是一般还是使用instanceof验证
PS: instanceName.constructor.name 构造器的名字

缺点: 每个方法都要在每个实例上重新创建一遍

1.1.3 原型模式

function Person() {
}
Person.prototype.name = "Lee";  //属性定义不灵活
Person.prototype.greeting = function() {
    alert('Hi! I\'m ' + this.name + '.');
};
var person1 = new Person();

优点: 动态更新
缺点: 属性定义不灵活/所有实例共享属性

原型对象

让所有对象实例共享它所包含的属性和方法(用于存放希望被原型链下游的对象继承的属性和方法)

img

img

prototype属性:指向其原型对象。

通过__proto__([[prototype]])查找对象的原型对象

//__proto__
person1.__proto__ == Person.prototype;
//isPrototypeOf()  原型对象和实例的关系
Person.prototype.isPrototypeOf(person1) == true;
//Object.getPrototypeOf()
Object.getPrototypeOf(person1) == Person.prototype;

判断是否存在某属性(实例属性/原型属性)

in

"name" in person1;

判断访问的是实例属性还是原型属性

hasOwnProperty()方法

person1.hasOwnProperty("name");
//true为实例, false为原型

重写原型对象的问题

  1. 重写了默认的prototype对象,constructor属性变为了新的对象的constructor属性
  2. 切断了现有原型与任何之前已经存在的对象实例之间的联系

1.1.4 组合使用构造函数模式和原型模式

使用最广泛、认同度最高的创建自定义类型的方法

function Person(name) {
	this.name = name;
}
Person.prototype.greeting = function() {
    alert('Hi! I\'m ' + this.name + '.');
};
var person1 = new Person("Lee");

1.2 继承

1.2.1 原型链

核心: 原型对象等于另一个对象的实例 SubType.prototype = new SuperType();

function SuperType() {
	this.property = true;
}
SuperType.prototype.getSuperType = function() {
	return this.property;
}
function SubType() {
	this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
	return this.subproperty;
}
var instance = new SubType();

注意

  1. 上述的property属性将会位于SubType.prototype中, 因为他是一个实例属性; 而getSuperType()原型方法还在SuperType.prototype中
  2. instance.constructor == SubType.prototype.constructor == SuperType
  3. 所有的函数原型都是Object的实例
  4. instanceisPrototypeOf()可用于判断原型和实例的关系

缺点

  1. 由于SubType.prototype = new SuperType(), 超类来的实例属性将会变为现在的**原型属性** ==> 所有的SubType实例都会共享这个属性(不应该被共享的实例属性到了原型对象中被共享了)
  2. 没办法在不影响所有实例的情况下, 给超类SuperType()传递参数

1.2.2 借用构造函数

核心: 子类型构造函数内调用父类型构造函数 SuperType.call(this);/SuperType.apply(this)

function SuperType() {
	this.colors = ["red", "blue"];
}
function SubType() {
	SuperType.call(this);
}
var instance = new SubType();

call()

调用一个在文件别处定义的函数, 第一个参数是运行该函数的this值

优点

可以在子类型中向父类型构造函数传递函数(不影响实例)

缺点

  1. 方法都在构造函数中定义, 函数不能复用
  2. 父类原型中定义的方法在子类型中不能使用

1.2.3 组合继承

组合使用原型链和借用构造函数 ==> 用借用构造函数实现对实例属性的继承; 用原型链实现对原型属性和方法的继承

function SuperType(name) {
	this.name = name;
}
SuperType.prototype.sayName = function() {
	alert(this.name);
}
function SubType(name, age) {
    //借用构造函数继承 实例属性
    //可以向父类型构造函数传递参数, 实例不共享该属性, 不影响实例。
	SuperType.call(this, name);  //第二次调用, 把之前的name覆盖掉了
    this.age = age;
}

//原型链继承 原型属性和方法(SubType.prototype.__proto__ === SuperType.prototype)
SubType.prototype = new SuperType();  //第一次调用, 有name属性
//既然改了原型对象就要让其constructor指回其构造函数
SubType.prototype.constructor = SubType;

SubType.prototype.sayAge = function () {
	alert(this.age);
}

var instance = new SubType("Lee", 18);

缺点

调用了两次父类构造函数, 导致新对象和原型对象有两组同名属性

1.2.4 原型式继承(非构造函数)

Object.create()

作用: 返回一个对象, 并让新对象的__proto__指向参数

funtion create(o) {
    function F(){};
    F.prototype = o;
    return new F();
}
var person = {
	name: "Nicholas",
	friends: ["Van", "Lee"];
}

var anthorPerson = Object.create(person);
anthorPerson.name = "Greg";

anthorPerson.proto == F.prototype == person

优点: 不用创建构造函数, 非构造函数继承

1.2.5 寄生组合式继承

//如果不支持Object.create()
if (typeof Object.create !== 'function') {
    Object.create = function() {
        function F() {};
        F.prototype = o;
        return new F();
    }
}

function SuperType(name) {
	this.name = name;
}
SuperType.prototype.sayName = function() {
	alert(this.name);
}
function SubType(name, age) {
	SuperType.call(this, name);   //只调用了一次SuperType构造函数
    this.age = age;
}

SubType.prototype = Object.create(SuperType.prototype);  //不必再调用SuperType, 只需要父类原型
SubType.prototype.constructor = SubType;

SubType.prototype.sayAge = function () {
	alert(this.age);
}

var instance = new SubType("Lee", 18);