《javascript模式--by Stoyan Stefanov》书摘--字面量和构造函数

时间:2023-02-22 16:59:52

二、字面量和构造函数

1,能够使用对象字面量时,就没理由使用new Object构造函数

//   一个空对象
var 0 = new Object();
console.log( o.constructor === Object ); //true // 一个数值对象
var o = new Object(1);
console.log( o.constructor === Number ); //true

2、自定义构造函数

可重用的成员,比如可重用方法,都应该放置到对象的原型中

3、构造函数的返回值

在构造函数中可以*返回任意对象,只要它是一个对象。如果不是,并不会造成错误,相反,构造函数将会返回this所引用的对象。

4、构造函数避免使用this

function Sayhello() {
this.name = "finder"; //等同window.name
return this;
} // 以上虽然在ES5得到解决,并且在严格模式中this不会指向 全局变量
// 推荐以下方式
function Sayhello() {
var that = {};
that.name = "finder"; //
return that;
}

5、自调用构造函数

function Sayhello (){
if ( !(this instanceof Sayhello)) {
return new Sayhello();
}
} // 通用方法
function Sayhello (){
if ( !(this instanceof arguments.callee)) {
return new arguments.callee();
}
}

6、数组构造函数的特殊性(数组字面量表示更为安全)

//   一个元素数组
var a = [3];
console.log(a.length); //
console.log(a[0]); // // 三个元素的数组
var a = new Array(3);
console.log(a.length); //
console.log(typeof a[0]); //"undefined" // 如果传入一个浮点数?worst...
var a = [3.14];
console.log(a[0]); // 3.14
var a = new Array(3.14);
console.log(a.length); // RangeError: Invalid array length

7、检查数组性质

参考地址:http://www.nowamagic.net/librarys/veda/detail/1250

//  数组也是对象
typeof []; // "object" // 支付宝同学在用的
if (value instanceof Array ||
(!(value instanceof Object) &&
(Object.prototype.toString.call((value)) == '[object Array]') ||
typeof value.length == 'number' &&
typeof value.splice != 'undefined' &&
typeof value.propertyIsEnumerable != 'undefined' &&
!value.propertyIsEnumerable('splice'))) {
return 'array';
} // 最直接的、简单的方式(在不同 iframe 中创建的 Array 并不共享 prototype)
var arr = [];
arr instanceof Array; // true
arr.constructor == Array; //true // 基于iframe的情况 使用 Douglas Crockford 的方法是可以解决这个问题(《JavaScript 语言精粹》P61)
var is_array = function(value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.splice === 'function' &&
!(value.propertyIsEnumerable('length'));
}; // 更简单的方法,也是jQuery 正在使用的。淘宝的 kissy 也是使用这种方式
var isArray = function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
} // 大而全而cool 判断类型
var is = function (obj,type) {
return (type === "Null" && obj === null) ||
(type === "Undefined" && obj === void 0 ) ||
(type === "Number" && isFinite(obj)) ||
Object.prototype.toString.call(obj).slice(8,-1) === type;
}
// jQuery,Ext3的写法,也是推荐的写法
isArray : function(v){
return toString.apply(v) === '[object Array]';
}

 8、JSON

json和文字对象之间唯一的语法差异:属性名必需包装在引号中才能成为合法的JSON,而在对象字面量中,仅当属性名称不是有效的标识符时才会需要引号,比如:字符之间的空格{"first name": "javascript"}

此外,在JSON字符串中,不能使用函数或正则表达式字面量

9、使用JSON

