导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

作用

参数

特性

默认用 Object.defineProperty 定义的属性不可修改、不可枚举、不可删除

function defineProperty() {
  var _obj = {};

  // 定义单个属性
  Object.defineProperty(_obj, 'a', {
    value: 1
  }); // 返回 _obj, 但一般不直接赋值,return目标对象就好了

  // 同时定义多个属性
  Object.defineProperties(_obj, {
    b: {
      value: 2
    },
    c: {
      value: 3
    }
  });
  return _obj;
}

const obj = defineProperty();

obj.a = 10;
console.log(obj.a); // 1 // 属性值不可修改

for (const key in obj) {
  console.log(key + ': ' + obj[key]);
  // 属性也不可枚举
}

delete obj.a; // 不可被删除
console.log(obj); // { a: 1, b: 2, c: 3 }

writeable 可修改、enumerable 可枚举、configurable 可配置(一般用作可删除)

function defineProperty() {
  var _obj = {};

  Object.defineProperties(_obj, {
    a: {
      value: 1,
      writable: true, // 可修改
      enumerable: true, // 可枚举
      configurable: true, // 可操作的(一般指删除)
    },
    b: {
      value: 2
    }
  });
  return _obj;
}

const obj = defineProperty();

obj.a = 10;
obj.b = 5;

console.log(obj); // { a: 10, b: 2 }
// a被改了,b没有

for (const key in obj) {
  console.log(key + ': ' + obj[key]);
}
// 只打印 a: 10 ,不打印 b

delete obj.a; // 此时可删除a了
console.log(obj); // { b: 2 }

getter、setter

数据劫持

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <p>0</p>
  <script src="./text.js"></script>
</body>
</html>
function defineProperty() {
  var _obj = {};

  var a = 1;

  Object.defineProperties(_obj, {
    a: {
      get() {
        return '"a"\\'s value is ' + a + '.';
      },
      set(newVal) {
        console.log('The value "a" has been designed a new value "' + newVal + '".');
        var oP = document.querySelector('p');
        oP.innerText = newVal;
      }
    }
  });
  return _obj;
}

const obj = defineProperty();
console.log(obj.a);
obj.a = 233;

Untitled

function defineProperty() {
  var _obj = {};

  var a = 1;

  Object.defineProperties(_obj, {
    a: {
      get() {
        return a;
      },
      set(newVal) {
        a = newVal;
      }
    }
  });
  return _obj;
}

const obj = defineProperty();
console.log(obj.a);
obj.a = 233;
console.log(obj.a);

当给属性设置了 setter、getter 后,不允许设置 value 和 writeable

Object.defineProperties(_obj, {
  a: {
    // value: 1,
    // writable: true,
    get() {
      return a;
    },
    set(newVal) {
      a = newVal;
    }
  }
});

Untitled

通过 getter、setter 设置了的属性,在原对象中不可见,但默认可枚举、可删除

var obj = {
	name: 'Lance',
  age: 24
}

var _obj = {};
Object.keys(obj).forEach(key => {
  _obj[key] = obj[key];
	Object.defineProperty(obj, key, {
  	get() {
    	return _obj[key];
    },
    set(newVal) {
    	_obj[key] = newVal;
    },
  });
});

console.log(obj);
for (var key in obj) {
	console.log(obj[key]);
}
delete obj.name;
console.log(obj);

Untitled

var obj = {
	name: 'Lance',
  age: 24
}

var _obj = {};
Object.keys(obj).forEach(key => {
  _obj[key] = obj[key];
	Object.defineProperty(obj, key, {
    // value: 1, // 不可配置
    // writeable: false, 不可配置
  	get() {
    	return _obj[key];
    },
    set(newVal) {
    	_obj[key] = newVal;
    },
    enumerable: false, // 可配置
    configurable : false // 可配置
  });
});

console.log(obj);
for (var key in obj) {
	console.log(obj[key]);
}
delete obj.name;
console.log(obj);

Untitled

基本使用

var obj = {};
Object.defineProperty(obj, 'a', {
	value: 2,
  configurable: true,
  writable: true,
  enumerable: true
});
var obj = {};
Object.defineProperty(obj, 'a', {
	value: 2,
  configurable: true,
  writable: false, // 不可写入,但可用delete删除
  enumerable: true
});
obj.a = 3; // 写入失败 静默失败,严格模式报错
delete obj.a; // 可以删除
var obj = {};
Object.defineProperty(obj, 'a', {
	value: 2,
  configurable: false, // 禁止配置
  writable: true, // 允许读写
  enumerable: true
})

obj.a = 3; // 可更改

console.log(obj); // { a: 3 }
var obj = {};
Object.defineProperty(obj, 'a', {
	value: 2,
  configurable: false,
  writable: true,
  enumerable: true
})

obj.a = 3;
console.log(obj.a); // 3 更改成功
delete obj.a; //configurable: false 不可以删除
console.log(obj.a); // 3 删除失败

⭐️ 应用

监听数组

function DataArr() {
  var _val = null, // obj
      _arr = [];

  Object.defineProperty(this, 'val', {
    get() {
      return _val;
    },
    set(newVal) {
      _val = newVal;
      _arr.push({ val: _val });
      console.log(`A new value "${_val}" has been pushed to _arr`)
    }
  });

  this.getArr = function() {
    return _arr;
  }
}

var dataArr = new DataArr();
dataArr.val = '123';
dataArr.val = '234';
console.log(dataArr.getArr());

Untitled

计算器

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style type="text/css">
    .btn-group button.current {
      background-color: orange;
      color: #fff;
    }
  </style>
</head>
<body>
  <div class="J_calculator">
    <div class="result">0</div>
    <div class="input-group">
      <input type="text" value="0" class="f-input" />
      <input type="text" value="0" class="s-input" />
    </div>
    <div class="btn-group">
      <button data-field="plus" class="current">+</button>
      <button data-field="minus">-</button>
      <button data-field="mul">*</button>
      <button data-field="div">/</button>
    </div>
  </div>
  <script src="./index.js"></script>
</body>
</html>
class Compute {
  plus(a, b) {
    return a + b;
  }
  minus(a, b) {
    return a - b;
  }
  mul(a, b) {
    return a * b;
  }
  div(a, b) {
    return a / b;
  }
}

// 通过继承 Compute 获取计算方法
class Calculator extends Compute {
  constructor(doc) {
    super();
    // 获取容器
    const oCal = doc.getElementsByClassName('J_calculator')[0];
    // 获取两个input
    this.fInput = oCal.getElementsByTagName('input')[0];
    this.sInput = oCal.getElementsByTagName('input')[1];
    // 获取按钮
    this.oBtnGroup = oCal.getElementsByClassName('btn-group')[0];
    this.oBtnItems = this.oBtnGroup.getElementsByTagName('button');
    // 获取结果
    this.oResult = oCal.getElementsByClassName('result')[0];
    // 处理数据
    this.data = {
      // fNumber: xxx,
      // sNumber: xxx,
      // field: 'plus'
    };
    this.data = this.defineData();
    // field 高亮状态
    this.btnIdx = 0;
  }
  init() {
    this.bindEvent();
  }
  bindEvent() {
    this.oBtnGroup.addEventListener('click', this.onFieldBtnClick.bind(this), false);
    this.fInput.addEventListener('input', this.onNumberInput.bind(this), false);
    this.sInput.addEventListener('input', this.onNumberInput.bind(this), false);
  }
  defineData() {
    let _obj = {},
        fNumber = 0,
        sNumber = 0,
        field = 'plus';

    const _self = this;

    Object.defineProperties(_obj, {
      fNumber: {
        // get 返回值
        get() {
          console.log('"fNumber" is being got.');
          return fNumber;
        },
        // set监听值的改变,然后刷新视图
        set(newVal) {
          fNumber = newVal;
          _self.computeResult(fNumber, sNumber, field);
          console.log(`The value "fNumber" has been changed. [${fNumber}]`);
        }
      },
      sNumber: {
        get() {
          console.log('"sNumber" is being got.');
          return sNumber;
        },
        set(newVal) {
          sNumber = newVal;
          _self.computeResult(fNumber, sNumber, field);
          console.log(`The value "sNumber" has been changed. [${sNumber}]`);
        }
      },
      field: {
        get() {
          console.log('"field" is being got.');
          return field;
        },
        set(newVal) {
          field = newVal;
          _self.computeResult(fNumber, sNumber, field);
          console.log(`The value "field" has been changed. [${field}]`);
        }
      }
    });

    return _obj;
  }

