《JS高程(3)》-第6章笔记(02)

第六章 面向对象的编程

6.2 创建对象

起因:使用Object和字面量使用同一个接口创建很多个对象,会产生大量的代码重复。

  1. 基础模式

    • 工厂模式

    • 构造函数模式

    • 原型模式

  2. 升级模式(见笔记03)

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

    • 动态原型模式

    • 寄生构造函数模式

    • 稳妥构造函数模式


1.1 工厂模式
因ECMAScript无法创建类,遂发明了一种用函数来封装 以特定接口创建对象的函数。

function createPerson (name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age; 
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    } 
    return o;
}

var person1 = createPerson("Nicholas", 29, "Software Engineer");

var person2 =  createPerson("Greg", 27, "Doctor");

优点:可多次调用;
缺点:对象类型无法识别;
类型:Object。

1.2 构造函数模式

因原生构造函数,在运行时会自动出现在执行环境中,由此创建自定义的构造函数,从而定义自定义对像类型的属性和方法。

function Person(name, age, job){
    this.name = name ;
    this.age = age; 
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };
}

var person1 =new Person("Nicholas", 29, "Software Engineer");

var person2 =new Person("Greg", 27, "Doctor");

优点:对象类型可识别;

缺点:构造函数中的方法在实例化时重复创建;

类型:Object/Person 实例(可标志为特定类型)。

创建构造函数实例的步骤:

(1):创建一个新对象;
(2):将构造函数的作用域赋给新对象;
(3):执行构造函数中的代码;
(4):返回新对象。

检测对象类型

(1) : constructor;

    person1.constructor

(2): instanceof 。

    person1 instanceof  Object;
    person1 instanceof  Person;

1.2 原型模式

通过在prototype中定义对象实例的信息,从而让所有对象共享它所包含的方法和属性。

Created with Raphaël 2.1.0 prototype 与 person1 简图 prototype prototype constructor constructor Person Person person1 person1
function Person(){
}

Person.prototype.name = "Grey";
Person.prototype.age = "29";
Person.prototype.job = "Doctor";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
person1.sayName();//"Grey"

var person2 = new Person();
person2.sayName();//"Grey"
console.log(person1.sayName == person2.sayName);//true

原型模式工作原理

  • 理解原型对象

    1. 函数在创建时自动生成一个prototype属性,该属性指向函数的原型对象。

      Person.prototype

    2. 原型对象中存在一个constructor属性,该属性包含一个指向 prototype所在函数 的指针。

      Person.prototype.constructor == Person

    3. 构造函数创建实例后,该实例内部包含一个指针([[Prototype]]),指向构造函数的原型对象。

      Object.getPrototypeOf(person1) == Person.prototype;
      Person.prototype.isPrototypeOf(person1);

      实例函数的原型均指向Person.prototype,与构造函数本身没有直接关系

    4. 属性读取顺序:

      对象实例本身 – >原型对象;

      hasOwnProperty()方法,用于检测属性存在于原型还是实例中,存在于实例中返回true;

      Object.getOwnPropertyDescriptor()方法,只用于获取实例属性。


- 原型与in 操作符

in判断运算符prop in objectName (符合则true,范围为整个原型链勿用in判断String,Array,Number等用字面量创建的实例
for-in循环语句for (variable in object)(遍历自定义属性包括原型链上的)String,Array,Number中少用
Object.key()方法Object.keys(obj)(返回一个所有元素为字符串的数组)ES6:非对象的参数将被强制转换为一个对象
Object.getOwnPropertyNames()方法Object.getOwnPropertyNames(obj)(返回一个数组含有指定对象可枚举/不可枚举属性的名称)ES6:非对象的参数将被强制转换为一个对象

  • 更简单的原型语法

起因:Person.prototype的重复输入

方法:用一个包含所有属性和方法的对象字面量来重写整个原型对象。

function Person (){
}

Person.prototype = {
    name : "Grey",
    age : 29,
    job : "Doctor",
    sayName : function (){
        alert(this.name);
    }
};

var friend = new Person();

alert (friend instanceof Object); //true

alert (friend instanceof Person); //true

alert (friend .constructor == Object); //true

alert (friend .constructor == Person); //false

Person.prototype等于以对象字面量的形式创建了一个新对象;

该对象的constructor属性的指向为Object.可在Person.prototype中重写constructor:Person,

constructor的[[Enumerable]]变为true。


  • 原型的动态性

    1. 对原型对象所做的任何修改都会反映到实例上;

    2. 实例与原型间的连接是一个指针的松散连接;

    3. 实例中的指针仅指向原型,而非构造函数。

    4. 重写原型对象后,已存在的对象实例仍指向最初的原型,与现有原型没有任何关系。


  • 原生对象的原型

原生的引用类型,可以通过原型模式获取和定义新的方法。

String.prototype.startsWith = function(text){
    return this.indexOf(text) == 0;
}

var mst = "Hello World";

alert (mst.startsWith('Hello')); //true
//最好不修改原生对象的原型

  • 原型对象的问题

    1. 所有实例在默认情况下取得的属性值都相同;

    2. 对于引用类型,获取的是地址,当一个实例修改引用类型属性时,其他实例所获取的属性值也会随之发生变化。


(发现写错的地方,请留言,看到会立即修改,谢谢大牛们)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值