<<Javascript Patterns>>阅读笔记 – 第3章 字面量和构造函数

对象字面量

首先给出对象字面量的定义语法:

1. 将对象定义在一对括号中(左大括号“{”和右大括号”}”)

2. 对象中以逗号分隔属性和方法. 每个属性或方法以key-value的形式出现, key和value之间以冒号分割.

3. 当给变量赋值时, 不要忘记或大括号后面的分号

空对象

var obj = {};

这样就定义了一个空的对象, 但它并非什么也没有, 至少它具有从Object.prototype中继承下来的属性和方法.

来自构造函数的对象

语法:

// 反模式, 不推荐这么用
Var obj = new Object();
obj.name = ‘张三’;

与字面量创建对象的方式相比, 字面量对象输入的字符更少,

而且, 当创建一个局部函数时, 解释器需要从调Object()位置开始向上查询作用域链, 直到发现全局的Object构造函数.

当使用Object()构造函数创建对象时, 直到代码运行时才能确定其类型, 借用书中的例子:

// 创建一个空对象
var o1 = new Object();
console.info(o1.constructor == Object); // true
// 创建一个数值对象
var o2 = new Object(7);
console.info(o2.constructor == Number); // true
// 创建一个字符串对象
var o3 = new Object(‘hello world‘);
console.info(o3.constructor == String); // true

总得来说, 不要使用new Object()创建对象, 应该使用对象字面量的方式.

自定义构造函数及其返回值

// 定义一个Person构造函数
function Person(name) {
    this.name = name;
    this.say = function () {
        console.info(‘hello!‘);
    };
};

当使用new调用构造函数时, 函数内部将创建一个this对象, 并将属性和方法添加到this对象中,

然后隐式的返回this对象(如果没有显式的return语句).

当然构造函数中可以显式的返回一个对象, 例如:

function Person() {
    this.name = ‘张三‘;
    // 创建一个that对象, 并返回该对象
    var that = {};
    that.name = ‘李四‘;
    return that;
}
var p = new Person();
console.info(p.name); // 李四

正如上面看到的, 构造函数可以返回任意对象, 只要它是一个对象.

如果构造函数试图返回一个非对象, 这虽然不会导致错误, 但还是忽略此返回值, 继续返回this, 例如:

function Person() {
    this.name = ‘张三‘;
    this.age = 21;
    return 0; // 试图返回一个非对象, 被忽略, 返回this
}
var p = new Person();
console.info(p.name); // 张三

强制使用new的模式

构造函数也是函数, 只不过它是用new操作符调用的.

如果在调用时, 忘记使用new操作符, 那么构造函数中的this将指向全局对象,

在浏览器环境下this会指向window对象, this的中所有属性或方法只能通过window对象来访问, 或是直接访问, 这显然是不想看到的情况.

// 构造函数
function Person() {
    this.msg = ‘hello‘;
}
// 定义一个对象
var p1 = new Person();
console.info(typeof p1); // object
console.info(p1.msg); // hello
// 反模式: 忘了使用new
var p2 = Person();
console.info(typeof p2); // undefined
console.info(msg); // hello
console.info(window.msg); // hello

上面的问题在ECMAScript5中已经得到了解决, 但在非EC5环境下, 需要想办法解决上面的问题.

命名约定

约定开头字母大写的函数为构造函数, 必须使用new来调用, 普通函数首字母小写, 可直接调用.

使用that

约定只是约定, 保不会忘, 下面的模式可以确保即使不使用new, 属性或方法也不会添加到全局对象中.

// 定义构造函数-1
function Person1() {
    var that = {};
    that.name = ‘张三‘;
    return that;
}
// 定义构造函数-2
function Person2() {
    return {
        name: ‘李四‘
    };
}
// 以上两种方式, 总会返回一个对象
var p1 = new Person1(),
    p2 = Person1();
console.info(p1.name); // 张三
console.info(p2.name); // 李四

但是, 上面两种模式会丢失与各自原型的链接, 当扩展其原型时, 对于对象来说都是不可用的, 例如:

