Literals and constructors

Source: Internet
Author: User

Literals and constructors

The literal patterns in JavaScript are more concise, expressive, and are not prone to error when defining objects. This chapter discusses literals, including objects, arrays, and regular expression literals, and why literals are better than equivalent built-in constructors (such as Object() , Array() etc.). This chapter also describes the JSON format, which is a data interchange format defined using the form of arrays and object literals. This chapter also discusses custom constructors, including how to enforce them new to ensure that constructors execute correctly.

To facilitate the use of literals rather than constructors, this chapter complements some of the knowledge, such as the built-in wrapper constructors Number() , String() and Boolean() , and how to compare them to the original values (numbers, strings, and Boolean values). Finally, a quick introduction to Error() the use of constructors.

Object literal

We can simply interpret the objects in JavaScript as hash tables (hash table, also called hash table) consisting of name value pairs. In other programming languages, it is called an associative array. The value can be either the original value or the object. Regardless of the type, they are property, and the property value can also be a function, when the property is called method.

Custom objects in JavaScript (user-defined local objects) are mutable at any time. The properties of built-in local objects are also mutable. You can create an empty object first, and then add functionality to it when you need it. "Object literal notation (literal notation)" is an ideal way to create objects on demand.

Take a look at this example:

// 定义空对象var dog = {};// 添加一个属性dog.name = "Benji";// 添加一个方法dog.getName = function () {    return dog.name;};

In this example, we first define an empty object, and then add a property and a method that can be used at any time during the lifetime of the program:

    • Change the values of properties and methods, such as:

      Dog.getname = function () {//redefine method, returns a hard-coded value return "Fido";};

    • Delete Properties/Methods

      Delete Dog.name;

    • Add more properties and methods

      Dog.say = function () {return "woof!";}; Dog.fleas = true;

It is not necessary to create an empty object each time, and the object literal pattern can add functionality directly to the object creation, as in the following example:

var dog = {    name: "Benji",    getName: function () {        return this.name;    }};

It is important to understand that there are many references to "empty Objects" ("Blank object" and "null") in this book, which is simply a short name, and there is no real empty object in JavaScript at all. Even the simplest {} objects contain Object.prototype properties and methods inherited from them. The "empty" object we mentioned simply says that the object has no property (own properties), regardless of whether it has inherited attributes.

Object literal syntax

If you've never been in touch with the object literal, it might feel weird. But the more you love it later. Essentially, the object literal syntax includes:

    • Enclose the object body within a pair of curly braces ( { and } ).
    • You use commas to separate properties or methods within an object. The last name can also have a comma after the value, but in IE will be error, so try not to add a comma after the last property or method.
    • The property name and value are separated by a colon.
    • If you assign an object to a variable, do not forget to fill the } semicolon after the closing parenthesis.
Creating an object from a constructor function

There is no class concept in JavaScript, which gives JavaScript a great deal of flexibility because you don't need to know anything about an object in advance, or the "Blueprint" of a class: The structure of a class. But JavaScript also has constructors, whose syntax is very similar to the creation of classes-based objects in Java or other languages.

You can use a custom constructor to create an object instance, or you can use built-in constructors to create, for example Object() ,, Date() , and String() so on.

The following example shows the creation of two separate instance objects using two equivalent methods:

// 一种方法,使用字面量var car = {goes: "far"};// 另一种方法,使用内置构造函数// 注意:这是一种反模式var car = new Object();car.goes = "far";

As you can see from this example, one of the obvious advantages of the literal notation is that it has less code. "The best way to create an object is to use a literal" there is another reason why it can be emphasized that an object is simply a mutable hash, not necessarily derived from a class.

Another reason to create an instance object using a literal rather than a Object() constructor is that the object literal does not require a scope resolution (scope resolution). Because there is a possibility that you have created a constructor with the same name, Object() when you invoke Object() it, the parser needs to follow the scope chain from the current scope until it finds the global Object() constructor.

argument to the Object () constructor

The title of this section is Object Constructor Catch, the translator's level is limited, I do not know how to translate, so I changed the title of this section.

