一、创建对象的方式
-
1、直接创建(常用)
let obj = { name: '哈哈', gender: '男' } 复制代码
-
2、使用实例化对象的方式创建(比较少用)
function Foo() { // } let foo = new Foo() 复制代码
-
3、内置对象的实例
let x1 = new Object(); // A new Object object let x2 = new String(); // A new String object let x3 = new Number(); // A new Number object let x4 = new Boolean(); // A new Boolean object let x5 = new Array(); // A new Array object let x6 = new RegExp(); // A new RegExp object let x7 = new Function(); // A new Function object let x8 = new Date(); // A new Date object 复制代码
-
4、使用工厂方式创建(很少用)
function CreatePerson(name, age, sex) { var obj = new Object(); obj.name = name; obj.age = age; obj.sex = sex; obj.sayName = function () { return this.name; } return obj; } let p1 = new CreatePerson('哈哈', 20, '男'); 复制代码
二、一些基本的属性或者方法
-
1、每一个对象都有链接着原型对象的隐藏属性
__proto__
var obj = {}; obj.__proto__ === Object.prototype; //true 复制代码
-
2、判断一个对象是否包含一个属性
const obj2 = {gender: '男'}; console.log('gender' in obj2); console.log('name' in obj2); // 也可以使用hasOwnProperty console.log(obj2.hasOwnProperty('gender')); 复制代码
-
3、判断一个对象是否为空
const obj2 = {gender: '男'}; console.log(Object.keys(obj2)); console.log(Object.values(obj2)); 复制代码
-
4、删除一个属性
const obj2 = {gender: '男', age: 20, name: '张三'}; delete obj2.gender; console.log(obj2); // 也可以使用解析赋值的方式 const {name, ...obj1} = obj2; console.log(obj1); 复制代码
-
4、
Object.assign()
的使用- 1.对象的合并
- 2.对象的浅拷贝
- 3.给对象新增属性/方法
- 4.克隆对象(非深拷贝)
-
5、判断是否为对象
Object.prototype.toString.call(data).slice(8, -1) 复制代码
三、关于对象中几个重要词的理解
-
1、
constructor
查找该对象是由什么创建出来的let obj = {}; let reg = new RegExp(); let arry = new Array(); let str = new String(); let date = new Date(); console.log(obj.constructor); console.log(reg.constructor); console.log(arry.constructor); console.log(str.constructor); console.log(date.constructor); // 继续往上面找 console.log(Date.constructor); console.log(Function.constructor); 复制代码
-
2、
instanceof
判断构造函数是否在对象实例的原型链上Person.prototype.dance = function () { return 'dance function'; } // 定义一个子类 function Foo() { } Foo.prototype = new Person(); let foo = new Foo(); /** * 修改Foo原型的constructor * 关于defineProperty几个参数的介绍 * 第一个参数:属性所在的对象,第二个参数:属性的名字,一个描素符对象 */ Object.defineProperty(Foo.prototype, 'constructor', { writable: false, enumerable: false, value: Foo, }); let foo1 = new Foo(); console.log(foo1 instanceof Foo); console.log(foo1 instanceof Person); console.log(foo1 instanceof Object); 复制代码
-
3、
hasOwnProperty()
判断一个对象是否拥有该属性var obj = {name: '哈哈', gender: '男'}; obj.hasOwnProperty('name'); 复制代码
-
4、
setPrototypeOf()
修改对象的原型function Foo() { }; const foo = new Foo(); // 每一个对象都有constructor let bar = {}; console.log(bar.constructor); // 修改bar的原型 Object.setPrototypeOf(bar, foo); console.log(bar.constructor); // [Function: Foo] 复制代码
四、配置对象的属性
-
1、
configurable
: 如果为true表示可以修改与删除属性,如果为false
就不能修改与删除 -
2、
enumerable
: 如果为true表示为可枚举的可以使用for..in
-
3、
value
:指定属性的值 -
4、
writable
:如果为true
表示可以通过赋值语句修改对象属性 -
5、
get
定义gettter
函数 -
6、
set
定义setter
函数 -
7、测试案例
let obj1 = {}; obj1.name = '哈哈'; obj1.gender = '男'; // 定义第三个属性 Object.defineProperty(obj1, 'address', { configurable: false, enumerable: true, value: '深圳', writable: false, }); console.log(JSON.stringify(obj1)); for (let key in obj1) { console.log(`${key}===${obj1[key]}`); } 复制代码
五、对象的一些扩展
-
1、对象的私有属性
function Foo() { let name; // 定义一个set方法赋值 this.setName = (newVal) => name = newVal; // 定义一个get方法取值 this.getName = () => name; } let foo = new Foo(); foo.setName('哈哈'); console.log(foo.getName()); 复制代码
-
2、对象的
set
和get
方法// 在对象中get与set只是在属性前面加上了一个关键词,但是依然是属性的方式调用 const obj1 = { name: '哈哈', get getName() { console.log('get方法'); return this.name; }, set setName(newVal) { this.name = newVal; } }; console.log(obj1.getName); // obj1.setName = '张三'; // console.log(obj1.getName); console.log(obj1.name); 复制代码
-
3、使用
defineProperty
定义私有属性function Foo() { let _age = 0; // 扩展一个属性 Object.defineProperty(this, 'age', { get() { return _age; }, set(newVal) { _age = newVal; } }) } let foo = new Foo(); console.log(foo.age); foo.age = 10; console.log(foo.age); 复制代码
-
4、使用
set
和get
进行数据的校验function Foo() { let _age = 0; Object.defineProperty(this, 'age', { get() { return _age; }, set(newVal) { if (/\d+/.test(newVal)) { _age = newVal; } else { throw new TypeError('必须是数字'); } } }) } try { let foo = new Foo(); console.log(foo.age); foo.age = 10; console.log(foo.age); foo.age = '哈哈'; } catch (e) { console.log(e); } 复制代码
六、关于原型的理解
-
1、关于使用
new
关键词创建对象所发生的事情- 创建一个新对象
- 将构造函数的作用域赋值给新对象(this指向新对象)
- 执行构造函数的代码
- 返回新的对象
-
2、为什么要使用构造函数的原型
在使用构造函数创建对象的时候,每
new
一次就会创建一个对象,不同的实例的同名函数是不相等的,因此创建很多重复的代码(每次new一个构造函数,上面的构造函数就会执行一次,就会在内存中开辟一块空间,指向新的堆对象,这样内存消耗比较大),我们希望代码尽可能的复用,就需要原型// 普通的创建一个构造函数 function Animal(name, age) { this.name = name; this.age = age; this.print = function() { console.log(`${this.name}====${this.age}`); } } // 使用原型 function Animal(name, age) { this.name = name; this.age = age; } Animal.prototype.print = function() { console.log(`${this.name}====${this.age}`); } 复制代码
-
3、所有的对象都有一个
constructor
指向原型 -
4、构造函数都有
prototype
指向原型
七、深入理解类的继承(ES6
前的版本)
在面向对象开发中继承的概念是,新对象复用旧对象上的属性和方法(有点类似拷贝
Object.assign)
,类似生活中子继承父的财产及工具的概念
-
1、一个构造函数的原型指定另外一个构造函数
function Person() { } // 定义原型 Person.prototype.dance = function () { return 'dance function'; }; // 定义一个子类 function Foo() { } Foo.prototype = Person.prototype; // 总结:采用这种方式来创建类的继承,只是地址指向(一个修改了,另外一个也会随之修改) 复制代码
-
2、一个构造函数的原型指定另外一个函数的实例对象
function Person() { } // 定义原型 Person.prototype.dance = function () { return 'dance function'; }; // 定义一个子类 function Foo() { } // Foo构造函数的原型指向Person的实例对象 Foo.prototype = new Person(); let foo = new Foo(); console.log(foo.dance()); // 这样继承的方式会造成Foo的原型丢失,直接指定了Person console.log(foo.constructor); console.log(foo instanceof Foo); // 总结:采用这种方式实现继承:造成Foo的原型丢失,直接指定了Person 复制代码
-
3、修正方式二中
constructor
的指向function Person() { } Person.prototype.dance = function () { return 'dance function'; } // 定义一个子类 function Foo() { } Foo.prototype = new Person(); let foo = new Foo(); console.log(foo.constructor); // 修改Foo原型的constructor Object.defineProperty(Foo.prototype, 'constructor', { writable: false, enumerable: false, value: Foo, }); let foo1 = new Foo(); console.log(foo1.constructor); // 总结:修正`constructor`的指向 复制代码
八、采用class
的方式创建类
-
1、创建一个类
class Person { constructor(name, age) { this.name = name; this.age = age; } // 普通方法 say() { return 'say...'; } // 静态方法 static talk() { console.log(this); return '我是静态方法'; } } let p = new Person('哈哈', 20); console.log(Person.talk()); 复制代码
-
2、实现类的继承
class Animal { constructor(name) { this.name = name; } call() { return '在叫'; } } class Dog extends Animal { constructor(name, age) { super(name); this.age = age; } // 重写父类的方法 call() { return `${this.name}在叫`; } } let dog = new Dog('大黄狗', 3); console.log(dog.call()); 复制代码
-
3、使用
set
和get
方法class Person { constructor() { this.name = '哈哈'; } set setName(newVal) { this.name = newVal; } get getName() { return this.name; } } let p = new Person(); console.log(p.getName); p.setName = '张三'; console.log(p.getName); 复制代码
九、Proxy
的使用
Proxy
是ES6
中新增的对象,使用方式Proxy(目标对象,代理的对象)
主要有如下属性
-
get(target, propKey, receiver)
:拦截对象属性的读取,比如√proxy.foo和proxy['foo']√。 -
set(target, propKey, value, receiver)
:拦截对象属性的设置,比如proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。 -
has(target, propKey)
:拦截propKey in proxy
的操作,返回一个布尔值。 -
deleteProperty(target, propKey)
:拦截delete proxy[propKey]
的操作,返回一个布尔值。 -
ownKeys(target)
:拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in
循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。 -
getOwnPropertyDescriptor(target, propKey)
:拦截Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。 -
defineProperty(target, propKey, propDesc)
:拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。 -
preventExtensions(target):拦截
Object.preventExtensions(proxy)`,返回一个布尔值。 -
getPrototypeOf(target):拦截
Object.getPrototypeOf(proxy)`,返回一个对象。 -
isExtensible(target)
:拦截Object.isExtensible(proxy)
,返回一个布尔值。 -
setPrototypeOf(target, proto)
:拦截Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 -
apply(target, object, args)
:拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)
。 -
construct(target, args)
:拦截Proxy
实例作为构造函数调用的操作,比如new proxy(...args)
-
1、使用案例
let targetObj = {name: '哈哈'}; const proxy = new Proxy(targetObj, { set(target, key, val) { console.log(target); console.log(key); console.log(val); target[key] = val; }, get(target, key) { console.log(target); console.log(key); return key in target ? target[key] : '不存在这个key'; }, // 使用in的时候调用 has(target, key) { console.log(target, key) if (target.hasOwnProperty(key)) { return true; } else { return false; } }, deleteProperty(target, key) { if (target.hasOwnProperty(key)) { return true; } else { return false; } } }); 复制代码
-
2、代理方法
let targetObj = function () { return '目标函数'; }; let proxy = new Proxy(targetObj, { apply(target, ctx, args) { console.log(target()); console.log(ctx); console.log(args); return 'apply 函数'; } }); proxy(12, 20); 复制代码