对象
对象转换
Symbol.toPrimitive
内部自定义Symbol.toPrimitive
方法用来处理所有的转换场景
let hd = {
num: 1,
[Symbol.toPrimitive]: function() {
return this.num;
}
};
console.log(hd + 3); //4
valueOf/toString
可以自定义valueOf
与 toString
方法用来转换,转换并不限制返回类型。
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
默认值
为变量设置默认值
let [name, site = 'love'] = ['you']
console.log(site) //love
属性管理
检测属性
hasOwnProperty
检测对象自身是否包含指定的属性,不检测原型链上继承的属性。
let obj = { name: 'love'};
console.log(obj.hasOwnProperty('name')); //true
使用 in
可以在原型对象上检测
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
可以获取对象的属性名集合
let hd = { name: 'love', year: 2010 }
const names = Object.getOwnPropertyNames(hd)
console.log(names)// ["name", "year"]
assign
使用 Object.assign
静态方法从一个或多个对象复制属性
"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}
计算属性
对象属性可以通过表达式计算定义,这在动态设置属性或执行属性方法时很好用。
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方法返回的是迭代对象。
工厂函数
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
关键词生成对象
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
中函数也是一个对象
function hd(name) {}
console.log(hd.toString());
console.log(hd.length);
函数是由系统内置的 Function
构造函数创建的
function hd(name) {}
console.log(hd.constructor);
下面是使用内置构造函数创建的函数
const User = new Function(`name`,`
this.name = name;
this.show = function() {
return this.name;
};
`
);
const lisi = new User("李四");
console.log(lisi.show());
属性特征
查看特征
使用 Object.getOwnPropertyDescriptor
查看对象属性的描述。
"use strict";
const user = {
name: "love",
age: 18
};
let desc = Object.getOwnPropertyDescriptor(user, "name");
console.log(JSON.stringify(desc, null, 2));
使用 Object.getOwnPropertyDescriptors
查看对象所有属性的描述
"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 将不能被遍历、删除、修改。
"use strict"
const user = {
name: "love"
}
Object.defineProperty(user, "name", {
value: "you",
writable: false,
enumerable: false,
configurable: false
});
使用 Object.defineProperties
可以一次设置多个属性,具体参数和上面介绍的一样。
禁止添加
Object.preventExtensions
禁止向对象添加属性
"use strict";
const user = {
name: "love"
};
Object.preventExtensions(user);
user.age = 18; //Error
Object.isExtensible
判断是否能向对象中添加属性
封闭对象
Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为
configurable: false
"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
用户的年龄数据使用访问器监控控制
"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
计算函数执行时间
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原理
<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>