You do not use constructors when creating an instance object, new Object() but sometimes you may be working on a code that someone else writes, and you need to understand an "attribute" of the constructor (and another reason not to use it), that is, the Object() constructor can receive the arguments, This parameter allows you to delegate the creation of an object instance to another built-in constructor and return another object instance, which is often not what you want.

The following example code shows the passing of new Object() different parameters (numbers, strings, and Boolean values), resulting in objects that are generated by different constructors:

// 注意:这是反模式// 空对象var o = new Object();console.log(o.constructor === Object); // true// 数值对象var o = new Object(1);console.log(o.constructor === Number); // trueconsole.log(o.toFixed(2)); // "1.00"// 字符串对象var o = new Object("I am a string");console.log(o.constructor === String); // true// 普通对象没有substring()方法,但字符串对象有console.log(typeof o.substring); // "function"// 布尔值对象var o = new Object(true);console.log(o.constructor === Boolean); // true

Object()This characteristic of the constructor causes some unexpected results, especially when the parameters are indeterminate. Finally, again, do not use the new Object() object literal as much as possible to create the instance object.

Custom constructors

In addition to object literals and built-in constructors, you can create object instances from custom constructors, as shown in the following code:

var adam = new Person("Adam");adam.say(); // "I am Adam"

This writing is very similar to Java in the Person creation of an instance of a class, the syntax is very close, but in fact, JavaScript does not have the concept of class, Person() is a function.

Person()How is the constructor defined? Look at the following code:

var Person = function (name) {    this.name = name;    this.say = function () {        return "I am " + this.name;    };};

newthese things happen in the function body when you call this constructor by:

    • Creates an empty object, assigns a reference to it this , and inherits the prototype of the function.
    • by this adding properties and methods to this object.
    • Finally returns the new object this is pointing to (if no other object is returned manually).

The process is represented in code as follows:

