资讯专栏INFORMATION COLUMN

JS-创建对象

william / 2076人阅读

摘要:创建对象使用或者对象字面量都可以创建对象,但是这样创建的对象过于简单,不易于对象的属性与方法的扩展与继承。下面讲的对象可以与中的做类比。通过调用构造函数创建的那个对象实例的原型对象。

创建对象

使用new Object()或者对象字面量都可以创建对象,但是这样创建的对象过于简单,不易于对象的属性与方法的扩展与继承。
下面讲的对象可以与JavaEE中的bean做类比。

工厂模式

对,首先可能想到的是使用设计模式中的工厂模式

function createPizza(type) {
  var o = new Object();
  o.type = type;
  o.bake = function() {
    alert("Start~");
    alert(this.type);
    alert("End~");
  };
  return o;
}

var cheesePizza = createPizza("cheese");
var veggiePizza = createPizza("veggie");
cheesePizza.bake();
优点

工厂模式解决了创建多个类似对象的问题

缺点

对象无法识别,即创建出来的对象无法通过instanceof等分析出属于哪种类型

构造函数模式

用构造函数可用来创建特定类型的对象

// 构造函数首字母遵循OO语言惯例进行大写
function Pizza(type) {
  this.type = type;
  this.bake = function() {
    alert("Start~");
    alert(this.type);
    alert("End~");
  };
}

var cheesePizza = new Pizza("cheese");
var veggiePizza = new Pizza("veggie");
cheesePizza.bake();

与工厂模式相比:

没有在方法中显示创造对象(o);

直接将属性与方法赋值给this;

没有return语句

在用new的时候,会经历一下4步:

创建一个新对象

将构造函数的作用域赋值给新对象(此时this指向新对象)

执行构造函数代码(为对象添加属性)

返回新对象

如果不使用new,将构造函数当做函数使用,则this指向Global对象(在浏览器中为window对象),当然,可以使用call方法来指定作用域,例如
var o = new Object();
Pizza.call(o, "salty");
o.bake();

使用构造函数方法,每个实例对象都有一个constructor构造函数属性,该属性指向Pizza(使用对象字面量、工厂模式方法创建的对象该属性指向Object)

cheesePizza.constructor == Pizza

检查某个对象属于哪种类型,一般使用instanceof,cheesePizza同时属于PizzaObject(之所以属于Object,是因为所有对象均继承于Object)

cheesePizza instanceof Pizza;
cheesePizza instanceof Object;
优点

与工厂模式相比,构造函数模式能够识别出对象类型
与下面的原型模式相比,能够实现对象属性的互相独立,在引用类型属性上很有用

缺点

每个实例对象的方法都是独立的,导致方法不能够共享

原型模式

每个函数(不是实例对象)都有一个prototype属性,该属性是一个指针,指向一个对象,对象的用途是包含所有实例共享的属性和方法。prototype通过调用构造函数创建的那个对象实例的原型对象。使用原型对象的好处是可以让所有实例对象共享属性与方法。

function Pizza() {

}

Pizza.prototype.type = "original"
Pizza.prototype.bake = function() {
  alert("Start~");
  alert(this.type);
  alert("End~");
};

var cheesePizza = new Pizza();
cheesePizza.type = "cheese";
var veggiePizza = new Pizza();
veggiePizza.type = "veggie";

cheesePizza.bake();
veggiePizza.bake();

各个对象共享属性与方法,同时每个对象都可以建立自己的属性,并屏蔽掉原型对象的同名属性,因为共享属性与方法,所以以下等式成立

cheesePizza.bake == veggiePizza.bake
对象字面量重写原型对象

也可以通过对象字面量来重写整个原型对象:

Pizza.prototype = {
  type: "original",
  bake: function() {
    alert("Start~");
    alert(this.type);
    alert("End~");
  }
}

这样完全重写,原型对象上的constructor属性不再指向Pizza函数(全新的constructor指向Object),不过不影响通过instanceof来识别对象类型。如果constructor特别重要的话,可以显式将它置为适当的值:

Pizza.prototype = {
  constructor: Pizza,
  type: "original",
  bake: function() {
    alert("Start~");
    alert(this.type);
    alert("End~");
  }
}

不过这种方式会将constructor的属性特征变为可枚举,而默认情况下它是不可枚举的,如果想不可枚举,可以使用Object.defineProperty()方法。

原型的动态性

对原型对象的修改会体现在实例对象上,即使实例对象先被创建。但是通过对象字面量重写的原型对象则没有该动态性

优点

定义在原型对象上的属性,能够保证在各实例对象上的共享

缺点

对于引用类型的属性,各实例的共享会导致额外的问题。

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

整合构造函数模式与原型模式,构造函数模式用于定义实例属性,原型模式用于定义方法和共享属性。

动态原型模式 寄生构造函数模式 稳妥构造函数模式 各创建模式在Chrome浏览器中的表现

可以通过Chrome浏览器观察使用工厂模式创建的cheesePizza对象属性为:

cheesePizza
{type: "cheese", bake: ƒ}
  bake: ƒ ()
  type: "cheese"
  __proto__:
    constructor: ƒ Object()
    hasOwnProperty: ƒ hasOwnProperty()
    isPrototypeOf: ƒ isPrototypeOf()
    propertyIsEnumerable: ƒ propertyIsEnumerable()
    toLocaleString: ƒ toLocaleString()
    toString: ƒ toString()
    valueOf: ƒ valueOf()
    __defineGetter__: ƒ __defineGetter__()
    __defineSetter__: ƒ __defineSetter__()
    __lookupGetter__: ƒ __lookupGetter__()
    __lookupSetter__: ƒ __lookupSetter__()
    get __proto__: ƒ __proto__()
    set __proto__: ƒ __proto__()

