<笔记>面向对象的设想形式

建立对象

什么是工场形式 ?

封装一个函数 , 用来建立对象并给对象中特定的属性添加值 , 长处是可以轮回挪用 , 瑕玷是每一个建立出来的对象都是自力的 , 不能肯定它是哪一个范例的对象 ( 或许说是想要将哪一个对象作为模板举行建立 )

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 范例的实例 

组织函数形式的瑕玷

然则 , 上面的组织函数形式也不是没有瑕玷的 : 纯真的组织函数形式建立对象的时刻 , 对象中每一个要领都邑在实例对象上从新建立一次 , 也就是说每次都邑建立一个看起来雷同然则完整不是一个”要领”的要领

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 实例的要领

什么是原型形式

  • 每一个函数在建立的时刻都邑有一个 prototype 属性 , 这个属性指向一个对象
  • 一切以这个函数为组织函数建立的实例对象 , 都邑衔接到组织函数的 prototype 属性指向的这个对象上 , 而且可以接见这个对象的一切属性和要领 , 这个对象就叫做原型对象
  • 原型对象在建立的时刻自带一个不可罗列的 constructor 属性 , 指向组织函数
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 要领都是原型对象上的要领 , 不是它们本身的 , 如许就处理了组织函数形式屡次建立要领实例的瑕玷

原型对象中的属性和要领会和实例对象自有的争执吗

假如当前实例对象中已经有了想要查找的属性和要领 , 会直接运用实例对象的属性和要领 , 假如没有才去原型对象中查找

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

实例对象怎样接见原型对象

  • 在火狐、谷歌等浏览器中供应了一个 __proto__ 的属性 , 可以接见它的原型对象
  • ECMAScript 5 中供应了 Object.getPrototypeOf( ) 要领可以检测并返回它的原型对象
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

原型对象和原型属性有什么区分

  • 实例对象 ( person1 ) 的原型对象 ( __proto__ ) 是建立当前对象的组织函数 ( Person ) 的原型属性 ( prototype ) , 个人用来区分接见门路 , 便于明白
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( ) 要领可以检车要查找的属性或要领是不是来自实例对象而不是实例对象的原型对象

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 属性来自实例对象

罗列对象中的属性和要领有哪些要领

  • for – in 遍历 , 会将当前对象和当前对象的原型对象上一切可以罗列的属性和要领都返回
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
}
  • ECMAScript 5 的 Object.key( ) 要领 , 遍历当前对象的可罗列属性和要领 , 不会去找原型对象
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
  • Object.getOwnPropertyNames( ) 要领 , 遍历当前对象的一切属性和要领 , 包含不可罗列的 , 不会去找原型对象
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

原型形式建立对象的瑕玷

原型中的一切属性和要领都是同享的 , 假如有多个实例 , 经由过程个中一个实例转变原型对象中的属性和要领 , 其他实例接见的属性会随着转变

组合运用组织函数形式和原型形式

将对象的私有属性和要领经由过程组织函数形式建立 , 将对象的大众属性和要领经由过程原型形式建立

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
// 到头了

原型链继续

原型链继续的道理就是实例对象可以接见原型对象的属性和要领 , 并经由过程原型链向上查找

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
    原文作者:Oswald
    原文地址: https://segmentfault.com/a/1190000016039854
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