Understanding JavaScript Constructors

It was:

1) This article is technically sound. JavaScript doesn't really have classes in a traditional sense and this is the way most people shoehorn them in.

2) We may want to stop shoehorning them in. JavaScript has objects and we can use them in the way they are intended to do the same kinds of things. Kyle calls it OLOO (Objects Linked to Other Objects). 

Having a good understanding of constructors is crucial to truly understand the JavaScript language. Unlike many other languages, JavaScript doesn't support classes, but it has constructors to bring similar functionality to JavaScript. In this tutorial, we will explore constructors in detail and see how JavaScript utilizes them to make objects.
Constructors are like regular functions, but we use them with the "new" keyword. There are two types of constructors: native (aka built-in) constructors like Array and Object, which are available automatically in the execution environment at runtime; and custom constructors, which define properties and methods for your own type of object.

A constructor is useful when you want to create multiple similar objects with the same properties and methods. It’s a convention to capitalize the name of constructors to distinguish them from regular functions. Consider the following code:

function Book() {
// unfinished code
}
var myBook = new Book();

The last line of the code creates an instance of Book and assigns it to a variable; even though the Book constructor doesn't do anything, myBook is still an instance of it. As you can see there is no difference between this function and regular functions except that we call it with the new keyword and the function name is capitalized.

#Determining the Type of an Instance

To find out whether an object is an instance of another one, we use the instanceof operator:

myBook instanceof Book    // true
myBook instanceof String // false

Note that if the right side of the instanceof operator isn’t a function, it will throw an error:

myBook instanceof {};
// TypeError: invalid 'instanceof' operand ({})

Another way to find the type of an instance is using the constructor property. All object instances have a constructor property that point to the constructor function that created it.

Consider the following code fragment:

myBook.constructor == Book;   // true

Since the constructor property of myBook points to Book the result is true. All objects inherit a constructor property from their prototype:

var s = new String("text");
s.constructor === String; // true "text".constructor === String; // true var o = new Object();
o.constructor === Object; // true var o = {};
o.constructor === Object; // true var a = new Array();
a.constructor === Array; // true [].constructor === Array; // true

Although checking constructor property can be used to check the type of an instance, it is recommended to only use the instanceof operator for this purpose, because the constructor property might be overwritten, so it cannot be a reliable method for checking the type of an instance.

#Custom Constructor Functions

A constructor is like a cookie cutter to make more than one object with similar features. In other words, the benefit of using a constructor is that it makes it easy to create multiple objects with the same properties and methods.

Consider the following code:

function Book(name, year) {
this.name = name;
this.year = '(' + year + ')';
}

The book constructor expects two parameters: name and year; when it is called with the new keyword it assigns the received parameters to the name and year property of the current instance so the constructor can be used to create objects with initialized name and year properties:

var firstBook = new Book("Pro AngularJS", 2014);
var secondBook = new Book("Secrets Of The JavaScript Ninja", 2013);
var thirdBook = new Book("JavaScript Patterns", 2010); console.log(firstBook.name, firstBook.year);
console.log(secondBook.name, secondBook.year);
console.log(thirdBook.name, thirdBook.year);

This code logs the following in the console:

As you can see, we can quickly build a large number of different book objects by invoking the Book constructor with different arguments. This is exactly the same pattern that JavaScript uses in its built-in constructors like Array() and Date().

#Object.defineProperty Function

The Object.defineProperty() can be used inside of a constructor to help perform all necessary property setup. Consider the following constructor:

function Book(name) {
Object.defineProperty(this, "name", {
get: function() {
return "Book: " + name;
},
set: function(newName) {
name = newName;
},
configurable: false
});
} var myBook = new Book("Single Page Web Applications");
console.log(myBook.name); // Book: Single Page Web Applications // we cannot delete the name property because "configurable" is set to false
delete myBook.name;
console.log(myBook.name); // Book: Single Page Web Applications // but we can change the value of the name property
myBook.name = "Testable JavaScript";
console.log(myBook.name); // Book: Testable JavaScript

In this code we used accessor properties inside theObject.defineProperty(). Accessor properties don’t include any properties or methods, but they define a getter to call when the property is read, and a setter to call when the property is written to.