JSON.parse()方法是ES5的一部分,一般情况下可以使用JSON.org库(http://www.json.org/json2.js)以访问JSON对象及其方法。

//   JQuery的parseJSON()方法
var data = '{"name": “finder”}';
console.log( JQuery.parseJSON( data.name ) ); // "finder" // 与JSON.parse()相对的方法JSON.stringify()

10、正则表达式字面量

javasript正则表达式也是对象

typeof /\//;    //"object"

//   创建正则表达式
var re = /\\/g; // 字面量方法创建 推荐
var re = new RegExp("\\\\", "gm"); // 构造函数方法创建

11、正则表达式语法

用斜杠来包装用于匹配的正则表达式模式,在第二个斜杠之后,可以将该模式改为不加引号的字母形式:

  • g----全局匹配
  • m---多行
  • i----大小写敏感的匹配
//  正则表达式使用
var name = "fin123d456e789r".replace(/[0-9]/gi, "");
console.log(name); // "finder"

使用new RegExp()的原因:某些场景无法事先确定模式,而只能在运行时以字符串方式创建。

正则表达式字面量各构造函数之间的其中一个区别在于:字面量在解析时只有一次创建了一个对象,如下例子()

//经测试字面量创建共享一个对象的情况在浏览器里已经不存在了,包括IE6
function getName () {
var person = /[a-z]/;
person.name = "finder";
return person;
} var firstName = getName(),
realName = getName(); console.log(firstName === realName); // false
firstName.name = "liubei";
console.log(realName.name) // "finder"

如代码所示,这样的情况如果在浏览器环境中就可以不用考虑了

注:调用RegExp()时不使用new与使用new效果是相同的

12、基本值类型包装器

javascript有五个基本的值类型:数字,字符串,布尔值,nullt和undefined。除了null和undefined以外,其他三个具有所谓的基本包装对象(primitive wrapper object)。可以使用内置构造函数Number(),String(),Boolean()创建包装对象。

为了基本(primitive)数字和数字对象(object)之间的差异,来个例子

//  一个基本类型
var n = 6;
console.log(typeof n); // number // 一个数值Number对象
var nbj = new Number(6)j;
console.log(typeof nbj); // object

当基本类型使用对象方法的时候它会自动临时转换为一个对象

//  用来作为对象的基本字符串
var name = "finder";
console.log(name.toUpperCase()); // FINDER // 值本身可以作为一个对象
"finder".slice(0,4); // "find" // 与数值的方法相同
(22/7).toPrecision(3); // "3.14"

通常使用包装对象的原因:有扩充值以及持久保存状态的需要,由于基本值类型不是对象,不可能扩充属性

//    基本字符串
var greet = "hello I'm finder"; // 使用split自动从基本数据类型转换为对象
greet.split(" ")[0]; // "hello" // 试图增加一个原始数据类型并不会导致错误
greet.smile = true; // 但,它并不是实际运行。。
typeof greet.smile; // "undefined"

在使用没有带new操作符时,它将转换为一个基本类型

typeof Number(6)      //   "number"
typeof Number("6") // "number"
typeof Number(new Number()); // "number"
typeof String(6); // "string"
typeof Boolean(1); // "boolean" // 神奇的布尔值~~
Boolean(1).toString(); // "true"
Boolean(0).toString(); // "false"
Boolean().toString(); // "false" // 下面的可以猜到吗???
Boolean(4).toString(); // "true"
Boolean(-4).toString(); // "true"
Boolean(0.1).toString() // "true"

13、错误对象

javascript有一些内置错误函数(error constructor),比如Error(),SyntaxError(),TypeError以及其他,这些都带有throw语句,通过这些错误构造函数创建的错误对象具有下列属性:

name:名称属性,“Error”/更为专门的构造函数,比如"RangeError"

message:字符串

错误对象还有一些其他属性,因浏览器实现不一,并不可靠。

另外,throw适用于任何对象,

try{
// 抛出错误
throw{
name : string,
message : “oop”,
extra : string,
remedy : genericErrorHandler // 指定应该处理该错误的函数
}
}catch(e){
// 通知用户
alert(e.message); // "oop"
e.remedy(); // 调用函数genericErrorHandler
}
// 错误构造函数心函数的形式调用(不带new)时,其表现行为与构造函数(带new)相同,并且返回同一个错误对象

14、常用构造函数

一般情况下,除了Date()构造函数以外,很少需要内置构造函数,下面为常用函数

//    Built-in constructors   (avoid)
var o = new Object();
var a = new Array();
var re = new RegExp("[a-z]", "g");
var s = new String();
var n = new Number();
var b = new Boolean();
throw new Error("ooooooooops!"); // Literals an primitives (prefer)
var o = {};
var a = [];
var re = /[a-z]/g;
var s = "";
var n = 0;
var b = false;
throw{
name : "Error",
message: "oooooooooops!!!"
}
// or
throw Error("oooooooops!");