// 定义构造函数-1
function Person1() {
    var that = {};
    that.name = ‘张三‘;
    return that;
}
// 扩展Person1的原型
if(typeof Person1.prototype.say === ‘undefined‘) {
    Person1.prototype.say = function() {
        console.info(‘hello world...‘);
    }
}
var p1 = new Person1();
p1.say(); // TypeError: p1.say is not a function

自调用构造函数

为了解决上述两种模式的问题, 可以引用下面的解决方案,

就是在构造函数内部, 检查this对象是否是构造函数的一个实例, 如果不是, 那么使用new操作符再次调用构造函数创建对象, 代码如下:

// 定义构造函数
function Person() {
    // 注意this instanceof Person需要用括号括起来
    if(!(this instanceof Person)) {
        return new Person();
    }
    this.name = ‘张三‘;
}
// 扩展其原型
if(typeof Person.prototype.say === ‘undefined‘) {
    Person.prototype.say = function() {
        console.info(‘hello world...‘);
    }
}
var p1 = new Person(),
    p2 = Person();
console.info(p1.name); // 张三
p1.say(); // hello world...
console.info(p2.name); // 张三
p2.say(); // hello world...

数组字面量

推荐使用字面量的方式创建数组, 主要原因一是因为数组字面量简单明确, 二是因为数组构造函数的特殊性.

当向Array()构造函数中传递单个数值时, 它不会成为数组的第一个元素, 而是设置了数组的长度,

但是该数组中没有实际的元素, 所以当访问数组的元素时返回的是undefined. 来几个小例子:

var arr1 = [7];
console.info(arr1.length); // 1
console.info(arr1[0]); // 7

var arr2 = new Array(7);
console.info(arr2.length); // 7
console.info(arr2[0]); // undefined

var arr3 = [3.14];
console.info(arr3.length); // 1
console.info(arr3[0]); // 3.14

var arr4 = new Array(3.14); // RangeError: invalid array length
console.info(arr4.length);
console.info(arr4[0]);

检查数组的性质

使用typeof对数组进行操作, 返回值为”object”, 因为数组也是对象, 但意义不大.

可以通过检查length属性或slice()方法来判断是不是数组, 但是, 其他的自定义对象同样可以拥有这些属性和方法.

ECMAScript5中定义了Array.isArray()方法, 来判断对象是不是数组, 但是不支持EC5的环境中就无法使用该方法. 但仍可以通过以下方法检测是否是数组:

if(typeof Array.isArray === ‘undefined‘) {
    Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === ‘[object Array]‘;
    }
}
时间: 2024-12-09 23:17:16

<<Javascript Patterns>>阅读笔记 – 第3章 字面量和构造函数的相关文章

JavaScript模式读书笔记 第3章 字面量和构造函数

1,对象字面量 -1,Javascript中所创建的自定义对象在任务时候都是可变的.可以从一个空对象开始,根据需要增加函数.对象字面量模式可以使我们在创建对象的时候向其添加函数.       <script> //定义空对象 var dog = {}; //对空对象添加方法 dog.name = "Liubo"; //对对象增加方法 dog.getName = function(){ return dog.name; }; //改变属性和方法 dog.getName = f

&lt;&lt;Javascript Patterns&gt;&gt;阅读笔记 -- 第2章 基本技巧(一)

第一次写这种东西, 有些生涩和蹩脚, 也是为了自己在表达或是总结方面有所提高, 同时为看过的东西留个痕迹, 以便日后查阅. 有错误或是不妥的地方, 还望各位指正, 谢谢! 第1章 简介 本章主要介绍了本书要讨论的内容, Javascript的一些基本概念, 面向对象, 原型, ECMASCript5, JSLine和console的相关内容. 不做过多阐述, 给出模式的定义 广义上: 模式是一个可以用来产生其他事物的模板或模型. 在软件开发中, 模式是指一个通用问题的解决方案. 书中主要讨论三种

&lt;&lt;Javascript Patterns&gt;&gt;阅读笔记 -- 第2章 基本技巧(二)