A getter is expected to return a value, while a setter receives the value being assigned to the property as an argument. This constructor allows us to set or change the name property of instances, but we are not allowed to delete it, and when we get the value of name, the getter prepends the string "Book: " to the name and returns it.

#Object Literal Notations are Preferred to Constructors

The JavaScript language has nine built-in constructors: Object(),Array()String()Number()Boolean()Date()Function(),Error() and RegExp(). When creating values we are free to use either object literals or constructors, but object literals are not only easier to read but also faster to run because they can be optimize at parse time. Whenever we need simple objects it's best to stick with literals:

// a number object
// numbers have a toFixed() method
var obj = new Object(5);
obj.toFixed(2); // 5.00 // we can achieve the same result using literals
var num = 5;
num.toFixed(2); // 5.00 // a string object
// strings have a slice() method
var obj = new String("text");
obj.slice(0,2); // "te" // same as above
var string = "text";
string.slice(0,2); // "te"

As you can see there's hardly any difference between these object literals and constructors and we can still call methods on literals. It's because when we call a method on a literal, behind the scene JavaScript converts the literal to a temporary object so that it's possible to use object methods for primitive values, then JavaScript discards the temporary object.

#Using the "new" Keyword is Essential

It's important to remember to use the new keyword before all constructors, if we accidentally forget "new" we will be modifying the global object instead of the newly created object. Consider the following example:

function Book(name, year) {
console.log(this);
this.name = name;
this.year = year;
} var myBook = Book("js book", 2014);
console.log(myBook instanceof Book);
console.log(window.name, window.year); var myBook = new Book("js book", 2014);
console.log(myBook instanceof Book);
console.log(myBook.name, myBook.year);

When we call the Book constructor without new keyword, in fact we are just calling a function without a return statement and "this" inside the Book constructor will be equal to Window (instead of myBook), in other words we have unintentionally created two global variables which causes the code to produce unintended results, but when we call the function with the "new" keyword the context is switched from global (window) to the instance, therefore "this" points to myBook. Here is what the above code logs in browser console:

Note that in strict mode this code throws an error because strict mode protects us from accidentally calling a constructor without the newkeyword.

#Scope-Safe Constructors

Since a constructor is just a function, it can be called without the newkeyword, but this leads to unexpected results and errors especially for inexperienced programmers. The solution to this problem is scope-safe constructors. We can call Scope-safe constructors with or without new keyword and they return the same result in either form.

Most of built-in constructors, such as Object, Regex and Array, are scope-safe. They use a pattern to determine whether the constructor is called withnew or not.

If new isn't used, a proper instance of the object is created by calling the constructor again with new keyword. Consider the following code:

function Book(name) {
if (!(this instanceof Book)) { // the constructor was called without "new".
return new Book(name);
}
}

So using this pattern we can easily rewrite a scope-safe version of our constructor:

function Book(name, year) {
if (!(this instanceof Book)) {
return new Book(name, year);
}
this.name = name;
this.year = year;
} var person1 = new Book("js book", 2014);
var person2 = Book("js book", 2014);
console.log(person1 instanceof Book); // true
console.log(person2 instanceof Book); // true

The fact that "this" is an instance of the custom type allows us to determine if new is not used as soon as the constructor begins to execute and run the constructor again with new keyword.

#Conclusion

JavaScript has no class statement, which is baffling for coders who are used to languages with a class statement; However, JavaScript has constructors to bring similar functionality. Constructors are just regular functions which are used with new keyword. They come in handy when we need to make multiple similar objects with the same properties and methods.

原文链接:https://css-tricks.com/understanding-javascript-constructors/

