zoukankan      html  css  js  c++  java
  • <<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]';
        }
    }
    ------------------
    要比昨天的自己更强
  • 相关阅读:
    JS数组常用方法参考---5、sort方法
    JS数组常用方法---1、课程介绍
    JS数组常用方法参考---4、unshift方法
    JS数组常用方法参考---3、队列对应的方法
    ES6课程---12、面向对象
    legend3---30、不同类型的网站打包方案
    数据库Sharding的基本思想和切分策略
    用sharding技术来扩展你的数据库(一)sharding 介绍
    什么是Scale Up和Scale Out?
    淘宝网采用什么技术架构来实现网站高负载的
  • 原文地址:https://www.cnblogs.com/lzj0616/p/4421012.html
Copyright © 2011-2022 走看看