当前位置: 首页 > 科技观察

JavaScript原型链和instanceof操作符的暧昧关系

时间:2023-03-17 19:42:46 科技观察

回到两个月前,简单了解了原型链、prototype和__proto__之间的乱七八糟的关系,也简单了解了typeof和instanceof操作符这两种类型,但是,无论如何,尝试以下两个问题:console.log(FunctioninstanceofFunction);console.log(StringinstanceofString);因此,我们经常使用typeof运算符来判断一个变量的类型,确实好用。可以判断number、boolean、string,但是判断object的能力一般。比如Array和null的判断结果都是对象,而对于new的一些对象,比如newString(),newNumber()等,结果都是对象,所以就有一个问题是不可能的更详细的判断对象实例,这时候就需要instanceof了。顾名思义,instanceof是一个运算符,用于判断一个对象是否是某个构造函数的实例。这样对于new出来的变量到底是数字,字符串还是别的什么,就有了更进一步的理解。看起来很简单,其实不然。以上两个问题只是一个小测试。先放一下,再回顾一下原型链。JavaScript中的一切都是对象,所有对象都有一个__proto__属性值(即原型),一些作弊浏览器可能不支持。暂且将对象的这个属性的值作为对象的构造函数的值。原型值的作用是对于某一类对象,不需要重复定义某个方法。比如对于对象[1,2,3],明明this是一个数组对象,里面有pop、push等方法,但并不代表它本身就有这些方法,而是它的构造函数Array,以及对象的__proto__值是Array函数的原型值,所以如果它本身没有pop方法,就会使用它的__proto__在所谓的原型链中查找;而链的末端是Object,因为所有的对象都是从Object构造出来的,而Object.prototype.__proto__规定它指向null。文字的描述总是苍白无力,举个简单的例子:varfun=function(){this.a=1;};fun.prototype.b=2;varobj=newfun();obj.a;//1obj。b;//2网络盗版的例子和图片,仔细看会发现很清楚。志新接下来看instanceof操作符。instanceof的常规用法是判断a是否是b类型:console.log(trueinstanceofBoolean);//falseconsole.log(newNumber(1)instanceofNumber);//trueinstanceof也可以判断父类型:functionFather(){}functionChild(){}Child.prototype=newFather();vara=newChild();console.log(ainstanceofChild);//trueconsole.log(ainstanceofFather);//trueChild构造函数继承自Father,实例a无疑是Child构造的,但为什么也是Father的一个实例呢?其实instanceof操作符的核心可以简单的用下面的代码来描述:a=a.__proto__;}returnfalse;}functionFoo(){}console.log(ObjectinstanceofObject===check(Object,Object));//trueconsole.log(FunctioninstanceofFunction===check(Function,Function));//trueconsole.log(NumberinstanceofNumber===check(Number,Number));//trueconsole.log(StringinstanceofString===check(String,String));//trueconsole.log(FunctioninstanceofObject===check(Function,Object));//trueconsole.log(FooinstanceofFunction===check(Foo,Function));//trueconsole.log(FooinstanceofFoo===check(Foo,Foo));//true简单的说,如果a是一个b的实例,然后a将b的原型中定义的方法和属性必须是可以使用的,那么代码说明a的原型链中有一个b.prototype值相同的对象,所以一层层查找就可以了沿着a的原型链,StringNumberBoolean和Function都是函数,函数统一由Function构造,所以它们和任何简单的函数一样,可以在Function上使用prototype属性:Function.prototype.a=10;console.log(String.a);//10***先简单说一下前两个问题。//为了表达方便,先区分左边的表达式和右边的表达式FunctionL=Function,FunctionR=Function;//下面按照规范一步步推导=FunctionL.__proto__=Function.prototype//第一次判断O==L//返回true//为了表达的方便,先区分左边的表达式和右边的表达式StringL=String,StringR=String;//按照规范一步步推导O=StringR。prototype=String.prototypeL=StringL.__proto__=Function.prototype//第一次判断O!=L//循环判断L是否还有__proto__L=String.prototype.__proto__=Object.prototype//第二次判断O!=L//循环查找L是否还有__proto__L=String.prototype.__proto__=null//第三次判断L==null//返回false