js查缺补漏——详解原型、原型对象、原型链和设计模式

面向对象的理解

都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。

所以对象其实就是无序属性的集合,属性可以包含基本值、对象和函数。

创建自定义对象的方法:

  1. 使用new Object的方法
  2. 使用对象字面量的方法
var obj = new Object()
obj.name = 'aa';
obj.sayName = function(){
}

var obj = {
 name: 'aa';
 sayName: function(){
   alert('1111')
 }
}

ECMAScript所具备的两种属性:数据属性和访问器属性。
1.数据属性:包含一个数据值的位置,在这个位置可以读取和写入值。

  1. [[Confugurable]] 表示能否通过delete删除属性从而重新定义属性,默认值为true.
  2. [[Enumerable]] 表示能否通过循环for-in返回属性,默认true.
  3. [[Writable]] 表示能否修改属性的值。默认true
  4. [[Value]] 包含这个属性的属性值,读取和写入,默认是undefined.

2.访问器属性:不包含数据值,包含一对getter、setter函数。读取访问器的属性调用getter函数并返回值,写入访问器属性会调用setter函数并传入新值,决定如何处理函数。也是具备四个属性。

  1. [[Confugurable]] 表示能否通过delete删除属性从而重新定义属性,默认值为true.
  2. [[Enumerable]] 表示能否通过循环for-in返回属性,默认true.
  3. [[Get]] 读取属性时调用的函数,默认undefined
  4. [[Set]] 写入属性时调用的函数,默认undefined

修改属性的特性

要修改默认属性的特性,需要Object.defineProperty(),接收三个参数,属性所在的对象,属性的名字和一个描述符对象。如果需要定义多个属性,需要使用Object.defineProperties(), 属性可以随之增加。

注意:使用Object.defineProperty()创建一个新属性时,如果不指定,除了value以外的值都是false.修改属性无限制。

读取属性的特性

Object.getOwnPropertyDescriptor() 可以取得给定属性的描述符。接收两个参数,属性所在的对象和要读取其描述符的属性名称,会返回一个对象。根据属性不同,返回不同的值。

所以使用Object创建很多对象会存在一个问题,会产生大量的重复代码,使用工厂模式可以很好的解决这个问题。

几种设计模式

一、工厂模式:用函数来封装以特定接口创建对象的细节,抽象了创建具体对象的过程。

function createObj(name,age) {
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.sayName = function() {
     alert(this.name)
  }
  return obj;
}

var person = createObj('bob', 10)

优缺点:解决了创建多个相似对象的问题,但没解决对象识别的问题,无法知道一个对象的类型。

二、构造函数模式:可以用来创建特定类型的对象,像Object、Array这样的原生构造函数,运行时会自动出现在执行环境中。还可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。

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

var obj = new Person('aaa', 23)

构造函数名的首字母是需要大写的,创建实例需要使用new。构造函数除了本身是函数还可以用来创建对象。

和工厂函数的区别:
1、没有return语句
2、没有显式的创建对象
3、直接将属性和方法赋给this对象

调用构造函数创建对象的步骤:

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(通过this指向新对象)
  • 执行构造函数中的代码(为新对象添加属性和方法)
  • 返回新对象

这些实例obj不仅是Object对象的实例,还是Person的实例。对象的constructor属性的用来标识对象类型的,instanceof可以作为检测对象类型。创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型。

但构造函数也有问题,每个方法都要在每个实例上重新创建一遍。每个同样的创造函数生成的实例会有不同的Function实例,所以以这种方式创建函数会导致不同的作用域链和标识符解析,不同实例的同名函数不相同。

解决方法:将函数定义拿到构造函数外面去,这样多个对象共享同一个函数。但全局定义的函数其实只能被某个对象所调用,同时如果某个对象需要多个方法就需要定义很多全局函数,就会又出现问题。此时为了解决这个,需要采用原型模式。

三、原型模式:

原型:[[prototype]]或者_proto_,创建的每一个函数都有一个原型属性,是一个指针,指向一个对象。用途是包含可以由特定类型的所有实例共享的属性和方法。也就是prototype是通过调用构造函数而创建的那个对象实例的原型对象,好处可以让所有实例对象共享所包含的属性和方法。可以通过直接将这些信息添加到原型对象里。

原型对象:就是上述所说的原型属性指向的那个对象就是原型对象。

涉及原型及原型对象的几个方法:

1.isProtoTypeOf(obj) 用来判断原型是否指向调用当前方法的实例对象,如果有指向则返回true.
alert(Person.prototype.isProtoTypeOf(obj))
2.Object.getProtoTypeOf() 返回[[Prototype]]对象原型的值。【所以原型的作用可以实现继承】
3.hasOwnProperty() 可以检测一个属性是存在于实例中还是原型中,如果存在于实例中返回true,否则返回flase.
4.Object.getOwnPropertyDescriptor() 用于实例属性,获取原型属性的描述符。

所以当代码读取某个对象的某个属性时,会执行一次搜索,目标是具有给定名字的属性,搜索首先是从实例对象去查找,如果找到了则返回该属性的值。如果没有则继续搜索指针指向的原型对象,在原型对象查找给定名字的属性。找到了返回该属性值。

注意:通过对象实例访问保存在原型中的值,但不能通过对象实例重新原型中的值,如果添加了一个属性和实例原型相同,会仅仅覆盖掉实例对象的属性值,不会修改原型中的属性值。因为在实例中找到了这个属性,就直接返回不再继续查找原型中的。如果要修改只有通过delete才能删除掉原型的属性。如
delete Person.name

如何遍历和判断原型的属性

  1. in操作符,是判断属性是否存在于原型或实例上,存在则返回true.
  2. for in 返回的是能够通过对象访问的、可枚举属性,会屏蔽掉不可枚举的属性和方法:constructor、[[Enumerable]]、hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()和valueOf(),包括实例对象和原型的属性。
  3. Object.keys() 可以取得对象所有可枚举的属性,接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。
  4. Object.getOwnPropertyNames() 可以得到实例的所有属性,不管是否可枚举。包括constructor属性。

实例中的指针仅指向原型,不指向构造函数。
由于原型对象会共用属性,所以原型模式一般和构造模式组合使用。使用构造函数定义实例属性,使用原型模式定义方法和共享的属性。,可以很大幅度的节省内存。
此外设计模式还有很多,动态原型模式(把所有信息封装在构造函数里,通过初始化原型,检测某个方法是否有效去决定是否初始化)、寄生构造函数模式(封装创建对象的代码,返回新创建的对象)、稳妥构造函数模式(对没公共属性,方法也不被引用的稳妥对象去操作)。

四、实现继承:主要通过原型链的方法实现。利用原型让一个引用类型继承另一个引用类型的属性和方法。实质就是通过重写原型对象来进行。

当以读取模式访问第一个实例属性时,首先会在实例中搜索该属性,如果没找到该属性,则会继续搜索实例的原型。在通过原型链实现继承的情况下,继续沿着原型链继续向上查找。直到搜索到原型链末端停止。Object是原型链的最末端,最后查找的位置,有很多属性和方法都是从Object继承下来的,constructor、hasOwnProperty、isPrototypeOf、propertyIsEnumerable、toString、toLocaleString、valueOf。

所有函数的默认原型都是Object的实例,内部包含一个指针,指向Object.prototype.

五、确定原型和实例的关系

  1. instanceof 用来测试实例与原型链中出现过的构造函数,就返回true.
  2. isPrototypeOf() 只要是原型链出现过的原型,都可以说是该原型链所派生的实例的原型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值