JavaScript Patterns 读书笔记(二)

本文深入探讨了JavaScript中构造函数的使用方式与潜在陷阱,包括Object构造函数的特点、返回值控制、自调用构造函数、Array构造函数的特殊行为及错误处理等。

二.Object

  • Object Constructor Catch
       You have no reason to use the new Object() constructor when you can use an object literal, but you might be inheriting legacy code written by others, so you should be aware of one “feature” of this constructor (or yet another reason not to use it). The feature in question is that the Object() constructor accepts a parameter and, depending on the value passed, it may decide to delegate the object creation to another built-in constructor and return a different object than you expect. Following are a few examples of passing a number, a string, and a boolean value to new Object(); the result is that you get objects created with a different constructor:
    // Warning: antipatterns ahead
    // an empty object
    var o = new Object();
    console.log(o.constructor === Object); // true
    // a number object
    var o = new Object(1);
    console.log(o.constructor === Number); // true
    console.log(o.toFixed(2)); // "1.00"
    // a string object
    var o = new Object("I am a string");
    console.log(o.constructor === String); // true
    // normal objects don't have a substring()
    // method but string objects do
    console.log(typeof o.substring); // "function"
    // a boolean object
    var o = new Object(true);
    console.log(o.constructor === Boolean); // true
    
     
  • Constructor’s Return Values
      When invoked with new, a constructor function always returns an object; by default it’s the object referred to by this. If you don’t add any properties to this inside of your constructor, an “empty” object is returned (“empty” aside from inheriting from the constructor’s prototype).
     Constructors implicitly return this, even when you don’t have a return statement in the function. But you can return any other object of your choosing. In the next example, a new object referenced by that is created and returned.
    var Objectmaker = function () {
    	// this `name` property will be ignored
    	// because the constructor
    	// decides to return another object instead
    	this.name = "This is it";
    	// creating and returning a new object
    	var that = {};
    	that.name = "And that's that";
    	return that;
    };
    // test
    var o = new Objectmaker();
    console.log(o.name); // "And that's that"
    
        As can you see, you have the freedom to return any object in your constructors, as long as it’s an object. Attempting to return something that’s not an object (like a string or a boolean false, for example) will not cause an error but will simply be ignored, and the object referenced by this will be returned instead(!).
  • Self-Invoking Constructor
      To address the drawback of forgeting "new" when construct a new instance and have prototype properties available to the instance objects, consider the following approach. In the constructor you check whether this is an instance of your constructor, and if not, the constructor invokes itself again,this time properly with new:
    function Waffle() {
    	if (!(this instanceof Waffle)) {
    		return new Waffle();
    	}
    	this.tastes = "yummy";
    }
    
    Waffle.prototype.wantAnother = true;
    // testing invocations
    var first = new Waffle(),
    second = Waffle();
    console.log(first.tastes); // "yummy"
    console.log(second.tastes); // "yummy"
    console.log(first.wantAnother); // true
    console.log(second.wantAnother); // true
    
     
  • Array Constructor Curiousness
         One more reason to stay away from new Array() is to avoid a possible trap that this constructor has in store for you.
         When you pass a single number to the Array() constructor, it doesn’t become the value of the first array element. It sets the length of the array instead. This means that new Array(3) creates an array with length of 3, but no actual elements. If you try to access any of the elements, you get the value undefined because the elements don’t exist. The following code example shows the different behavior when you use the literal and the constructor with a single value.
    // an array of one element
    var a = [3];
    console.log(a.length); // 1
    console.log(a[0]); // 3
    // an array of three elements
    var a = new Array(3);
    console.log(a.length); // 3
    console.log(typeof a[0]); // "undefined"
    
     
       Although this behavior might be a little unexpected, it gets worse when you pass a floating point number to new Array() as opposed to an integer. This results in an error because the floating point is not a valid value for the array’s length:
    // using array literal
    var a = [3.14];
    console.log(a[0]); // 3.14
    var a = new Array(3.14); // RangeError: invalid array length
    console.log(typeof a); // "undefined"
    
      To avoid potential errors when creating dynamic arrays at runtime, it’s much safer to stick with the array literal notation.
  • Check for Array-ness
       Using the typeof operator with array operands returns “object.”
    console.log(typeof [1, 2]); // "object"
       Although this behavior makes sense (arrays are objects), it’s not too helpful. Often you need to know if a value actually is an array. Sometimes you can see code checking for the presence of length property or some array method such as slice() to determine “array-ness.” But these checks are not robust because there’s no reason why a nonarray object shouldn’t have properties and methods with the same names. Also people sometimes use instanceof Array, but this check works incorrectly when used across frames in some IE versions. ECMAScript 5 defines a new method Array.isArray(), which returns true if the argument is an array. For example:
    Array.isArray([]); // true
    // trying to fool the check
    // with an array-like object
    Array.isArray({
    	length: 1,
    	"0": 1,
    	slice: function () {}
    }); // false
    
       If this new method is not available in your environment, you can make the check by calling the Object.prototype.toString() method. If you invoke the call() method of toString in the context of an array, it should return the string “[object Array]”. If the context is an object, it should return the string “[object Object]”. So you can do something like this:

    	if (typeof Array.isArray === "undefined") {
    		Array.isArray = function (arg) {
    			return Object.prototype.toString.call(arg) === "[object Array]";
    		};
    	}
     
  • Error Objects
       JavaScript has a number of built-in error constructors, such as Error(), SyntaxError(),TypeError(), and others, which are used with the throw statement. The error objects created by these constructors have the following properties:

              • name
                 The name property of the constructor function that created the object; it could be  the general “Error” or a more specialized constructor such as “RangeError”

              • message
                  The string passed to the constructor when creating the object
     
       The error objects have other properties, such as the line number and filename where the error happened, but these extra properties are browser extensions inconsistently implemented across browsers and are therefore unreliable. 
       On the other hand, throw works with any object, not necessarily an object created with one of the error constructors, so you can opt in for throwing your own objects. Such error objects can have the properties “name,” “message,” and any other type of information you want to pass to be handled by the catch statement. You can be creative when it comes to your custom error objects and use them to restore the application state back to normal.

    try {
    	// something bad happened, throw an error
    	throw {
    		name: "MyErrorType", // custom error type
    		message: "oops",
    		extra: "This was rather embarrassing",
    		remedy: genericErrorHandler // who should handle it
    	};
    } catch (e) {
    	// inform the user
    	alert(e.message); // "oops"
    	// gracefully handle the error
    	e.remedy(); // calls genericErrorHandler()
    }
    
         The error constructors invoked as functions (without new) behave the same as constructors (with new) and return the same error objects.