  // 监听计算方式按钮
  onFieldBtnClick(ev) {
    const e = ev || window.event,
          tar = e.target || e.srcElement,
          tagName = tar.tagName.toLowerCase();

    tagName === 'button' && this.fieldUpdate(tar);
  }
  // 监听input变化
  onNumberInput(ev) {
    const e = ev || window.event,
          tar = e.target || e.srcElement,
          className = tar.className,
          val = Number(tar.value.replace(/\\s+/g, '')) || 0;

    switch (className) {
      case 'f-input':
        this.data.fNumber = val;
        break;
      case 's-input':
        this.data.sNumber = val;
      default:
        break;
    }
  }
  // 更新 field 以及样式
  fieldUpdate(target) {
    this.oBtnItems[this.btnIdx].className = '';
    this.btnIdx = [].indexOf.call(this.oBtnItems, target);
    target.className += ' current';
    this.data.field = target.getAttribute('data-field');
  }
  // 更新视图
  computeResult(fNumber, sNumber, field) {
    this.oResult.innerText = this[field](fNumber, sNumber);
  }
}

new Calculator(document).init();

if (a == 1 && a == 2 && a == 3)

如何让 if (a == 1 && a == 2 && a == 3) 成立

var a = {
  _a: 0,
  toString() {
    return ++this._a;
  }
}
if (a == 1 && a == 2 && a == 3) {
  console.log(1)
}

if (a === 1 && a === 2 && a === 3)

var _a = 0;
Object.defineProperty(window, 'a', {
  get() {
    return ++_a;
  }
});
if (a === 1 &&  a === 2 && a === 3) {
  console.log(1)
}

if (obj.a === 1 && obj.a === 2 && obj.a === 3)

var obj = {
  _a: 0,
  get a() {
    return ++this._a;
  },
  // set a() {

  // }
}
if (obj.a === 1 &&  obj.a === 2 && obj.a === 3) {
  console.log(1);
}

_ + _ + _ + ...

  1. _ + _ 为 'ab'
  2. _ + _ + _ 为 'abc'
  3. ...
  4. 一直到 'a...z' 26个字母为止
Object.defineProperty(window, '_', {
  get() {
    this.curCharCode = this.curCharCode || 'a'.charCodeAt(0); // 找到起始ascii位
    this.curChar = String.fromCharCode(this.curCharCode); // 赋值给要返回的值
    if (this.curCharCode >= 'a'.charCodeAt(0) + 26) return ''; // 一旦大于等于26 就返回空字符串
    this.curCharCode++; // 起始位自增
    return this.curChar;
  }
})

console.log(_ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _);

{ a: 1, b: 2, c: 3 } => { a: 3, b: 3, c: 5 }

var obj = {
	a: 1,
  b: 2,
  c: 3
}

// 循环 +1 后
for (var key in obj) {
	obj[key] += 1;
}

// 变成
console.log(obj); // { a: 3, b: 3, c: 5 }

实现:

var obj = {
	a: 1,
  b: 2,
  c: 3
}

var _obj = {
	a: 1,
  b: 2,
  c: 3
}

for (var k in _obj) {
	Object.defineProperty(obj, k, {
  	enumerable: true,
    writable: k === 'b' ? false : true,
    value: ++ _obj[k]
  });
}

for (var key in obj) {
	obj[key] += 1;
}

// 变成
console.log(obj);