var Person = function (name) {    // 使用对象字面量创建新对象    // var this = {};    // 添加属性和方法    this.name = name;    this.say = function () {        return "I am " + this.name;    };    //return this;};

In the example above, for simplicity, the say() method is added to, and the this result is that whenever a call is made, new Person() a new function () is created in memory say() , which is obviously inefficient because the methods of all instances say() are identical. The best way to do this is to add the method to Person() the prototype.

Person.prototype.say = function () {    return "I am " + this.name;};

We will discuss prototypes and inheritance in detail in the next chapter, and now just remember to put the members that need to be reused in the prototype.

The internal working mechanism of the constructor will also be discussed in more detail in subsequent chapters. Here we only make a brief introduction. As mentioned earlier, when the constructor executes, it first creates a new object and assigns its reference to this :

// var this = {};

In fact, this is not exactly the case, because the "empty" object is not really empty, the object inherits Person the prototype and looks more like:

// var this = Object.create(Person.prototype);

Further discussion will be discussed in subsequent chapters Object.create() .

The return value of the constructor function

When new the call is used, the constructor always returns an object, and by default returns the object to which it is this pointing. If no property is assigned within this the constructor, an "empty" object is returned (except for the prototype of the inherited constructor, which does not have its own property).

Although there is no statement in the constructor return , it is returned implicitly this . But in fact we can return any specified object, and in the following example we return the newly created that object.

var Objectmaker = function () {    // name属性会被忽略,因为返回的是另一个对象    this.name = "This is it";    // 创建并返回一个新对象    var that = {};    that.name = "And that‘s that";    return that;};// 测试var o = new Objectmaker();console.log(o.name); // "And that‘s that"

As you can see, the constructor can actually return any object, as long as you return something that is an object. If the return value is not an object (string, number, or Boolean), the program does not error, but the return value is ignored and ultimately returns the object that is being this referred to.

Forcing the use of new mode

We know that constructors are essentially the same as normal functions, just by new invoking them. So what happens if you forget to call the constructor new ? Missing new syntax errors and no run-time errors can result in logic errors that cause the execution results to be inconsistent with expectations. This is because if you do not write new , the inside of the function this will point to the global object (pointing at the browser side this window ).

When the constructor contains this.member such code, and calls the function directly (omitted new ), it actually creates a property of the global object member that can be passed through window.member or member accessed to. This is not the result we want because we are trying to make sure that the global namespace is clean.

// 构造函数function Waffle() {    this.tastes = "yummy";}// 新对象var good_morning = new Waffle();console.log(typeof good_morning); // "object"console.log(good_morning.tastes); // "yummy"// 反模式,漏掉newvar good_morning = Waffle();console.log(typeof good_morning); // "undefined"console.log(window.tastes); // "yummy"

This unexpected behavior logic is fixed in ECMAScript5. In strict mode, this no longer points to the global object. If you are in a JavaScript environment that does not support ES5, there are ways to ensure that the new behavior of constructors is consistent.

Naming conventions

A simple solution to the above problem is the naming convention, which has been discussed in the previous chapters, with the first letter of the construction function capitalized ( MyConstructor() ), the normal function and the method first letter lowercase ( myFunction ).

Use that

Compliance with naming conventions has a role to play, but the specification is not mandatory after all, and cannot be avoided entirely. Here is a pattern that ensures that constructors are guaranteed to be executed as constructors, that is, not to add all members to the this top, but to add them to the that top and return them that .

function Waffle() {    var that = {};    that.tastes = "yummy";    return that;}

If you want to create a simpler object, and you don't even need that a local variable, you can simply return an object literal, just like this:

function Waffle() {    return {        tastes: "yummy"    };}

newIt returns an instance object regardless of the way it is called (using or calling directly):

var first = new Waffle(),    second = Waffle();console.log(first.tastes); // "yummy"console.log(second.tastes); // "yummy"

The problem with this pattern is that the prototypes are lost, so that the Waffle() members on the prototype are not inherited into those objects.

It is important to note that this is that a naming convention that is that not part of the language feature and can be replaced with any name you like, such as self or me .

Call the constructor of itself

To solve the problem of the above pattern, we can let the object inherit the properties on the prototype, we use the following method: In the constructor, first check this whether it is an instance of the constructor, if not, by new calling yourself again:

function Waffle() {    if (!(this instanceof Waffle)) {        return new Waffle();    }    this.tastes = "yummy";}Waffle.prototype.wantAnother = true;// 测试var first = new Waffle(),    second = Waffle();console.log(first.tastes); // "yummy"console.log(second.tastes); // "yummy"console.log(first.wantAnother); // trueconsole.log(second.wantAnother); // true

There is also a more general way to check an instance by using it instead of arguments.callee simply writing the constructor name to die in the code:

if (!(this instanceof arguments.callee)) {    return new arguments.callee();}

This pattern takes advantage of the fact that an object is created inside any function arguments that contains the arguments passed in when the function is called. argumentscontains a callee property that points to the function being called. It is important to note that ES5 has been banned in strict mode arguments.callee , so it is best to limit its use and, wherever possible, to remove areas of existing code that are already in use.

Array literal

Like most "things" in JavaScript, arrays are objects as well. You can create an array by using a built-in constructor, Array() or you can create it in literal form, just like the object literal. It is also more recommended to create arrays using literals.

The sample code here shows two methods for creating two arrays with the same elements, using Array() and using the literal pattern:

// 有三个元素的数组// 注意:这是反模式var a = new Array("itsy", "bitsy", "spider");// 完全相同的数组var a = ["itsy", "bitsy", "spider"];console.log(typeof a); // "object",因为数组也是对象console.log(a.constructor === Array); // true
Array literal syntax

Array literals are simple to use: The entire array is enclosed in square brackets, and the array elements are separated by commas. An array element can be any type, including arrays and objects.

The array literal syntax is simple, intuitive and elegant, after all, the array is just a collection of some values indexed from 0, and there is absolutely no need to introduce constructors and new operators (and write more code).

The "trap" of the Array () constructor

We new Array() also have a reason to be at a distance, in order to avoid the trap caused by the constructor function.

If Array() a number is passed to the constructor, the number does not become the first element of the array, but the length of the array is set. That is, an new Array(3) array of length 3 is created instead of an element of 3. If you access any of the elements of an array, you will get undefined it because the element does not exist. The following example code shows the difference between a literal and a constructor:

// 含有1个元素的数组var a = [3];console.log(a.length); // 1console.log(a[0]); // 3// 含有3个元素的数组var a = new Array(3);console.log(a.length); // 3console.log(typeof a[0]); // "undefined"

The behavior of the constructor may be a bit unexpected, but when it comes to new Array() passing a floating-point number, the situation is even worse, and an error occurs when the incoming floating-point number for the new array () is reported as "range error" rangerror) because the array length cannot be a floating-point number.

// 使用数组字面量var a = [3.14];console.log(a[0]); // 3.14var a = new Array(3.14); // RangeError: invalid array lengthconsole.log(typeof a); // "undefined"

To avoid this error when creating an array dynamically at run time, it is strongly recommended to use the array literal instead new Array() .

Some people use Array() constructors to do interesting things, such as to generate repeating strings. The following line of code returns a string containing 255 spaces (ask the reader to think about why it is not 256 spaces).var white = new Array(256).join(‘ ‘);

Check if array

If typeof the operand is an array, it returns "Object".

console.log(typeof [1, 2]); // "object"

The result is a little plausible, after all, the array is also an object, but for us this result is useless, in fact you often need to know that a value is not a real array. Sometimes you'll see some methods for checking arrays: Checking length properties, checking array methods such as slice() , and so on, but these methods are very fragile, and non-array objects can also have properties with the same name. Others use it instanceof Array to judge arrays, but this approach can cause problems in multiple IFRAME scenarios in some versions of IE: the reason is that arrays created in different IFrame do not share their properties with each other prototype .

ECMAScript5 defines a new method Array.isArray() that returns true if the argument is an array. Like what:

Array.isArray([]); // true// 尝试用一个类似数组的对象去测试Array.isArray({    length: 1,    "0": 1,    slice: function () {}}); // false

If your development environment does not support ECMASCRIPT5, you can use Object.prototype.toString() methods instead. The toString call() string "[Object array]" is returned as a method called and passed in the array context. If the object context is passed in, the string "[Object Object]" is returned. So you can do this:

if (typeof Array.isArray === "undefined") {    Array.isArray = function (arg) {        return Object.prototype.toString.call(arg) === "[object Array]";    };}
Json

We've just discussed object and array literals and you should be familiar with it, so let's take a look at JSON. JSON (JavaScript Object Notation) is a lightweight data interchange format that can be easily used in multiple languages, especially in JavaScript.

JSON format and its simplicity, it is just a mix of arrays and object literals, see an example of a JSON string:

{"name": "value", "some": [1, 2, 3]}

The only syntactic difference between JSON and object literals is that legitimate JSON attribute names need to be enclosed in quotation marks. In the object literal, quotation marks are used only if the property name is an illegal identifier, for example, the property name contains spaces {"first name": "Dave"} .

In a JSON string, you cannot use functions and regular expression literals.

Using JSON

As mentioned in the previous chapters, it is not recommended eval() to use rough parsing of JSON strings for security reasons. It is best JSON.parse() to use the method, which is already included in ES5, and the JavaScript engine in modern browsers has built-in support for JSON. For older JavaScript engines, you can use the JS file (http://www.json.org/json2.js) provided by json.org to get JSON objects and methods.

// 输入JSON字符串var jstr = ‘{"mykey": "my value"}‘;// 反模式var data = eval(‘(‘ + jstr + ‘)‘);// 更好的方式var data = JSON.parse(jstr);console.log(data.mykey); // "my value"

If you are already using a JavaScript library, it is likely that the library has already provided a way to parse the JSON, you do not have to introduce additional json.org libraries, for example, if you have used YUI3, you can:

// 输入JSON字符串var jstr = ‘{"mykey": "my value"}‘;// 使用YUI来解析并将结果返回为一个对象YUI().use(‘json-parse‘, function (Y) {    var data = Y.JSON.parse(jstr);    console.log(data.mykey); // "my value"});

If you are using jquery, you can directly use the method it provides parseJSON() :

// 输入JSON字符串var jstr = ‘{"mykey": "my value"}‘;var data = jQuery.parseJSON(jstr);console.log(data.mykey); // "my value"

JSON.parse()corresponding to the law of the square JSON.stringify() . It converts an object or array (or any primitive value) to a JSON string.

var dog = {    name: "Fido",    dob:new Date(),    legs:[1,2,3,4]};var jsonstr = JSON.stringify(dog);// jsonstr的值为// {"name":"Fido","dob":"2010-04-11T22:36:22.436Z","legs":[1,2,3,4]}
Regular expression literals

Regular expressions in JavaScript are also objects, and they can be created in two ways:

    • Using new RegExp() constructors
    • Use Regular expression literals

The following example code shows two ways to create a regular expression that matches a backslash (\):

// 正则表达式字面量var re = /\\/gm;// 构造函数var re = new RegExp("\\\\", "gm");

It is obvious that the literal notation of regular expressions is shorter and does not make you feel that you are writing regular expressions using the idea of a constructor like a class, so it is more recommended to use literal notation.

In addition, if you use the RegExp() constructor notation, you also need to consider escaping the quotation marks and backslashes, as shown in the previous snippet, with four backslashes to match a backslash. This increases the length of the regular expression and makes it harder to understand and maintain. Getting Started with regular expressions is not an easy task, so don't give up any chance to simplify them, try to create regular expressions using literals instead of constructors.

Regular expression literal syntax

Regular expression literals are wrapped with two slashes, and the body part does not include slashes at both ends. After the second slash you can specify the pattern-matching modifier, which does not need to be quoted, and there are three modifiers in javascript:

    • g, Global match
    • m, multi-line matching
    • i, ignoring case-matching

Modifiers are freely combinable, and are independent of order:

var re = /pattern/gmi;

Using regular expression literals can make your code more concise and efficient, such as when you invoke String.prototype.replace() a method, you can pass in a regular expression parameter:

var no_letters = "abc123XYZ".replace(/[a-z]/gi, "");console.log(no_letters); // 123

One of the scenarios that has to be used is that new RegExp() regular expressions are not deterministic and only wait until run time to determine the situation.

The other difference between regular expression literals and constructors is that the literal only creates a regular expression object at parse Time: parsing the same regular expression multiple times results in the same instance object. If the object is created repeatedly using the same literal in the loop body, the object created for the first time and its properties (for example) are returned lastIndex . The following example shows the case of returning the same regular expression two times.

function getRE() {    var re = /[a-z]/;    re.foo = "bar";    return re;}var reg = getRE(),    re2 = getRE();console.log(reg === re2); // truereg.foo = "baz";console.log(re2.foo); // "baz"

This has changed in ECMAScript5, and each computation of the same regular expression literal creates a new instance object, which is now corrected by many modern browsers.

Finally, it is necessary to mention that no new call RegExp() (as a normal function) new RegExp() is exactly the same as a band call.

Wrapper object for original value

There are five primitive types in javascript: Numbers, strings, Booleans, null and undefined . In null addition undefined to and, the other three types have a corresponding "wrapper object" (Primitive wrapper object). You can build wrapper objects by using built-in constructors Number() , String() and Boolean() .

To illustrate the difference between a numeric original value and a numeric object, take a look at the following example:

// 一个数字原始值var n = 100;console.log(typeof n); // "number"// 一个Number对象var nobj = new Number(100);console.log(typeof nobj); // "object"

The wrapper object has some useful properties and methods. For example, a numeric object toFixed() has toExponential() a method with and and the like, a string object with substring() , chatAt() and and so on, and toLowerCase() length properties. These methods are very handy, and this is the advantage of wrapping the object compared to the original value, but the original value can also call these methods, because the original value is first converted to a temporary object, and if the conversion succeeds, the method that wraps the object is called.

// 像使用对象一样使用一个字符串原始值var s = "hello";console.log(s.toUpperCase()); // "HELLO"// 值本身也可以像对象一样"monkey".slice(3, 6); // "key"// 数字也是一样(22 / 7).toPrecision(3); // "3.14"

Because the original value can be converted to an object as needed, it is not necessary to manually "wrap" the original value into an object in order to wrap the object in its own way. For example, you do not need to use the new String ("HI") to directly use "HI".

// 避免这些:var s = new String("my string");var n = new Number(101);var b = new Boolean(true);// 更好更简洁的办法:var s = "my string";var n = 101;var b = true;

One scenario where you have to use a wrapper object is that sometimes we need to expand the value and keep the value state. The original value is not an object after all, and it cannot be expanded directly.

// 字符串原始值var greet = "Hello there";// 为使用split方法,原始值被转换为对象greet.split(‘ ‘)[0]; // "Hello"// 给原始值添加属性并不会报错greet.smile = true;// 但实际上却没有作用typeof greet.smile; // "undefined"

In this sample code, it is greet only temporarily converted to an object to guarantee access to its properties and methods without error. In another case, greet by new String() being defined as an object, the smile process of expanding the property is as we would expect. It is rare to extend a string, number, or Boolean value, so it is recommended to use wrapper objects only if it is really necessary.

When omitted new , the wrapper object's constructor converts the arguments passed to it to the original value:

typeof Number(1); // "number"typeof Number("1"); // "number"typeof Number(new Number()); // "number"typeof String(1); // "string"typeof Boolean(1); // "boolean"
Error Handling Object

JavaScript has many built-in error-handling constructors, such as, Error() SyntaxError() , and TypeError() so on, that are commonly throw used with statements. The error objects created by these constructors contain these properties:

    • name

      A name attribute is the name of the constructor that generated the object, usually "Error", sometimes with a specific name such as "Rangeerror"

    • message

      The string passed into the constructor when the object was created

The Error object also has some other properties, such as the line number and file name that produce the error, but these properties are self-implemented by the browser, and the implementations of different browsers are inconsistent, so these properties are not recommended for compatibility reasons.

throwYou can throw any object, not just the "wrong object," so you can throw a custom object as needed. These objects contain the property "name" and "message" or other information that you want to pass to the exception handling logic, which is specified by the catch statement. You can flexibly use the thrown Error object to restore the program from an error state to a normal state.

try {    // 一些不好的事情发生了,抛出错误    throw {        name: "MyErrorType", // 自定义错误类型        message: "oops",        extra: "This was rather embarrassing",        remedy: genericErrorHandler // 应该由谁处理    };} catch (e) {    // 通知用户    alert(e.message); // "oops"    // 优雅地处理错误    e.remedy(); // 调用genericErrorHandler()}

Using new call and omit new call error constructors are identical and they all return the same Error object.

Summary

In this chapter, we discuss a number of literal patterns, which are alternatives to writing using constructors, which are described in this chapter:

    • Object literal notation-a simple and elegant way to define an object, wrapped by curly braces, separated by commas between the pairs of name values
    • Constructors-built-in constructors (built-in constructors usually have a corresponding literal syntax) and custom constructors
    • A technique for forcing a function to run a line in a pattern of constructors (regardless new of the instance that is always returned without invoking new the constructor)
    • Array literal notation-wrapped in square brackets, separated by commas between array elements
    • json--a lightweight Data interchange format
    • Regular expression literals
    • Avoid using other built-in constructors: String() , Number() , Boolean() and different kinds of Error() constructors

In general, except Date() that other built-in constructors are not commonly used, the following table organizes these constructors and their literal syntax.

Built-in constructors (not recommended) Literal syntax and primitive values (recommended)
var o = new Object (); var o = {};
var a = new Array (); var a = [];
var re = new RegExp ("[A-Z]", "G"); var re =/[a-z]/g;
var s = new String (); var s = "";
var n = new number (); var n = 0;
var B = new Boolean (); var B = false;
throw new Error ("Uh-oh"); Throw {name: "error", Message: "Uh-oh"}, or throw Error ("Uh-oh");

Literals and constructors

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.