zoukankan      html  css  js  c++  java
  • 《JavaScript模式》第3章 字面量和构造函数

    @by Ruth92(转载请注明出处)

    第3章:字面量和构造函数

    一、创建对象的三种方式

    // 对象字面量
    var car = {goes: "far"};
    
    // 内置构造函数(反模式)
    var car = new Object();
    car.goes = "far";
    
    // 自定义构造函数
    var adam = new Person("Adam");
    adam.say();
    

    ☛ 对象字面量的优点:

    • 按需创建对象,在程序生命周期内的任何时候都可以修改;
    • 输入更短的字符;
    • 强调该对象仅是一个可变哈希映射,而不是从对象中提取的属性和方法;
    • 没有作用域解析

    二、构造函数

    ☛ 构造函数的特征(使用缺点):

    • 依赖传递的参数的值,该构造函数可能会委派另一个内置构造函数来创建对象,并且返回了一个并非期望的不同对象

    • 当传递给构造函数的值是动态的,并且直到运行时才能确定其类型

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

    ✔ JavaScript 中没有类的概念,但是它却支持极大的灵活性,因为不必预先知道对象的一切细节,也不需要类“蓝图”。

    // 构造函数的定义
    var Person = function(name) {
      this.name = name;
      this.say = function() {
        return "I am " + this.name;
      };
    };
    

    ✔ 当以 new 操作符调用构造函数时,函数内部将会发生以下情况:

    • 创建一个空对象并且 this 变量引用了该对象,同时还继承了该函数的原型。
    • 属性和方法被加入到 this 引用的对象中。
    • 新创建的对象由 this 所引用,并且最后隐式地返回 this(如果没有显式地返回其它对象)。

    ✔ 当 new 操作符调用构造函数时,相当于在后台发生了如下事情:

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

    ✔ “空”对象实际上并不空,它已经从 Person 的原型中继承了许多成员。因此,更像下面的语句:

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

    构造函数的返回值:

    • 当用 new 操作符创建对象时,构造函数总是返回一个对象;
    • 默认返回 this 所引用的对象,也可以返回任意其他对象;
    • 如果在构造函数中并不向 this 添加任何属性,将返回“空”对象(这里的“空”,指的是除了从构造函数的原型中所继承的成员以外);
    • 如果试图返回并非对象的值,函数会忽略该值,并返回 this 所引用的对象。

    如果在调用构造函数时,忘记使用 new 操作符,会导致构造函数中的 this 指向全局对象。

    ☊ 自调用构造函数——解决忘记使用 new 的问题,同时还能使实例继承原型

    // 自调用构造函数
    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);   // "true";
    console.log(second.wantAnother);   // "true";
    

    另一种检测实例对象的方法:

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

    三、数组构造函数的特殊性

    /**
     * 向 Array() 构造函数传递单个数字时,会设定数组的长度
     */
    // 具有一个元素的数组
    var a = [3];
    console.log(a.length);	// 1
    console.log(a[0]);	// 3
    
    // 具有三个元素的数组
    var a = new Array(3);
    console.log(a.length);	// 3
    console.log(typeof a[0]);	// 'undefined'
    
    /**
     * 向 new Array() 传递浮点数,会产生范围错误
     */
    // 使用数组字面量
    var a = [3.14];
    console.log(a[0]);	// 3.14
    
    var a = new Array(3.14);	// RangeError: invalid array length
    console.log(typeof a);	// 'undefined'
    
    /**
     * Array() 构造函数的灵巧用法:重复字符串
     */
    var white = new Array(256).join(' ');	// 返回具有255个空白字符串的字符串
    

    检测是否为数组:

    Array.isArray()

    function polyfillArray(arr) {
    
      if (typeof Array.isArray === 'undefined') {
        Array.isArray = function(arg) {
          return Object.prototype.toString.call(arg) === "[object Array]";
        };
      }
    
      return Array.isArray(arr);
    }
    
    polyfillArray([]);  // 'true'
    
    polyfillArray({
      length: 1,
      "0": 1,
      slice: function () {}
    }); // false
    

    四、JSON

    JSON:代表 JavaScript 对象表示(JavaScript Object Notation)以及数据传输格式。

    它是一种轻量级数据交换格式,只是一个数组和对象字面量表示方法的组合:

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

    JSON 和文字对象之间的唯一语法差异:

    • 在 JSON 中,属性名称需要包装在引号中才能成为合法的 JSON;
    • 在对象字面量中,仅当属性名称不是有效标识符时才会需要引号,如字符中间有空格 { "first name": "Dave" };
    • 在 JSON 中,不能使用函数或正则表达式籽棉量。

    使用 JSON

    // JSON.parse();
    var jstr = '{"mykey": "my value"};
    var data = JSON.parse(jstr);
    console.log(data.mykey);	// 'my value'
    
    // JSON.stringify()
    var dog = {
    	name: 'Fido',
    	dob: new Date(),
    	legs: [1, 2, 3, 4]
    };
    
    var jsonstr = JSON.stringify(dog);
    console.log(jsonstr);	// "{"name":"Fido","dob":"2016-09-20T10:26:24.904Z","legs":[1,2,3,4]}"
    

    五、基本值类型包装器

    五个基本的值类型:NumberStringBooleannullundefined。除了 nullundefined 以外,其他三个都具有所谓的基本包装对象。

    可以使用内置构造函数 Number()String()Boolean() 创建包装对象。

    包装对象包含了一些有用的属性和方法。但是这些方法在基本值类型上也能够起作用。只要调用这些方法,基本值类型就可以在后台被临时转换为一个对象,并且表现得犹如一个对象。

    // 一个基本数值
    var n = 100;
    console.log(typeof n);  // 'number'
    
    // 一个数值 Number 对象
    var nobj = new Number(100);
    console.log(typeof nobj);   // 'object'
    
    // 用来作为对象的基本字符串
    var s = 'hello';
    console.log(s.toUpperCase());   // 'HELLO'
    
    // 值本身可以作为一个对象
    "monkey".slice(3, 6);   // "key"
    
    // 与数值的方法相同
    (22 / 7).toPrecision(3);    // '3.14'
    

    使用包装对象的场景

    有扩充值以及持久保存状态的需要。因为基本值类型并不是对象,它们不可能扩充值。

    六、错误对象

    • JavaScript 中有一些内置错误构造函数,如 Error()SyntaxError()TypeError(),这些错误构造函数都带有 throw 语句。通过这些错误构造函数创建的错误对象具有 namemessage 属性。

    • throw 适用于任何对象,并不一定是由某个错误构造函数所创建的对象,因此可以选择抛出自己的对象。这种错误对象也可以有属性 namemessage,以及任意希望传递给 catch 语句来处理的其他类型的信息。

        try {
            // 发生以外的事情,抛出一个错误
            throw {
                name: "MyErrorType",    // 自定义错误类型
                message: 'oops',
                extra: 'This was rather embarrassing',
                remedy: genericErrorHandler // 指定应该处理该错误的函数
            };
        } catch (e) {
            // 通知用户
            alert(e.message);   // 输出 'oops'
        
            // 优美的处理错误
            e.remedy(); // 调用函数 genericErrorHandler
        }
      
    • 错误构造函数以函数的形式调用(不带 new)时,其表现行为与构造函数(带 new)相同,并且返回同一个错误对象。


  • 相关阅读:
    浅谈异或相关性质
    重谈树状数组
    洛谷 U141397 !
    谈谈Sleep和wait的区别
    请描述线程的生命周期
    一个普通main方法的执行,是单线程模式还是多线程模式?为什么?
    创建线程的方式
    一道关于try catch finally返回值的问题
    throw跟throws的区别
    罗列常见的5个非运行时异常
  • 原文地址:https://www.cnblogs.com/Ruth92/p/5928812.html
Copyright © 2011-2022 走看看