创建对象的几种方法
//第一种:字面量,这种方式创建的对象,对象的原型链默认指向Object
var o1 = { name: 'happychen' };
//字面量方式创建的对象,对象的原型链默认指向Object
var o2 = new Object({ name: 'happychen' });
//第二种:构造函数创建对象
var M = function (name) {
this.name = name;
}
var o3 = new M('happychen');
//第三种
var P = { name: 'happychen' };
var o4 = Object.create(P);
效果:
原型(对象),构造函数,实例,原型链之间的关系:
任何一个函数只要被new使用了那这个函数就是个构造函数。当然,构造函数也是一个“函数”,任何一个函数都可以当做一个构造函数来使用。
//第二种:构造函数创建对象
//M是一个构造函数,
var M = function (name) {
this.name = name;
}
//o3是一个M的实例对象,
var o3 = new M('happychen');
函数都有prototype属性,这个属性是函数声明时js自动加上去的,prototype就是原型对象。(构造函数和原型对象通过prototype属性保持关联)
原型对象中会有一个constructor属性,这个属性是声明的那个构造函数。(构造函数和原型对象通过constructor属性又保持了关联)
构造函数可以通过new运算符生成一个实例对象。实例对象的__proto__属性指向 构造函数的原型对象prototype。
原型链就是从一个实例对象往上找 构造这个实例相关联的对象,这个相关联的对象再往上找又会找到和它相关联的原型对象,这样一直往上找,直到找到Object.prototype终止。
原型链的查找是通过__proto__和prototype这两个属性进行查找的。Object.prototype是整个原型链的顶端,找到Object.prototype就会终止查找。
将构造函数中的属性和方法放在原型对象上,构造函数的实例就可以共享这些属性和方法。通过原型链的方式找到原型对象,原型对象上的方法是可以被不同的实例共享的。
如果在实例对象上没有找一个属性或者方法,就会在实例的原型对象上找,如果在实例的原型对象上还没找到,就会在当前原型对象的原型对象上继续查找,直到找到Object.prototype终止。
只有构造函数才有prototype属性,实例对象有__proto__属性。但是构造函数也会有__proto__属性,因为构造函数也是一个函数,函数是一个对象,所以构造函数也会有__proto__属性。
说明函数M的构造函数是Function。
instanceof的原理![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/9679215bf0922290513636f8105845ff.png)
实例对象的__proto__属性引用的其实是 构造函数的prototype属性指向的那个原型(上图最后面的那个原型),虽然实例对象是由构造函数生成的,但是实例对象的__proto__属性和构造函数本身没什么关联,关联的只是造函数的prototype属性**指向的那个原型。
instanceof的原理就是判断实例对象的__proto__属性 和 构造函数的prototype属性**指向的是不是同一个引用。
原型链中的构造函数instanceof
时都会返回 true
用constructor来判断实例对象的直接构造函数:
new运算符的工作原理
new 运算符后面跟的是构造函数,比如 f = new foo();
- 一个新对象被创建,可以理解成一个字面量对象,这个对象是个空对象。这个空对象继承foo.prototype,此时原型链已经被关联上了,但还没关联到最终的实例对象上。
- 构造函数foo被执行,执行的时候,相应的参数会被传入,同时上下文(this)会被指定为这个新实例。new foo 等同于 new foo() ,只能用在不传任何参数的情况下。
- 如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象。
new运算符的工作原理代码演示:
var new2 = function (func) {
//新创建一个继承func.prototype的空对象
var o = Object.create(func.prototype);
//执行构造函数,此时将func函数的上下文转到对象o中
var k = func.call(o);
//判断函数执行结果的类型
if (typeof k === 'object') {
return k;
} else {
return o;
}
}
var o6 = new2(M);
console.log(o6 instanceof M); //true
console.log(o6 instanceof Object); //true
console.log(o6.__proto__.constructor === M); //true
Object.create()
方法创建的对象是用原型链来连接的
var P = { name: 'happychen' };
var o4 = Object.create(P);
也就是o4.__proto__指向的就是P对象,o4的原型对象就是P。
name属性不直接在o4对象上,而是在原型链上: