Skip to content

对象

对象转换

Symbol.toPrimitive

内部自定义Symbol.toPrimitive方法用来处理所有的转换场景

javascript
let hd = {
  num: 1,
  [Symbol.toPrimitive]: function() {
    return this.num;
  }
};
console.log(hd + 3); //4

valueOf/toString

可以自定义valueOftoString 方法用来转换,转换并不限制返回类型。

javascript
let hd = {
  name: "love",
  num: 1,
  valueOf: function() {
    console.log("valueOf");
    return this.num;
  },
  toString: function() {
    console.log("toString");
    return this.name;
  }
};
console.log(hd + 3); //valueOf 4
console.log(`${hd} you`); //toString love you

默认值

为变量设置默认值

javascript
let [name, site = 'love'] = ['you']
console.log(site) //love

属性管理

检测属性

hasOwnProperty检测对象自身是否包含指定的属性,不检测原型链上继承的属性。

javascript
let obj = { name: 'love'};
console.log(obj.hasOwnProperty('name')); //true

使用 in 可以在原型对象上检测

javascript
let arr = ["love"];
console.log(arr);
console.log(arr.hasOwnProperty("length")); //true
console.log(arr.hasOwnProperty("concat")); //false
console.log("concat" in arr); //true

获取属性名

使用 Object.getOwnPropertyNames 可以获取对象的属性名集合

javascript
let hd = { name: 'love', year: 2010 }
const names = Object.getOwnPropertyNames(hd)
console.log(names)// ["name", "year"]

assign

使用 Object.assign 静态方法从一个或多个对象复制属性

javascript
"use strict";
let hd = { a: 1, b: 2 };
hd = Object.assign(hd, { f: 1 }, { m: 9 });
console.log(hd); //{a: 1, b: 2, f: 1, m: 9}

计算属性

对象属性可以通过表达式计算定义,这在动态设置属性或执行属性方法时很好用。

javascript
let id = 0;
const user = {
  [`id-${id++}`]: id,
  [`id-${id++}`]: id,
  [`id-${id++}`]: id
};
console.log(user);

for/in

使用for/in遍历对象属性

for/of

for/of用于遍历迭代对象,不能直接操作对象。但Object对象的keys/values/entries方法返回的是迭代对象。

工厂函数

javascript
function stu(name) {
  return {
    name,
    show() {
      console.log(this.name);
    }
  };
}
const lisi = stu("李四");
lisi.show();
const zhangsan = stu("zhangsan");
xj.show();

构造函数

和工厂函数相似构造函数也用于创建对象,它的上下文为新的对象实例。

  • 构造函数名每个单词首字母大写即Pascal 命名规范
  • this指当前创建的对象
  • 不需要返回this系统会自动完成
  • 需要使用new关键词生成对象
javascript
function Student(name) {
  this.name = name;
  this.show = function() {
    console.log(this.name);
  };
  //不需要返回,系统会自动返回
  // return this;
}
const lisi = new Student("李四");
lisi.show();
const zhangsan = new Student("zhangsan");
xj.show();

对象函数

JS中函数也是一个对象

javascript
function hd(name) {}

console.log(hd.toString());
console.log(hd.length);

函数是由系统内置的 Function 构造函数创建的

javascript
function hd(name) {}

console.log(hd.constructor);

下面是使用内置构造函数创建的函数

javascript
const User = new Function(`name`,`
  this.name = name;
  this.show = function() {
    return this.name;
  };
`
);

const lisi = new User("李四");
console.log(lisi.show());

属性特征

查看特征

使用 Object.getOwnPropertyDescriptor查看对象属性的描述。

javascript
"use strict";
const user = {
  name: "love",
  age: 18
};
let desc = Object.getOwnPropertyDescriptor(user, "name");
console.log(JSON.stringify(desc, null, 2));

使用 Object.getOwnPropertyDescriptors查看对象所有属性的描述

