创建对象、原型、原型链

栏目: 后端 · 发布时间: 5年前

内容简介:工厂模式虽然解决了创建多个相似对象的问题,但是却没有解决对象识别的问题,即怎样知道一个对象的类型。构造函数和工厂函数不同之处在于:** 调用构造函数会经历下面4个步骤(即new干了什么)**:
var person = function(name,age){
  var o = new Object();
  o.name = name;
  o.age = age;
  o.sayName = function() {
    console.log(this.name)
  }
  return o;
} 

var person1 = person('li', 20);
var person2 = person('xiao', 18);

person1.sayName();  //li
person2.sayName();  //xiao
复制代码
  • 先创建一个object
  • object绑定属性和方法
  • 返回这个object

缺点

工厂模式虽然解决了创建多个相似对象的问题,但是却没有解决对象识别的问题,即怎样知道一个对象的类型。

构造函数

var Person = function(name,age) {
  this.name = name;
  this.age = age;
  this.sayName = function() {
    console.log(this.name)
  }
}

var person1 = new Person('li',20)
var person2 = new Person('xiao',18)

person1.sayName()  //li
person2.sayName()  //xiao
复制代码

构造函数和工厂函数不同之处在于:

  • 没有显示的创建对象
  • 直接将属性和方法赋给了this对象
  • 没有return语句
  • 函数名的首字母大写
  • 要创建构造函数的实例,必须使用new操作符

** 调用构造函数会经历下面4个步骤(即new干了什么)**:

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

上面的person1和person2分别保存Person的一个不同实例,这两个对象都有一个constructor(构造函数)属性,该属性执行Person

person1.constructor == person2.constructor == Person

可以用constructor来识别对象类型,但是用instanceof 更可靠

person1和person2同时也是object的实例,因为所有的对象都继承自Object

缺点

如果构造函数里面有方法,那方法都会在每个实例上都创建一遍,因此不同实例上的函数是不相等的

person1.sayName == person2.sayName // false

虽然可以把方法移到构造函数外部,设置成全局函数,但是如果对象需要定义很多方法,就要定义很多个全局函数,

原型模式

function Person(){};
Person.prototype.name = "li";
Person.prototype.age = 20;
Person.prototype.sayName = function(){
  console.log(this.name)
};
var person1 = new Person()
var person2 = new Person()

person1.sayName()  //li
person2.sayName()  //li

person2.name = 'xiao'  //person2这个实例加了一个name属性,重写name属性,但不会改变原型的值
person1.sayName()  //li
person2.sayName()  //xiao  //如果实例上有name属性,取的是实例上的
复制代码

好处

可以让所有对象实例共享它所包含的属性和方法。

person1.sayName !== person2.sayName //true

原型对象

只要创建了一个函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针(妈呀,很拗口,看代码和图比较直观)

创建了自定义的构造函数后,其原型对象默认只会取得constructor属性,至于其他方法,都是从object继承而来。当调用构造函数创建一个实例,该实例内部将包含一个指针,指向构造函数的原型对象,可以用_proto_属性访问。这个链接存在与实例与构造函数的原型对象之间,而不存在于实例与构造函数之间。

Person.prototype.constructor = Person

person1._proto_ == Person.prototype

创建对象、原型、原型链

判断是不是对象的原型

  • isPrototypeOf

Person.prototype.isPrototypeOf(person1) // true

  • Object.getPrototypeOf可以取到一个实例的原型

Object.getPrototypeOf(person1) == Person.prototype // true Object.getPrototypeOf(person1).name //li

判断一个属性是存在实例中还是原型中

  • hasOwnProperty()只在给定属性存在实例中时,才返回true
person1.hasOwnProperty('name') // false
person2.hasOwnProperty('name') //true
复制代码
  • in 不管属性是存在实例上还是原型中,都返回true

'name' in Person // true

hasOwnProperty和in一起可以判断属性是不是在原型中

!object.hasOwnProperty(name) && ('name' in object)

对象字面量

我们将Person.prototype 设置为等于一个以对象字面量形式创建的新对象,最终结果相同,但是constructor属性不再指向Person。这里的语法,本质上完成重写了默认的portotype对象,因此它的原型是Object,constructor是指向Object的构造函数。但是用instanceof 操作符还能返回正确结果

function Person(){};
Person.prototype = {
  name: 'li',
  age: 20,
  sayName: function(){
    console.log(this.name)
  }
};
var person1 = new Person()
console.log(Person.prototype.constructor == Person)  //false
console.log(Person.prototype.constructor == Object)  //true
console.log(person1 instanceof Person) // true
复制代码

原型的动态性

function Person(){};
var person1 = new Person()
Person.prototype = {
  name: 'li',
  age: 20,
  sayName: function(){
    console.log(this.name)
  }
};

person1.sayName()  //person1.sayName is not a function
复制代码

先创建实例,在重写其原型对象,会切断现有原型与之前任何已经存在的对象实例之间的联系。person1引用的还是原来的原型。可以用下面这种写法

function Person(){};

var person1 = new Person()

Person.prototype.sayName = function(name){
    console.log(name)
  }


person1.sayName('li')  //li
复制代码

原型对象的缺点

  • 省略了为构造函数传递初始化参数,所有实例在默认情况下都取得相同的属性值。
  • 如果有引用类型的属性,会导致在一个实例里修改引用类型的值,会把原型上的也修改了

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

  • 构造函数模式用于定义实例属性
  • 原型模式用于定义方法和共享的属性
var Person = function(name,age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayName = function(){
  console.log(this.name)
};
var person1 = new Person('li',20)
var person2 = new Person('xiao',18)

person1.sayName()  //li
person2.sayName()  //xiao
复制代码
  • 动态原型模式
function Person(name, age){
  this.name = name;
  this.age = age
  if(typeof this.sayName != function) {
    Person.prototype.sayName = function(name){
      console.log(this.name)
    }
  }
};
复制代码

判断这个代码只会在初次调用构造函数时执行

  • 寄生构造函数模式
  • 委托构造函数模式 不引用this

继承

js只支持实现继承 主要是依靠 原型链 来实现的.

利用原型让一个引用类型继承另一个引用类型的属性和方法

方法:

  • 原型链
  • 借用构造函数
  • 组合继承
  • 原型式继承
  • 寄生式继承
  • 寄生组合式继承

原型链

每一个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原型对象的指针。那么,如果我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应的,另一个原型中也包含着一个指向另一个构造函数的指针,假如另一个原型又是另一个类型的实例。。。如此层层递进,就构成了实例和原型的链条

如果引用对象(实例instance)的某个属性,会现在这个对象内找,如果找不到,就会到这个对象的原型上去找,原型上找不到,就到原型的原型上去找,直到找到这个属性或者返回null为止


以上所述就是小编给大家介绍的《创建对象、原型、原型链》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

MySQL性能调优与架构设计

MySQL性能调优与架构设计

简朝阳 / 2009-6 / 59.80元

《MySQL性能调优与架构设计》以 MySQL 数据库的基础及维护为切入点,重点介绍了 MySQL 数据库应用系统的性能调优,以及高可用可扩展的架构设计。 全书共分3篇,基础篇介绍了MySQL软件的基础知识、架构组成、存储引擎、安全管理及基本的备份恢复知识。性能优化篇从影响 MySQL 数据库应用系统性能的因素开始,针对性地对各个影响因素进行调优分析。如 MySQL Schema 设计的技巧......一起来看看 《MySQL性能调优与架构设计》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具