使用构造函数模式创建cheesePizza对象属性为:

cheesePizza
Pizza {type: "cheese", bake: ƒ}
  bake: ƒ ()
  type: "cheese"
  __proto__:
    constructor: ƒ Pizza(type)
    __proto__:
      constructor: ƒ Object()
      hasOwnProperty: ƒ hasOwnProperty()
      isPrototypeOf: ƒ isPrototypeOf()
      propertyIsEnumerable: ƒ propertyIsEnumerable()
      toLocaleString: ƒ toLocaleString()
      toString: ƒ toString()
      valueOf: ƒ valueOf()
      __defineGetter__: ƒ __defineGetter__()
      __defineSetter__: ƒ __defineSetter__()
      __lookupGetter__: ƒ __lookupGetter__()
      __lookupSetter__: ƒ __lookupSetter__()
      get __proto__: ƒ __proto__()
      set __proto__: ƒ __proto__()

使用原型模式创建cheesePizza对象属性为:

cheesePizza
Pizza {type: "cheese"}
  type: "cheese"
  __proto__:
    bake: ƒ ()
    type: "original"
    constructor: ƒ Pizza()
    __proto__:
      constructor: ƒ Object()
      hasOwnProperty: ƒ hasOwnProperty()
      isPrototypeOf: ƒ isPrototypeOf()
      propertyIsEnumerable: ƒ propertyIsEnumerable()
      toLocaleString: ƒ toLocaleString()
      toString: ƒ toString()
      valueOf: ƒ valueOf()
      __defineGetter__: ƒ __defineGetter__()
      __defineSetter__: ƒ __defineSetter__()
      __lookupGetter__: ƒ __lookupGetter__()
      __lookupSetter__: ƒ __lookupSetter__()
      get __proto__: ƒ __proto__()
      set __proto__: ƒ __proto__()
参考文章

ESLint 需要约束 for-in (guard-for-in)

个人不定期更新主页

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100145.html

相关文章

  • [译]执行上下文、作用域链和JS内部机制

    摘要:执行上下文作用域链和内部机制一执行上下文执行上下文是代码的执行环境,它包括的值变量对象和函数。创建作用域链一旦可变对象创建完,引擎就开始初始化作用域链。 执行上下文、作用域链和JS内部机制(Execution context, Scope chain and JavaScript internals) 一、执行上下文 执行上下文(Execution context EC)是js代码的执...

    caozhijian 评论0 收藏0
  • javascript对象详解:__proto__和prototype的区别和联系

    摘要:当这步完成,这个对象就与构造函数再无联系,这个时候即使构造函数再加任何成员,都不再影响已经实例化的对象了。此时,对象具有了和属性,同时具有了构造函数的原型对象的所有成员,当然,此时该原型对象是没有成员的。 前言 本篇文章用来记录下最近研究对象的一些心得,做一个记录与总结,以加深自己的印象,同时,希望也能给正在学习中的你一点启发。本文适合有一定JavaScript基础的童鞋阅读。原文戳这...

    chavesgu 评论0 收藏0
  • 后端知识点总结——NODE.JS基础

    摘要:后端知识点总结基础不是是一种软件开发平台,它的竞争对象历史第一次有一种语言可以通吃前后端网站阿里云镜像版本年初年中年底最新版本功能强大可靠,适合大型企业级项目简单易用适合互联网项目易用适合平台性能好适合服务器端密集型项目不适合密集型项目密集 后端知识点总结——NODE.JS基础 1.Node.js Node.js不是JS,是一种软件开发平台,它的竞争对象JSP/PHP/ASP.NET...

    Freeman 评论0 收藏0
  • JS 原型模式

    摘要:你可以使用像下面这样的代码为上面的例子来实现车辆模具是福特总结原型模式在里的使用简直是无处不在,其它很多模式有很多也是基于的,这里大家要注意的依然是浅拷贝和深拷贝的问题,免得出现引用问题。 1. 简介 原型模式(Prototype pattern),用原型实例指向创建对象的类,使用于创建新的对象的类的共享原型的属性与方法。 2. 实现 对于原型模式,我们可以利用JavaScript特有...

    Coding01 评论0 收藏0
  • JS-对象

    摘要:一概述是一种面向对象的语言。除了基本数据类型,其他的都是对象。表示创建一个没有原型的空对象。模拟操作符注意返回值访问对象属性访问方式也就是。对象在作为值时,是作为引用传递的。假如判断对象是否为数组目前的很多库,中都是这样实现的。 一、概述 JS是一种面向对象的语言。除了基本数据类型number, string, boolean(true, false), null, undefined...

    kidsamong 评论0 收藏0
  • 关于javascript的原型和原型链,看我就够了(一)

    摘要:要用作原型的对象。函数对象可以创建普通对象,这个我们上面讲过了回顾一下这是一个自定义构造函数普通对象没法创建函数对象,凡是通过创建的对象都是函数对象,其他都是普通对象通常通过创建,可以通过来判断。 关于js的原型和原型链,有人觉得这是很头疼的一块知识点,其实不然,它很基础,不信,往下看要了解原型和原型链,我们得先从对象说起 创建对象 创建对象的三种方式: 对象直接量 通过对象直接量创建...

    MoAir 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<