简介
对象除了可以保持自有的属性,还可以从一个称为原型的对象继承属性
属性包括名字和值。属性名可以是包含空字符串在内的任意字符串,但对象中不能存在两个同名的属性
原型和原型链参考:Javascript之原型和原型链
对象继承参考:Javascript之对象继承
创建对象
可以使用对象字面量
、new 关键字
和 ECMAScript 5
中的 Object.create()
函数来创建对象
// 对象字面量创建对象
// 推荐写法
var person = {
name : "stone",
age : 28
};
// 也可以写成
var person = {};
person.name = "stone";
person.age = 28;
// new 关键字创建对象
var person = new Object();
person.name = "stone";
person.age = 28;
// Object.create() 函数创建对象
var person = Object.create(Object.prototype);
person.name = "stone";
person.age = 28;
var obj1 = Object.create(null);
console.log(obj1); // {}
使用
new
实例化对象会经历以下4
个步骤
- 创建一个新对象;
- 将构造函数的作用域赋给新对象(因此
this
就指向了这个新对象);- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象:判断构造函数返回值是否为对象,如果为对象就使用构造函数返回的值,否则使用 obj,这样就实现了忽略构造函数返回的原始值。
模拟new
和Object.create
方法参考:手写各种原生方法
属性
// 取值
// 推荐写法
console.log(person.name); // "stone"
console.log(person.age); // "28"
// 也可以写成
console.log(person["name"]); // stone
console.log(person["age"]); // 28
// 赋值
// 推荐写法
person.name = "sophie"; // 赋值
person.age = 30; // 赋值
person.weight = 38; // 创建
// 也可以写成
person["name"] = "sophie"; // 赋值
person["age"] = 30; // 赋值
person["weight"] = 38; // 创建
方法
Object.getPrototypeOf(obj)
:获取对象构造函数的原型对象Object.setPrototypeOf(obj, proto)
:设置对象的原型对象Object.isExtensible(obj)
:对象是否可扩展(是否可以新增属性)Object.seal(obj)
:冻结属性,不可以新增和删除,但可以修改现有的属性Object.freeze(obj)
:冻结属性,不可以新增、删除和修改;不能修改该对象已有属性的可枚举性、可配置性、可写性;该对象的原型也不能被修改Object.getOwnPropertyNames(obj)
:获取对象自有属性的属性名组成的数组Object.getOwnPropertySymbols(obj)
:返回一个给定对象自身的所有Symbol
属性的数组Object.getOwnPropertyDescriptor(obj, key)
:返回指定对象上一个自有属性对应的属性描述符Object.getOwnPropertyDescriptors(obj)
:获取一个对象的所有自身属性的描述符Object.preventExtensions(obj)
:禁止扩展对象Object.defineProperty(obj, key, { get() {}, set() {} , ...})
:拦截对象操作Object.defineProperties(obj, {})
:批量设置对象属性obj.hasOwnProperty(key)
:是否是对象自身属性key in obj
:对象自身或者原型链中是否有某个属性delete obj.a
:删除对象属性for (let k in obj) {}
:枚举Object.keys(obj)
:对象属性的属性名组成的数组
delete
只是断开属性和宿主对象的联系,并没有真正的删除它
delete
运算符只能删除自有属性,不能删除继承属性
for...in
循环主要是为了遍历对象而生,不适用于遍历数组
for...of
循环可以用来遍历数组、类数组对象,字符串、Set
、Map
以及 Generator
对象
- 检测属性可以通过
in 运算符
、hasOwnPreperty()
和propertyIsEnumerable()
// in:若对象的自有属性或继承属性中包含这个属性则返回 true
var o = { x: 1 }
console.log("x" in o); // true,x是o的属性
console.log("y" in o); // false,y不是o的属性
console.log("toString" in o); // true,toString是继承属性
// hasOwnProperty():对象的自有属性
var o = { x: 1 }
console.log(o.hasOwnProperty("x")); // true,x是o的自有属性
console.log(o.hasOwnProperty("y")); // false,y不是o的属性
console.log(o.hasOwnProperty("toString")); // false,toString是继承属性
// propertyIsEnumerable(): 对象的自有属性且这个属性的可枚举性
var o = Object.create({ y: 2 });
o.x = 1;
o.propertyIsEnumerable("x"); // true:,x是o的自有属性,可枚举
o.propertyIsEnumerable("y"); // false,y是继承属性
Object.prototype.propertyIsEnumerable("toString"); // false,不可枚举
// !== 判断一个属性是否是 undefined(如果属性被显式的赋值成undefined,这种方法就不准了,需要用 in 检测)
var o = { x: 1 }
console.log(o.x !== undefined); // true,x是o的属性
console.log(o.y !== undefined); // false,y不是o的属性
console.log(o.toString !== undefined); // true,toString是继承属性
getter
和setter
var o = {
// 普通的数据属性
data_prop: value,
// 存取器属性都是成对定义的函数
get accessor_prop() { /*这里是函数体 */ },
set accessor_prop(value) { /* 这里是函数体*/ }
};
关卡
请实现下面用来枚举属性的对象工具函数:
/*
* 把 p 中的可枚举属性复制到 o 中,并返回 o
* 如果 o 和 p 中含有同名属性,则覆盖 o 中的属性
*/
function extend(o, p) {
for (prop in p) { // 遍历 p 中的所有属性
o[prop] = p[prop]; // 将属性添加至 o 中
}
return o;
}
/*
* 将 p 中的可枚举属性复制至 o 中,并返回 o
* 如果 o 和 p 中有同名的属性,o 中的属性将不受影响
*/
function merge(o, p) {
for (prop in p) { // 遍历 p 中的所有属性
if (o.hasOwnProperty[prop]) continue; // 过滤掉已经在 o 中存在的属性
o[prop] = p[prop]; // 将属性添加至 o 中
}
return o;
}
/*
* 如果 o 中的属性在 p 中没有同名属性,则从 o 中删除这个属性
* 返回 o
*/
function restrict(o, p) {
for (prop in o) { // 遍历 o 中的所有属性
if (! (prop in p)) delete o[prop]; // 如果在 p 中不存在,则删除之
}
return o;
}
/*
* 如果 o 中的属性在 p 中存在同名属性,则从 o 中删除这个属性
* 返回 o
*/
function subtract(o, p) {
for (prop in p) { // 遍历 p 中的所有属性
delete o[prop]; // 从 o 中删除(删除一个不存在的属性不会报错)
}
return o;
}
/*
* 返回一个新对象,这个对象同时拥有 o 的属性和 p 的属性
* 如果 o 和 p 中有重名属性,使用 p 中的属性值
*/
function union(o, p) {
return extend(extend({},o), p);
}
/*
* 返回一个新对象,这个对象拥有同时在 o 和 p 中出现的属性
* 很像求 o 和 p 的交集,但 p 中属性的值被忽略
*/
function intersection(o, p) {
return restrict(extend({},o), p);
}
/*
* 返回一个数组,这个数组包含的是 o 中可枚举的自有属性的名字
*/
function keys(o) {
if (typeof o !== "object") throw TypeError(); // 参数必须是对象
var result = []; // 将要返回的数组
for (var prop in o) { // 遍历所有可枚举的属性
if (o.hasOwnProperty(prop)) // 判断是否是自有属性
result.push(prop); // 将属性名添加至数组中
}
return result; // 返回这个数组
}
发表评论