JavaScript Constructors的更多相关文章

  1. JavaScript constructors, prototypes, and the `new` keyword

    Are you baffled(阻碍:使迷惑) by the new operator in JavaScript? Wonder what the difference between a func ...

  2. 图解Javascript原型链

    本文尝试阐述Js中原型(prototype).原型链(prototype chain)等概念及其作用机制.上一篇文章(图解Javascript上下文与作用域)介绍了Js中变量作用域的相关概念,实际上关 ...

  3. [Javascript] ES6 Class Constructors and the Super Keyword

    When the ES6 class shipped back in 2015, a number of additional keywords came with it. Two of these ...

  4. JavaScript中对象的比较

    Javascript中有'=='和'==='两种相等比较,后者是全等,会判断数据类型,前者是相等,在比较时,会发生隐式转换. 如果将两个对象做'=='比较,结果会如何呢? 比如有如下两个对象: var ...

  5. 深入理解javascript(一)

    此段文章摘自大叔的博客: 此文的目的是书写可维护的javascript代码. 最小的全局变量: JavaScript通过函数管理作用域.在函数内部声明的变量只在这个函数内部,函数外面不可用.另一方面, ...

  6. JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance

    // the parent constructor function Parent(name) { this.name = name || 'Adam'; } // adding functional ...

  7. JavaScript Patterns 5.4 Module Pattern

    MYAPP.namespace('MYAPP.utilities.array'); MYAPP.utilities.array = (function () { // dependencies var ...

  8. JavaScript Patterns 5.3 Private Properties and Methods

    All object members are public in JavaScript. var myobj = { myprop : 1, getProp : function() { return ...

  9. JavaScript Patterns 5.1 Namespace Pattern

    global namespace object // global object var MYAPP = {}; // constructors MYAPP.Parent = function() { ...

随机推荐

  1. 朱子奇- 精算师,Tailorwoods创始人 | 到「在行」来约见我

    朱子奇- 精算师,Tailorwoods创始人 | 到「在行」来约见我 Tailorwoods

  2. 动态加载/删除css文件以及图片预加载

    动态加载/删除css文件以及图片预加载   功能模块页面   最近,工作中遇到了一个比较奇葩的需求:要在一个页面(PC端)增加一个功能模块,但是这个页面在不久之后要重构,为了新增加的模块可以继续复用, ...

  3. 产品如何进行大屏数据可视化.md

    最近接到一个需求,需要给公司的竞赛平台面对省/校/竞赛进行大屏的可视化话数据展示,闲暇之余对自己最近的工作进行一些总结; 一.数据可视化的定义 数据可视化主要是关于数据_视觉表现形式的科学技术研究 - ...

  4. Android View源码解读:浅谈DecorView与ViewRootImpl

    前言 对于Android开发者来说,View无疑是开发中经常接触的,包括它的事件分发机制.测量.布局.绘制流程等,如果要自定义一个View,那么应该对以上流程有所了解.研究.本系列文章将会为大家带来V ...

  5. socket阻塞与非阻塞,同步与异步I/O模型

    作者:huangguisu 原文出处:http://blog.csdn.NET/hguisu/article/details/7453390 socket阻塞与非阻塞,同步与异步 1. 概念理解 在进 ...

  6. VS中的 MD/MT设置 【转】

    VS系列工具作为目前微软主打的集成开发环境,在历经了近20多年的发展后,到如今已经可以 说是Windows平台上各种IDE环境中的翘楚了.很多别的开发工具已经难望其项背了,如今VS2010也已经面市很 ...

  7. Webduino Smart 从入门到起飞

    前言 原创文章,转载引用务必注明链接.水平有限,如有疏漏,欢迎指正. 试用了一下,感觉这板子+WebduinoBlockly在线开发环境,下限低.上限也低,以后肯定要刷其他固件的.举个简单的例子,WB ...

  8. 解决MySQL出现大量unauthenticated user的问题

    近期OJ及相关的站点打开异常的慢,简直崩溃,一直没找着原因. 进入数据库server.进到mysql里,用show processlist命令查看一下,发现有非常多的unauthenticated u ...

  9. Android添加系统级顶层窗口 和 WindowManager添加view的动画问题

    当Dialog有编辑框时如果选择会弹菜单窗口就不要用 Context applicationContext = mainActivity.getApplicationContext(); AlertD ...

  10. Jenkins 搭建

    持续集成(CI continuous integration) 可以做什么? 自动构建.定时触发,或由某个事件触发.比如可以做 daily build,或每次代码提交时触发.这样可以最早发现代码编译和 ...