目录
一、题目
1、如何判断一个变量是数组类型
2、写一个原型链继承的例子
3、描述new一个对象的过程
4、zepto (或其他框架)源码中如何使用原型链
二、知识点
2.1 构造函数
2.2 构造函数——拓展
2.3 原型规则和示例
2.4 原型链
2.5 instanceof
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只能判断值类型,无法判断是否是数组。
这个例子仅供理解 面试时不要答这个哦
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
');
//构造函数 大写字母开头
function Foo(name,age){
this.name=name;
this.age=age;
this.class='class-1';
//return this //默认有这一行
}
var f=new Foo('zhangsan',20)
注意:构造函数的首字母是大写,自己写函数的时候,如果是构造函数,首字母也要大写,方便阅读。
过程分析:
var a={} 其实是 var a=new Object()
var a=[] 其实是 var a=new Array()
function Foo= {...} 其实是 var Foo=new Function(...)
使用instanceof 判断一个函数是否是一个变量的构造函数
判断一个变量是否为“数组” 变量 instanceof Array
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
JavaScript中的每一个对象都有一个prototype属性,成为原型,而原型的值也是一个对象,因此它也有自己的原型,这样就串联成一条原型链,原型链的链头是object,它的prototype比较特殊,值为null
原型链就是,如果在对象上没有找到需要的属性或者方法引用,引擎就会在[[prototype]]关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的[[prototype],以此类推。一直到Object.prototype原型对象终止(null),Object.prototype是原型链的顶端。
(如果找到Object.prototype上还找不到,原路返回,告诉实例此方法或属性没有找到或者没有定义。如果说在中间的任意一个环节找到了,他就停止向上查找直接返回这个方法的用处)
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原型对象上,任何一个实例就可以通过他的原型链找到他上面的原型对象,原型对象上面的属性和方法,都是可以被实例共享的。
用于判断引用类型属于哪个构造函数的方法