一二面_原型链
Posted 煜成'Studio
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一二面_原型链相关的知识,希望对你有一定的参考价值。
一二面_原型链
创建对象的几种方法?(考察这个为考察原型链和面向对象打下基础)
//第一种,下面的两个算是一类
//自变量对象,默认这个对象的原型链指向Object
var o1 = {name:'o1'};
//通过new Object申明一个对象
var o11 = new Object({name:'o1'});
//第二种,使用显式的构造函数来创建对象
var M = function () {
this.name = 'o2';
}
var o2 = new M()
//第三种,Object.create
var P = {name:'o3'};
var o3 = Object.create(P);
//这种方式创建的对象和上面两种不一样,看代码
原型、构造函数、对象实例、原型链?
上面的o1、o11、o2、o3是实例,(只要是生成的对象,它就是个实例);
凡是通过new来操作的后面跟着的函数就不是一个普通的函数,是构造函数(任何函数都可以当做构造函数,只要用new一操作);
构造函数可以通过new运算符生成一个实例;
申明一个函数的时候(function一个函数),JS自动加上一个prototype属性,这个属性会初始化一个空对象,也就是我们说的原型对象;
原型对象怎么能区分出我是被哪个构造函数所引用那,原型对象中会有一个构造器constructor,会默认申明的那个函数;
实例的__proto__属性指的是创建这个实例的构造函数的prototype属性;
原型链:
从实例对象往上找构造这个实例的相关联的对象,这个相关联的对象向上找它又有创造它的上一级的原型对象,以此类推,一直到Object.prototype终止(Object.prototype是整个原型链的顶端);
原型链是通过什么来实现这个向上找的过程那?
通过prototype和__proto__来完成原型链的查找;
原型对象和原型链之间到底起了一个什么作用?
构造函数中增加了很多属性和方法,实例便可以共用这些,当有多个实例的时候,想去共用某些属性和方法的时候,不能每个实例都拷贝一份,将这些实例共同的东西就是原型对象;
按照JS对象,JS引擎的分析的方式?
在访问一个实例的时候,在实例的本身上没有找到这个属性或者方法,就往它的原型对象上找,就是实例通过__proto__它的原型对象里面找,还没有找到,会在原型对象的基础上,通过__proto__再往上一级查找,以此类推,直到找到Object.prototype,要是还没找到,就原路返回,告诉它这个方法或属性没有找到,如果在中间的任何一个环节找到了,它就停止向上查找直接返回该属性或方法的用处;
注意:函数才会有prototype,对象是没有的;只有实例对象有__proto__,如果发现函数也有__proto__属性,因为函数既是函数也是一个对象,所以它也会有这个属性,一个函数的__protp__等于Function.prototype,所以说函数是Function这个构造函数的一个实例。
instanceof的原理?
实例对象的__proto__属性引用的是它的构造函数的原型对象(prototype),instanceof的原理就是判断实例对象的__proto__属性和构造函数的prototype是不是同一个引用,实例对象 instanceof 构造函数,在判断这个实例对象是不是这个构造函数的实例的时候,判断的是实例对象的__proto__属性和构造函数的prototype是不是引用的同一个地址,如果是,这个instanceof返回true,如果不是返回false,但是有一点,这个原型链上的原型对象上还会有它的构造函数的__proto__,以此类推向上走,那么在instanceof判断的时候,用实例对象来判断是不是上图原型的对象的构造函数的实例的情况,返回的也是true,只要是在这条原型链的构造函数都是这个实例对象的构造函数,这么说可能不严谨,但instanceof都会返回true,但如果这样怎么确定这个实例对象是这个构造函数的实例还是上级的实例那(特别是在有继承的情况下),此时可以用实例对象的constructor属性进行判断,实例对象的constructor属性只等于构造这个实例的构造函数,不等于上级其他的构造函数,这是唯一的,所以说用cosntructor来判断比用instanceof来判断更加严谨。
new运算符?
new运算符后面跟的是一个构造函数。一个新对象被创建,这个新对象继承自构造函数(foo)的prototype。==>
构造函数(foo)被执行。执行的时候,相应的传参会传入,同时上下文(this)会被指定为这个新对象。在不传任何参数的情况下,new foo 等同于 new foo(),并且只有这种情况下这个写法成立。==>
如果构造函数返回了一个“对象”,那么这个对象会取代这个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤一创建的对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型链</title>
</head>
<body>
<script>
// new运算符的解释
var new2 = function (func) {
// func为指定的构造函数
// 第一步,先要生成一个新的空对象o,新对象要指定(关联)构造函数原型对象(这里用第三种方式生成构造函数)(新创建的对象要继承构造函数的原型对象)
var o = Object.create(func.prototype);
// 执行构造函数
var k = func.call(o);
// 判断这个构造函数执行完的结果是不是对象类型,如果是对象类型的话直接返回k,如果不是,直接返回刚创建的那个对象
if (typeof k === 'object') {
return k;
}else{
return o;
}
}
var M = function (name) {
this.name = name;
this.age = 22;
}
o1 = new2(M);
console.log(o1);
console.log(o1 instanceof M);//true
console.log(o1 instanceof Object);//true
console.log(o1.__proto__.constructor === M);//true
M.prototype.walk = function () {
console.log('walk');
}
console.log(o1.walk());
console.log('----------------------');
//第三种创建对象的方式的得到的结果和其他两种不一样
//第一种,下面的两个算是一类
//自变量对象,默认这个对象的原型链指向Object
var o11 = {name:'o11'};
console.log(o11);
//通过new Object申明一个对象
var o111 = new Object({name:'o111'});
console.log(o111);
//第二种,使用显式的构造函数来创建对象
var MM = function () {
this.name = 'o22';
}
var o22 = new MM();
console.log(o22);
//第三种,Object.create
var p = {name:'o33'};
var o33 = Object.create(p);
console.log(o33);
//这种方式创建的对象和上面两种不一样,o33对象本身上是没有name属性,因为Object.create创建的对象是用原型链连接的,o33.__proto__指向的是p对象(p就是o33的构造函数的原型对象)
//为什么name不直接在这个对象上?o33本身是一个空对象,空对象上是没有name属性的,name属性是在原型对象上,Object.create方法是把参数中的对象作为一个新对象附给了o33,o33本身是不具备这个属性的,
//所以o33对象本身是没有name属性的,它只能通过原型链来查找这个属性,这就是三种创建对象不同的一个原因。
console.log(o33.__proto__ === p);//true
</script>
</body>
</html>
以上是关于一二面_原型链的主要内容,如果未能解决你的问题,请参考以下文章