js
"use strict"
const user = {
    name: "love",
    age: 18
}
let desc = Object.getOwnPropertyDescriptors(user)
console.log(JSON.stringify(desc, null, 2));

属性包括以下四种特性

特性说明默认值
configurable能否使用 delete、能否修改属性特性、或能否修改访问器属性true
enumerable对象属性是否可通过 for-in 循环,或 Object.keys() 读取true
writable对象属性是否可修改true
value对象属性的默认值undefined

设置特征

使用Object.defineProperty 方法修改属性特性,通过下面的设置属性 name 将不能被遍历、删除、修改。

js
"use strict"
const user = {
    name: "love"
}
Object.defineProperty(user, "name", {
    value: "you",
    writable: false,
    enumerable: false,
    configurable: false
});

使用 Object.defineProperties 可以一次设置多个属性,具体参数和上面介绍的一样。

禁止添加

Object.preventExtensions 禁止向对象添加属性

javascript
"use strict";
const user = {
  name: "love"
};
Object.preventExtensions(user);
user.age = 18; //Error

Object.isExtensible 判断是否能向对象中添加属性

封闭对象

Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为 configurable: false

js
"use strict"
const user = {
    name: "love",
    age: 18
}

Object.seal(user)
console.log(JSON.stringify(Object.getOwnPropertyDescriptors(user), null, 2))

Object.seal(user)
console.log(Object.isSealed(user))
delete user.name //Error

Object.isSealed 如果对象是密封的则返回 true,属性都具有 configurable: false

冻结对象

Object.freeze 冻结对象后不允许添加、删除、修改属性,writable、configurable 都标记为false

Object.isFrozen()方法判断一个对象是否被冻结

属性访问器

getter 方法用于获得属性值,setter 方法用于设置属性,这是 JS 提供的存取器特性即使用函数来管理属性。

  • 用于避免错误的赋值
  • 需要动态监测值的改变
  • 属性只能在访问器和普通属性任选其一,不能共同存在

getter/setter

用户的年龄数据使用访问器监控控制

js
"use strict"
const user = {
    data: { name: '后盾人', age: null },
    set age(value) {
        if (typeof value != "number" || value > 100 || value < 10) {
            throw new Error("年龄格式错误")
        }
        this.data.age = value
    },
    get age() {
        return `年龄是: ${ this.data.age }`
    }
}
user.age = 99
console.log(user.age);

代理拦截

代理(拦截器)是对象的访问控制,setter/getter 是对单个对象属性的控制,而代理是对整个对象的控制。

  • 读写属性时代码更简洁
  • 对象的多个属性控制统一交给代理完成
  • 严格模式下 set 必须返回布尔值

代理函数

如果代理以函数方式执行时,会执行代理中定义 apply 方法。

  • 参数说明:函数,上下文对象,参数

下面使用 apply 计算函数执行时间

javascript
function factorial(num) {
  return num == 1 ? 1 : num * factorial(num - 1);
}
let proxy = new Proxy(factorial, {
  apply(func, obj, args) {
    console.time("run");
    func.apply(obj, args);
    console.timeEnd("run");
  }
});
proxy.apply(this, [1, 2, 3]);

Vue原理

html
<body>
    <form action="">
        <input type="text" v-model="title">
        <input type="text" v-model="title">

    </form>
    <div v-bind="title"></div>
</body>
<script>
    function View() {
        let proxy = new Proxy({}, {
            get(obj, property) {

            },
            set(obj, property, value) {
                document.querySelectorAll(`[v-model="${ property }"]`).forEach((item) => {
                    item.value = value
                })
                document.querySelectorAll(`[v-bind="${ property }"]`).forEach((item) => {
                    item.innerHTML = value
                })
            }
        })
        this.init = function () {
            const els = document.querySelectorAll("[v-model]")
            els.forEach(item => {
                item.addEventListener('keyup', function () {
                    proxy[this.getAttribute('v-model')] = this.value
                })
            })
        }
    }
    new View().init()
</script>