封装一个函数 , 用来建立对象并给对象中特定的属性添加值 , 优势是能够循环调用 , 缺点是每个建立出来的对象都是独立的 , 不能肯定它是哪一个类型的对象 ( 或者说是想要将哪一个对象做为模板进行建立 )浏览器
function func(name, age) { var o = { "name" : name, "age" : age }; return o; } var person = func("oswald", 24); var person2 = func("oswald", 24); // {name: "oswald", age: 24} console.log(person === person2); // false console.log(person.__proto__ === Object.prototype); // true console.log(person2.__proto__ === Object.prototype); // true // 每一个对象都是独立的而且指向 Object.prototype 的 , 不能辨别基于哪一个对象为原型
构造函数模式就是经过构造函数来建立自定义类型的对象 , 建立出来的对象都指向了同一个构造函数的 prototype , 解决了工厂模式中不能识别对象模板的问题函数
function Person(name, age) { this.name = name; this.age = age; this.sayName = function(){ console.log(this.name); }; /* 没有显式的建立对象 用 this 代替新对象 没有 return 语句 */ } var person1 = new Person("oswald", 24); console.log(person1); // {name: "oswald", age: 24} console.log(person1.__proto__ === Person.prototype); // true // person1 指向了 构造函数 func.prototype console.log(person1 instanceof Person); // true // person1 对象是构造函数 Person ( 也能够叫作 Person 类型 ) 的实例 console.log(person1 instanceof Object); // true // person1 对象也是 Object 类型的实例
可是 , 上面的构造函数模式也不是没有缺点的 : 单纯的构造函数模式建立对象的时候 , 对象中每一个方法都会在实例对象上从新建立一次 , 也就是说每次都会建立一个看起来相同可是彻底不是一个"方法"的方法oop
function Person(name, age) { this.name = name; this.age = age; this.sayName = function(){ console.log(this.name); }; } var person1 = new Person("oswald", 24); var person2 = new Person("oswald", 24); console.log(person1.sayName = person2.sayName); // false // 每次建立对象的时候 , 都会生成一个功能同样可是是不一样 Function 实例的方法
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; Person.prototype.sayName = function(){ console.log(this.name); }; } var person1 = new Person(); console.log(person1); // {} 获得一个空对象 , 由于建立的属性和方法都在实例的原型对象上 console.log(Person.prototype); // {name: "oswald", age: 24, sayName: f(...)} console.log(person1.name); // oswald 获得一个名字 , 由于实例对象能够从它的原型对象上查找属性和方法 var person2 = new Person(); console.log(person2.sayName === person1.sayName); // true // person1 和 person2 访问的 sayName 方法都是原型对象上的方法 , 不是它们自身的 , 这样就解决了构造函数模式屡次建立方法实例的缺点
若是当前实例对象中已经有了想要查找的属性和方法 , 会直接使用实例对象的属性和方法 , 若是没有才去原型对象中查找this
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; } var person1 = new Person(); console.log(person1.name); // oswald person1.name = "yin"; console.log(person1.name); // yin
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; } var person1 = new Person(); console.log(person1.__proto__ === Person.prototype); // true console.log(Object.getPrototypeOf(person1) === Person.prototype); // true
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; } var person1 = new Person(); console.log(person1.__proto__ === Person.prototype); // true
function Person(){ } var person1 = new Person(); person1.prototype = { name: "yin", age: 23 } console.log(person1.name); // undefined
使用继承自 Object 对象的 hasOwnProperty( ) 方法能够检车要查找的属性或方法是否来自实例对象而不是实例对象的原型对象prototype
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; } var person1 = new Person(); console.log(person1.name); // oswald console.log(person1.hasOwnProperty("name")); // false 当前查找到的 name 属性来自原型对象 person1.name = "yin"; console.log(person1.name); // yin console.log(person1.hasOwnProperty("name")); // true 当前查找到的 name 属性来自实例对象
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; } var person1 = new Person(); person1.color = "red"; for( poop in person1 ){ console.log(poop); // color, name, age }
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; } var person1 = new Person(); person1.color = "red"; var p1keys = Object.key(person1); console.log(p1keys); // color
function Person(){ Person.prototype.name = "oswald"; Person.prototype.age = 24; } var person1 = new Person(); person1.color = "red"; var p1keys = Object.getOwnPropertyNames(person1); console.log(p1keys); // color var Ppkeys = Object.getOwnPropertyNames(Person.prototype); console.log(Ppkeys); // constructor、name、age
原型中的全部属性和方法都是共享的 , 若是有多个实例 , 经过其中一个实例改变原型对象中的属性和方法 , 其余实例访问的属性会跟着改变code
将对象的私有属性和方法经过构造函数模式建立 , 将对象的公共属性和方法经过原型模式建立对象
function Person(name,age){ /* 私有属性 */ this.name = name; this.age = age; } Person.prototype.sayName = function(){ /* 公共方法 */ console.log(this.name); } var person1 = new Person("oswald", 24); person1.sayName(); // oswald
原型链就是链接实例对象和原型对象的连接继承
/* 通常函数的原型链 */ function func(){ console.log(123); } console.log(func.__proto__); // Function.prototype // func 函数是 Function 构造函数的实例对象 console.log(func.__proto__.__proto__); // Object.prototype // func 函数的原型对象是 Object 构造函数的实例对象 console.log(func.__proto__.__proto__.proto__); // null // 这里就是原型链的头了 , 全部原型链查到 Object.prototype 再往上就会返回 null /* 通常构造函数的原型链 */ function Obj(){ Func.prototype.name = "oswald"; } var obj = new Obj(); console.log(obj); // {} console.log(obj.name); // oswald // obj 对象经过原型链查找到了 name 属性 console.log(Obj.__proto__); // Obj.prototype // obj 对象是 Obj 构造函数的实例对象 console.log(Obj.__proto__.__proto__); // Object.prototype // obj 对象的原型对象是 Object 构造函数的实例 console.log(Obj.__proto__.__proto__.__proto__); // null // 到头了
原型链继承的原理就是实例对象能够访问原型对象的属性和方法 , 并经过原型链向上查找ip
function Oswald(){ this.color = "red"; Oswald.prototype.sayName = function(){ console.log(this.name) }; } var oswald = new Oswald(); function Yin(name, age){ this.name = name; this.age = age; Yin.prototype.sayAge = function(){ console.log(this.age); } } Yin.prototype = oswald; /* 原型链继承的核心 , 把父类型 ( Oswald ) 的实例对象 ( oswald ) 设置为子类型 ( Yin ) 的原型属性 ( Yin.prototype ) */ var yin = new Yin("oswald", 24); // 必需要先继承再建立实例 , 不然会出现 Yin.prototype != yin.__proto__ 的状况 yin.sayName(); // oswald 继承了 Oswald 类型原型上的方法 yin.sayAge(); // 24 继承了 Yin 类型原型上的方法
function Oswald(color){ this.color = color; this.sayName = function(){ console.log(this.name) }; } function Yin(name, age, color){ Oswald.call(this, color); // 在 Yin 构造函数建立的新对象中调用 Oswald 函数 this.name = name; this.age = age; } var yin = new Yin("yin", 24, "red"); yin.sayName(); // yin
可是借用构造函数继承只可以继承父类型本身的属性和方法 , 不能继承原型链上 , 这个时候咱们能够使用原型链和借用构造函数的组合式继承 , 可是这个方法会调用两次父类型构造函数原型链
function Super(color){ this.color = color; // 本身的属性 Super.prototype.sayName = function(){ console.log(this.name) }; // 原型链上的方法 } function Sub(name, age, color){ Super.call(this, color); // 第二次调用 Super , 被当作普通函数调用 // 继承 Super 构造函数本身的属性和方法 this.name = name; this.age = age; } Sub.prototype = new Super(); // 第一次调用 Super , 被当作构造函数调用 // 继承 Super 原型链上的属性和方法 var yin = new Sub("yin", 24, "red"); yin.sayName(); // yin
ES 5 中使用 Object.create( o ) 方法规范了原型式继承 , 这个方法会返回一个新对象 , 新对象的原型对象指向传入的参数对象 o
function obj(o){ // Object.create( ) 方法的原理 function F(){}; F.prototype = o; return new F(); } var person = { name: "oswald", color: ["red"] } var person1 = obj(person); var person2 = Object.create(person); console.log(person1 === person2); // false console.log(person1.__proto__ === person2.__proto__); // true
目前最优的继承模式
function Super(color){ this.color = color; Super.prototype.sayName = function(){ console.log(this.name); } } function Sub(name, color){ Super.call(this, color); // 借调 Super 构造函数继承实例属性 this.name = name; } var F = Object.create(Super.prototype); F.constructor = Sub; Sub.prototype = F; var yin = new Sub("oswald","red"); yin.sayName(); // oswald