axlroseart / drx

0 stars 0 forks source link

开发中比较实用的JS技巧类 #9

Open axlroseart opened 5 years ago

axlroseart commented 4 years ago
/*
* 版权申明及注释部分
*/
;(function() {
  ...
})();

;是保证导入的其它 js 脚本,使用工具压缩 js 文件时不出错。一个自执行匿名函数包裹,防止内部变量污染到外部命名空间。阅读过 jQuery 源码的人都知道,jQuery 的也是相同的结构,只是 jQuery 定义的匿名函数多了两个参数 window 和 undefined,然后调用的时候只传入 window,这样,window 可以在 jQuery 内部安全使用,而 undefined 也的确表示未定义(有些浏览器实现允许重定义 undefined)。

axlroseart commented 4 years ago

const user = { name: 'pete', age: 28 }

const 声明的对象 user 本身是不能被修改的,比如 user = { name: 'kk' } 但是对象的属性可以修改,比如 user.name = 'kk'

如何设置对象属性也无法被修改: 利用Object.defineProperty

Object.defineProperty(user, 'name', { value: 'pete' })

因为此方法默认对象属性的标志(writable 、enumerable、configurable)都为false writable: 是否只读 enumerable: 是否可枚举 configurable: 是否可配置

let descriptor = Object.getOwnPropertyDescriptor(user, 'name');

alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
  "value": "pete",
  "writable": false,
  "enumerable": false,
  "configurable": false
}
 */
axlroseart commented 4 years ago

属性的 getter 和 setter

属性可以要么是访问器,要么是数据属性,而不能两者都是。 如果我们试图在同一个描述符中提供 get 和 value,则会出现错误:

// Error: Invalid property descriptor.
Object.defineProperty({}, 'prop', {
  get() {
    return 1
  },

  value: 2
});
axlroseart commented 4 years ago

Getter/setter 可以用作“真实”属性值的包装器,以便对它们进行更多的控制。

例如,如果我们想禁止为 user 设置太短的名称,我们可以将 name 存储在一个特殊的 _name 属性中。并在 setter 中过滤赋值操作:

let user = {
  get name() {
    return this._name;
  },

  set name(value) {
    if (value.length < 4) {
      alert("Name is too short, need at least 4 characters");
      return;
    }
    this._name = value;
  }
};

user.name = "Pete";
alert(user.name); // Pete

user.name = ""; // Name is too short...
axlroseart commented 4 years ago

getter 和 setter 背后的伟大设计思想之一 —— 它们允许控制“正常”数据属性并随时调整它。

例如,我们开始使用数据属性 name 和 age 来实现用户对象:

function User(name, age) {
  this.name = name;
  this.age = age;
}

let john = new User("John", 25);

alert( john.age ); // 25 …但迟早,情况可能会发生变化。我们可能决定存储 birthday,而不是 age,因为它更加精确和方便:

function User(name, birthday) {
  this.name = name;
  this.birthday = birthday;
}

let john = new User("John", new Date(1992, 6, 1));

现在如何处理仍使用 age 属性的旧代码?

我们可以尝试找到所有这些地方并修复它们,但这需要时间,而且如果该代码是由其他人编写的,则很难做到。另外,age 放在 user 中也是一件好事,对吧?在某些地方,这正是我们想要的。

为 age 添加 getter 可缓解问题:

function User(name, birthday) {
  this.name = name;
  this.birthday = birthday;

  // age 是由当前日期和生日计算出来的
  Object.defineProperty(this, "age", {
    get() {
      let todayYear = new Date().getFullYear();
      return todayYear - this.birthday.getFullYear();
    }
  });
}

let john = new User("John", new Date(1992, 6, 1));

alert( john.birthday ); // birthday 是可访问的
alert( john.age );      // ...age 也是可访问的
axlroseart commented 4 years ago

UMD模块会检查是否存在模块加载器环境。 这是非常形容观察到的模块,它们会像下面这样:

(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define(["libName"], factory);
    } else if (typeof module === "object" && module.exports) {
        module.exports = factory(require("libName"));
    } else {
        root.returnExports = factory(root.libName);
    }
}(this, function (b) {})

如果你在库的源码里看到了typeof define,typeof window,或typeof module这样的测试,尤其是在文件的顶端,那么它几乎就是一个UMD库。