JS面试—原型和原型链

目录

一、题目

1、如何判断一个变量是数组类型

2、写一个原型链继承的例子

3、描述new一个对象的过程

4、zepto (或其他框架)源码中如何使用原型链

二、知识点

2.1 构造函数

2.2 构造函数——拓展

2.3 原型规则和示例

2.4 原型链

2.5 instanceof


一、题目

1、如何判断一个变量是数组类型

var arr=[];
arr instanceof Array;//true

arr.__proto__===Array.prototype
Array.prototype.__proto__===Object.prototype上面的一句话代表的是这两句话,不能明确表示出arr的构造函数是Array还是Object,所以下面必须用constructor 

if(arr instanceof Array===true && arr.__proto__.constructor===Array){
      //是数组
}

注意:typeof arr;   //object     typeof只能判断值类型,无法判断是否是数组。 

2、写一个原型链继承的例子

这个例子仅供理解 面试时不要答这个哦

function Animal(){
    this.eat=function(){
        console.log('animal eat')
    }
}
//狗
function Dog(){
    this.bark=function(){
        console.log('dog bark')
    }
}
Dog.prototype=new Animal();
//哈士奇
var hashiqi=new Dog();
//DOM封装查询
function Elem(id){
	this.elem = document.getElementById(id); 
}
Elem.prototype.html = function(val){
	var elem = this.elem;
	if(val){
		elem.innerHTML = val;
		return this;
	}else{
		return elem.innerHTML;
	}
}
Elem.prototype.on = function (type,fn){
	var elem = this.elem;
	elem.addEventListener(type,fn);
	return this;
}
var div1 = new Elem('div1');
div1.html('

hello world

').on('click',function(){ alert('clicked'); }).html('

hello javascript

');

3、描述new一个对象的过程

  • 创建一个新对象;
  • 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ;
  • 执行构造函数中的代码(为这个新对象添加属性) ;
  • 返回新对象。

4、zepto (或其他框架)源码中如何使用原型链

二、知识点

2.1 构造函数

//构造函数 大写字母开头
function Foo(name,age){
    this.name=name;
    this.age=age;
    this.class='class-1';
    //return this   //默认有这一行
}
var f=new Foo('zhangsan',20)

注意:构造函数的首字母是大写,自己写函数的时候,如果是构造函数,首字母也要大写,方便阅读。 

过程分析:

  1. 一个新对象被创建。它继承自构造函数的原型对象(比如Foo.prototype)
  2. 构造函数Foo被执行。执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例。new Foo等同与new Foo(),只能用在不传递任何参数的情况。
  3. 如果函数没有返回其他对象,那么this指向这个新对象,否则this指向构造函数中返回的对象。

2.2 构造函数——拓展

var a={} 其实是 var a=new Object()
var a=[] 其实是 var a=new Array()
function Foo= {...} 其实是 var Foo=new Function(...)
使用instanceof 判断一个函数是否是一个变量的构造函数
判断一个变量是否为“数组”   变量 instanceof Array

2.3 原型规则和示例

 1、所有的引用类型(数组、对象、函数),都具有对象特性,即可自由拓展属性( 除了‘null’意外)

var obj={};obj.a=100;
var arr={};arr.a=100;
function fn (){};
fn.a=100;

2、所有的引用类型(数组、对象、函数),都有一个_proto_属性(隐式原型),属性值是一个普通的对象

console.log(obj._proto_);
console.log(arr._proto_);
console.log(fn._proto_);

3.所有的函数,都有一个prototype属性(显式原型)属性值也是一个普通对象

console.log(fn.prototype);

 4.所有引用类型(数组、对象、函数),_proto_  属性值指向它的构造函数的“prototype”属性值

console.log(obj._proto_===Object.probetype)

5.当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么就会去它的_proto_(即它的构造函数的prototype)中寻找

function Foo(name,age){
    this.nmae=name;
}
Foo.prototype.alertName=function(){
    alert(this.name)
}
//创建示例
var f =new Foo('zhangsan');
f.printName=function(){
    console.log(this.name)
}
//测试
f.printName();
f.alertName();  //要去f._proto_(Foo.prototype)中去找

注意:无论函数是自身的属性还是 从原型中得到的属性,this 都指向f自身

判断是不是对象自身的属性:

var item;
for(item in f){
//高级浏览器已经在for in中屏蔽了来自原型的属性
//但是这里建议大家还是加上这个判断,保证程序的壮健性
if(f.hasOwnProperty(item)){
console.log(item);//name,printName
}
}

6.每个构造函数的prototype属性都有一个constructor属性,这个属性指向构造函数本身

Object.prototype.constructor===Object//true

JS面试—原型和原型链_第1张图片

 

2.4 原型链

  • 什么是原型链:

JavaScript中的每一个对象都有一个prototype属性,成为原型,而原型的值也是一个对象,因此它也有自己的原型,这样就串联成一条原型链,原型链的链头是object,它的prototype比较特殊,值为null

原型链就是,如果在对象上没有找到需要的属性或者方法引用,引擎就会在[[prototype]]关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的[[prototype],以此类推。一直到Object.prototype原型对象终止(null),Object.prototype是原型链的顶端。

(如果找到Object.prototype上还找不到,原路返回,告诉实例此方法或属性没有找到或者没有定义。如果说在中间的任意一个环节找到了,他就停止向上查找直接返回这个方法的用处)

JS面试—原型和原型链_第2张图片

function Foo(name,age){
    this.nmae=name;
} 
Foo.prototype.alertName=function(){   //构造函数的原型上添加alertName属性
    alert(this.name)
}
//创建示例
//var f =Object.create(Foo)   创建一个新对象(f),并把它关联到我们制定的对象(Foo)
var f =new Foo('zhangsan');
f.printName=function(){
    console.log(this.name)
}
//测试
f.printName();
f.printName();//zhangsan,this指向的是f对象本身,f对象本身有printName这个属性
f.alertName();//zhangsan,this指向的是f对象本身,f对象本身没有alertName属性,然后去f对象的__proto__隐式原型上查找(即构造函数的显原型上查找Foo.prototype),然后找到alertName
f.toString();  //f对象本身没有toString属性,然后去f对象的__proto__隐式原型上查找,Foo.prototype上也没有,然后去Foo.prototype.__proto__上查找(相当于Object.prototype),然后找到toString属性(f.__proto__.__proto__)

var f =Object.create(Foo)   创建一个新对象(f),并把它关联到我们制定的对象(Foo) 

不需要类来创建俩个对象之间的关系,只需要通过委托来关联对象就足够

  • 原型对象和原型链他们之间到底起什么作用?

如果构造函数中有很多属性和方法,那么我的实例是不是就可以共用这些东西,当我有多个实例想用共用这些东西的时候,我不能每个实例都拷贝一份,他们之间有相同方法的时候我是不是考虑存到一个共同的东西上。那个共同的东西就是原型对象。

如果在构造函数里面用this添加很多方法或者属性,以后每个实例都会拷贝一份这个东西,会占用很多内存,我们可以把那些共用的方法都放在Foo.prototype原型对象上,任何一个实例就可以通过他的原型链找到他上面的原型对象,原型对象上面的属性和方法,都是可以被实例共享的。

2.5 instanceof

用于判断引用类型属于哪个构造函数的方法

JS面试—原型和原型链_第3张图片

 

JS面试—原型和原型链_第4张图片

你可能感兴趣的:(JavaScript知识点总结)