js没有类的概念,js里万物皆是对象,对象是无序属性的集合,其属性可以包含基本值,对象或者函数
js对象从某种维度上可分为两种:普通对象和函数对象
普通对象: let o = {}; let arr = new Array();这类普通的对象。
函数对象: let f = function() {};一些原生对象如Object,Array,Function都是函数对象,其实就是可以new的对象。
-
原型对象
原型对象指的是每创建一个函数,都会为该函数创建一个prototype属性和一个原型对象,并将prototype属性指向该原型对象,该原型对象里默认有一个constructor属性,该属性指向函数本身。所有该函数创建的实例都有一个__proto__属性,也指向函数的原型对象。如下图:
通过
Object.create()创建的对象使用第一个参数作为原型
通过对象直接量的对象使用Object.prototype作为原型
通过new创建的对象使用构造函数的prototype属性作为原型
-
原型链
每个对象都可以有一个原型_proto_,这个原型还可以有它自己的原型,以此类推,形成一个原型链。查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去向原型对象的原型对象里去寻找...这个操作被委托在整个原型链上,这个就是我们说的原型链了。
请看下面这张经典的图:
查找对象属性
obj.hasOwnProperty(属性名):实例属性属性名 in obj:实例属性 + 原型属性
function User(name) {
this.name = name
}
User.prototype.hello = 'hello'
const obj = new User('cjz');
console.log(obj.hasOwnProperty('name'), 'name' in obj); // true,true
console.log(obj.hasOwnProperty('hello'), 'hello' in obj); // false,true
遍历对象属性
let key in obj:实例属性 + 原型属性 + 可枚举的属性Object.keys(obj):实例属性 + 可枚举的属性Object.getOwnPropertyNames(obj):实例属性
instanceof和isPropertyOf判断对象类型
function User(name) {
this.name = name
}
const obj = new User('cjz');
console.log(obj instanceof User, obj instanceof Object); // true, true
console.log(User.prototype.isPrototypeOf(obj), Object.prototype.isPrototypeOf(obj)); // true, true
new对象的操作发生了什么?
- 以构造函数的
prototype属性为原型,创建新对象; - 将该对象和调用参数传给构造函数,执行;
- 如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return的对象。
简单实现一个new方法:
// 构造器函数
let Parent = function (name, age) {
this.name = name;
this.age = age;
};
Parent.prototype.sayName = function () {
console.log(this.name);
};
//自己定义的new方法
let newMethod = function (Parent, ...rest) {
// 1.以构造器的prototype属性为原型,创建新对象;
let child = Object.create(Parent.prototype);
// 2.将this和调用参数传给构造器执行
let result = Parent.apply(child, rest);
// 3.如果构造器没有手动返回对象,则返回第一步的对象
return typeof result === 'object' ? result : child;
};
//创建实例,将构造函数Parent与形参作为参数传入
const child = newMethod(Parent, 'echo', 26);
child.sayName() //'echo';
//最后检验,与使用new的效果相同
child instanceof Parent//true
child.hasOwnProperty('name')//true
child.hasOwnProperty('age')//true
child.hasOwnProperty('sayName')//false