关于for-in循环 循环数据时, 强烈不推荐使用for-in循环.因为当Array对象被扩展后, 再用for-in循环遍历数据会导致逻辑上的错误, 举例说明: var arr = ['a', 'b', 'c']; // 下标遍历 for(var i=0, len=arr.length; i<len; i++) { console.info(typeof i); // number console.info(i); } // for-in遍历 for(var i in arr) { consol

C++PRIMER 阅读笔记 第三章

本章主要介绍 string vector 和 bitset, 不能贪多,现在本文主要介绍 string 与 vector 头文件中最好不要使用namespace std, 因为头文件会直接被预处理器放置到C中 std::string 的构造方式: string s1; string s2(s1); string s3("value");string s4(n,'c');           第三种构造方式可有"\0"? cout 与 cin 可以直接操作string

人月神话阅读笔记—第三章

人月神话阅读笔记-第三章 一个由一流人才组成的小型的精干的队伍比由一群平庸的程序员组成的大型团队更有效率,但是这里面有一个重要的问题:如何在有意义的进度安排内创建大型的系统. 优秀的程序员和较差的程序员之间生产效率的差距是巨大的,当一个10人的精干团队进行开发,和一个100个人的平庸程序员进行开发,前者的效率更高.但是对于效率和概念的完成性来说,最好由少数干练人员开发,而大型系统需要大量人员进行开发,但是这两者是有矛盾的,需要进行平衡. 在开发过程中,可以使用一种崭新的开发方案,类似于外科医生做

构建之法阅读笔记05-第六章

阅读笔记 第六章:敏捷流程 第六章敏捷流程主要介绍了什么是敏捷流程及其原则,还有什么时候可以选择敏捷的开发方法,什么时候选择其他方法. 敏捷的流程是指一系列价值观和方法论的集合.介绍了一些敏捷开发原则,比如,经常发布可用的软件,业务人员和开发人员在项目开发过程中应该每天共同工作,面对面的交流始终是最有效的沟通方式,不断关注技术和设计,保持简明,团队要学会自我管理,时时总结如何提高团队效率,并付诸行动. 敏捷流程的方法论---Scrum方法论.首先第一步需要找出完成产品需要做的事情,然后决定当前的

构建之法阅读笔记08-第十一章

阅读笔记 第十一章:软件设计与实现 在第十一章的软件设计与实现方面,介绍了一些关于典型的开发流程和开发阶段的一些管理方法. 在拿到设计文档之后,还需要做一些其他事情,比如估计任务所需要的时间,写一些原型代码,看看效果:做代码的自我复审,进行重构:写单元测试等等.最后还要把修改集集成到代码库中. 开发人员有一个标准的工作流程:进行功能需求分析,复审设计文档,详细设计,实现设计来编写代码,同伴复审,源代码的合并.构建等等,其中的每一步都有可能出现bug,要随时发现并且修改bug,最后是测试完成,发布

人月神话阅读笔记—第四章

人月神话阅读笔记-第四章 ------2016.6.14 概念的完整性是很重要的,为了反应一系列连贯的设计思路,可以省略一些不规则的特性和改进,不提倡独立和无法整合的系统,最需要的是在整体概念上的完整性要求. 获得概念的完整性时,会出现一种情况,编程系统使计算机更加好用,但是功能比较多的时候,软件外部描述就会比系统本身大很多:但是功能太少,不能满足需求,但是都需要满足概念上的完整性. 在进行概念的完整性时,产品设计需要由一个人或者少数几个人来实现,但是对于大型的系统,需要将设计方法.体系结构的工

字面量和构造函数

字面量和构造函数 JavaScript中的字面量模式更加简洁.有表现力,而且在定义对象时不容易出错.本章将会讨论字面量,包括对象.数组和正则表达式字面量,以及为什么字面量要比等价的内置构造函数(如Object().Array()等)要更好.本章还会介绍JSON格式,JSON是使用数组和对象字面量的形式定义的一种数据交换格式.本章还会讨论自定义构造函数,包括如何强制使用new以确保构造函数正确执行. 为了方便使用字面量而不是构造函数,本章还会补充一些知识,比如内置包装构造函数Number().St