课程设计报告:总体方案设计说明 一、软件开发环境配置 本系统采用C++作为核心编程语言,结合Qt 5.12.7框架进行图形用户界面开发。数据库管理系统选用MySQL,用于存储用户数据与小精灵信息。集成开发环境为Qt Creator,操作系统平台为Windows 10。 、窗口界面架构设计 系统界面由多个功能模块构成,各模块职责明确,具体如下: 1. 起始界面模块(Widget) 作为应用程序的入口界面,提供初始导航功能。 2. 身份验证模块(Login) 负责处理用户登录与账户注册流程,实现身份认证机制。 3. 游戏主大厅模块(Lobby) 作为用户登录后的核心交互区域,集成各项功能入口。 4. 资源管理模块(BagWidget) 展示用户持有的全部小精灵资产,提供可视化资源管理界面。 5. 精灵详情模块(SpiritInfo) 呈现选定小精灵的完整属性数据与状态信息。 6. 用户名录模块(UserList) 系统内所有注册用户的基本信息列表展示界面。 7. 个人资料模块(UserInfo) 显示当前用户的详细账户资料与历史数据统计。 8. 服务器精灵选择模块(Choose) 对战准备阶段,从服务器可用精灵池中选取参战单位的专用界面。 9. 玩家精灵选择模块(Choose2) 对战准备阶段,从玩家自有精灵库中筛选参战单位的操作界面。 10. 对战演算模块(FightWidget) 实时模拟精灵对战过程,动态呈现战斗动画与状态变化。 11. 对战结算模块(ResultWidget) 对战结束后,系统生成并展示战斗结果报告与数据统计。 各模块通过统一的事件驱动机制实现数据通信与状态同步,确保系统功能的连贯性与数据一致性。界面布局遵循模块化设计原则,采用响应式视觉方案适配不同显示环境。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值