JavaScript学习总结(四)——this原型链javascript面向对象张果

在JavaScript中this表示:谁调用当前函数this就指向谁,不知道调用者时this指向window。

JavaScript是由对象组成的,一切皆为对象,万物皆为对象。this是一个动态的对象,根据调用的对象不同而发生变化,当然也可以使用call、apply修改this指向的对象。它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用

代码如下:

JavaScriptthis

JavaScriptthis

functionsayHello(){alert("HelloButton!");console.log(this);};document.getElementById("btnA").onclick=sayHello;请问输出到控制台的结果是什么?相同吗?输出两个什么对象?

答案:

WindowViewCode1.1、JavaScript中函数与方法的区分在面向过程的语言中我们习惯把完成某个特定功能的代码块称为“函数”或“过程”,当然过程一般没有返回值。在面向对象语言中我们把对象的功能称为“方法”。但JavaScript是种介于面向对象与面向过程中间的语言,同样的方法有时是函数,有时是方法,如下所示:

//1functionshow(){console.log("这是一个函数");}//2(function(){console.log("这是一个函数表达式");})();//3varobj1={show:function(){console.log("这是一个方法");}};//4functionobj2(){//obj2是函数,构造函数this.show=function(){console.log("这是一个方法,是一个表达式");}}varobj3=newobj2();可以简单的认为如果调用时没有通过对象没有指定上下文则为函数,否则为方法。

当在全部范围内使用this,它将会指向全局对象。一般是window对象,但全局对象不一定只有window,特别是在node.js环境中。作为函数调用时一般指向全局对象。

vari=5;i=6;console.log(i);//6console.log(window.i);//6console.log(this.i);//6console.log(this);//window结果:

varname="tom";console.log(this.name);//顶层对象,一般为windowfunctionshow(){console.log(this.name);//顶层对象,一般为windowreturnfunction(){console.log(this.name);//顶层对象,一般为window,因为返回的是函数}}varf1=show();f1();运行结果:

当函数作为方法调用时this指向调用该方法的对象。

functionshow(){//当obj1.view()时this就是obj1,obj2.view()时this就是obj2console.log(this.name);}varobj1={name:"jack",view:show};obj1.view();varobj2={name:"mark",view:show};obj2.view();运行结果:

示例代码:

varname="lucy";this.name="Mali";functionshow(){//当obj1.view()时this就是obj1,obj2.view()时this就是obj2console.log(this.name);returnfunction(){console.log(this.name);//这里的this是调用时动态决定}}varobj1={name:"jack",view:show};obj1.view();varobj2={name:"mark",view:show};varf1=obj2.view();f1();//因为f1属于window(浏览器环境),调用f1时的this也就是window运行结果:

varname="lucy";this.name="Mali";functionshow(){//当obj1.view()时this就是obj1,obj2.view()时this就是obj2console.log(this.name);that=this;//闭包returnfunction(){console.log(that.name);//这里的that指向的是外层函数调用时的对象}}varobj1={name:"jack",view:show};obj1.view();varobj2={name:"mark",view:show};varf1=obj2.view();f1();运行结果:

构造函数中的this指向新创建的对象,new出谁this就是谁。

this.name="吉娃娃";functionDog(name){this.name=name;this.bark=function(){console.log(this.name+"在叫,汪汪...");}}vardog1=newDog("哈士奇");dog1.bark();运行结果:

按照严格的语法,构造函数不应该返回值,但是JavaScript是允许构造方法返回值的,默认返回this,修改后的示例如下:

this.name="吉娃娃";functionDog(name){this.name=name;this.bark=function(){console.log(this.name+"在叫,汪汪...");}returnthis.bark;}vardog1=newDog("哈士奇");dog1();运行结果:

当调用方法是通过Function.call,或Function.apply时this为调用时指定的对象,如果没有指定则为顶层对象,浏览器中是window。

this.name="伽啡";functionCat(name){this.name=name;}varbark=function(n){console.log(this.name+"叫了"+(n||1)+"声喵喵...");}varcat1=newCat("波斯");varcat2=newCat("龙猫");bark.call(cat1,5);//调用时this是cat1bark.apply(cat2,[8]);//调用时this是cat2bark.apply(window,[9]);//调用时this是windowbark.apply();//调用时this是顶层对象

运行结果:

如果页面中的元素与事件进行绑定时事件中的this一般指向网页元素,如按钮,文本框等。但是在元素中直接指定要执行的函数则this指向window顶层对象。

当点击D时的效果:

当点击按钮E时的效果:

thisvalue="window的值"varapp={value:"app的值",show:function(){alert(this.value);//如果show为事件,则this指向触发事件的对象},init:function(){//handler中的this指向btnEdocument.getElementById("btnF").addEventListener("click",this.show,false);}};app.show();//"app的值",show方法中的this指向app这个对象app.init();//init中的this指向谁app对象加载时运行结果:

点击按钮F时的效果:

点击按钮G时的效果:

在HTML元素上直接指定事件严格来说都不能说是事件绑定,只能描述是当按钮点击完成后执行的函数。如果想将执行时的对象带回,可以增加参数this。

函数调用可以如下几种基本形式:

1)、fun(x,y);

2)、obj.fun(x,y);

3)、fun.apply(obj,[x,y]);

4)、fun.call(obj,x,y);

第1,2种调用的方式最终将转换成3,4方法,也就是说1,2只是一种简化的语法糖,那么this就是apply与obj的第1个参数,指向调用时的上下文。

在javascript面向对象中关于原型(prototype)、原型链、__proto__、Function、Object等内容是较难理解的,先上几张便于大家理解的图:

JavaScript藏宝图

在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个"Prototype"内部属性,这个属性所对应的就是该对象的原型。

"Prototype"作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了"__proto__"这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器"Object.getPrototype(object)")。

(1)、所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Emptyfunction)

(2)、所有对象的__proto__都指向其构造器的prototype

(3)、对于所有的对象,都有__proto__属性,这个属性对应该对象的原型

(4)、对于函数对象,除了__proto__属性之外,还有prototype属性

当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性)

实例说明:

代码:

//构造器,函数,对象functionCat(nickname,color){//各个对象独有的this.nickname=nickname;this.color=color;}//所有对象公有的Cat.prototype.life=9;Cat.prototype.bark=function(){console.log(this.nickname,this.color,this.life,"喵喵...");}varc1=newCat("波斯","绿色");c1.bark();varc2=newCat("加菲","红色");c2.bark();控制台:

关系图:

(1)、所有的函数/构造器都拥有prototype属性,用于指向原型对象。

(2)、所有的函数即是构造器又是对象。

(3)、所有的对象都拥有__proto__非标准属性。

(4)、所有函数(构造器)的__proto__都指向Function.prototype对象。

(5)、所有对象的__proto__指向它的构造器的prototype对象。

(6)、所有函数都是由Function构造出来的,Function自己构造了自己,Object是由Function构造出来的,Function是构造器。

(7)、所有对象的最终原型对象都指向了Object的prototype属性,Object的prototype对象的__proto__属性指向NULL。

(8)、所有prototype原型对象中的constructor属性都指向其构造器。

(9)、原型对象prototype中的成员是所有对象共有的。

(10)、对象在查找成员时先找本对象自己的所有成员,再查找构造器的原型中的成员(向上再查找父类的成员,多步),最终查询Object的成员。

JavaScriptObjectLayout:

ObjectRelationshipDiagramwithInheritance

JavaScript是一种通过原型实现继承的语言与别的高级语言是有区别的,像java,C#是通过类型决定继承关系的,JavaScript是的动态的弱类型语言,总之可以认为JavaScript中所有都是对象,在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个"prototype"内部属性,这个属性所对应的就是该对象的原型。

"prototype"作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome内核的JavaScript引擎中提供了"__proto__"这个非标准的访问器(ECMA新标准中引入了标准对象原型访问器"Object.getPrototype(object)")。

现在有一个Student构造函数,通过new调用该构造函数可以创建一个新的对象,示例如下:

//构造方法,用于创建学生对象functionStudent(name){this.name=name;}vartom=newStudent("tom");tom.show=function(){console.log(this.name);}varrose=newStudent("rose");rose.show=function(){console.log(this.name);}tom.show();rose.show();运行结果:

上面的示例中tom与rose都需要show方法,创建对象后我们直接为两个对象分别都增加了show方法,但是这样做的弊端是如果再增加更多对象也需要添加show方法,最好的办法是修改构造方法Student,如下所示:

//构造方法,用于创建学生对象functionStudent(name){this.name=name;this.show=function(){console.log(this.name);}}vartom=newStudent("tom");varrose=newStudent("rose");tom.show();rose.show();但是如果Student构造函数是一个内置的函数或是其它框架定义的类型,则修改就比较麻烦了,可以不修改源码的情况扩展该对象的原型也可以达到目的,如下所示:

//构造方法,用于创建学生对象functionStudent(name){this.name=name;}//修改Student对象的原型,增加show方法Student.prototype.show=function(){console.log(this.name);}vartom=newStudent("tom");varrose=newStudent("rose");tom.show();rose.show();在示例中我们并没有修改Student这个构造函数而是修改了了Student的原型对象,类似它的父类,如下图所示:

此时你也许会认为所有的Object都增加了show方法,这样想是错误的,因为Student的原型是一个对象而不是像其它高级语中的类型,我们修改的只是Student的原型对象,不会影响其它的对象。

varmark=newObject();mark.name="mark";varlucy={name:"lucy"};//mark.show();//lucy.show();此处的两个show方法是错误的。总之原型的主要作用就是为了实现继承与扩展对象。

在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个”[[Prototype]]”内部属性,这个属性所对应的就是该对象的原型。

“[[Prototype]]”作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了__proto__这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器”Object.getPrototype(object)”)。在JavaScript的原型对象中,还包含一个”constructor”属性,这个属性对应创建所有指向该原型的实例的构造函数

在JavaScript中,判断一个变量的类型可以用typeof,如:

varstr1="Hello";varstr2=newString("Hello");console.log(typeof1);console.log(typeof(true));console.log(typeofstr1);console.log(typeofstr2);console.log(typeof([1,2,3]));console.log(typeofDate);console.log(typeofundefined);console.log(typeofnull);console.log(typeofzhangguo);运行结果:

1)、数字类型,typeof返回的值是number。比如说:typeof(1),返回值是number2)、字符串类型,typeof返回的值是string。比如typeof("123")返回值是string。3)、布尔类型,typeof返回的值是boolean。比如typeof(true)返回值是boolean。4)、对象、数组、null返回的值是object。比如typeof(window),typeof(document),typeof(null)返回的值都是object。5)、函数类型,返回的值是function。比如:typeof(eval),typeof(Date)返回的值都是function。6)、不存在的变量、函数或者undefined,将返回undefined。比如:typeof(abc)、typeof(undefined)都返回undefined。

使用typeof运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回"object"。ECMAScript引入了另一个Java运算符instanceof来解决这个问题。instanceof运算符与typeof运算符相似,用于识别正在处理的对象的类型。与typeof方法不同的是,instanceof方法要求开发者明确地确认对象为某特定类型。

instanceof用于判断某个对象是否被另一个函数构造。

例如:varoStringObject=newString("helloworld");console.log(oStringObjectinstanceofString);//输出"true"

varstr1="Hello";varstr2=newString("Hello");console.log(str1instanceofString);//stringfalseconsole.log(str2instanceofString);//objecttrueconsole.log(1instanceofNumber);//falsefunctionFoo(){};varf1=newFoo();console.log(f1instanceofFoo);运行结果:

函数就是对象,代表函数的对象就是函数对象。所有的函数对象是被Function这个函数对象构造出来的。Function是最顶层的构造器。它构造了系统中所有的对象,包括用户自定义对象,系统内置对象,甚至包括它自已。这也表明Function具有自举性(自已构造自己的能力)。这也间接决定了Function的call和constructor逻辑相同。每个对象都有一个constructor属性,用于指向创建其的函数对象。

先来看一个示例:

functionFoo(a,b,c){//Foo这个构造函数由Function构造,函数也是对象returna*b*c;}varf1=newFoo();//f1由Foo构造,Foo是一个构造函数,可以理解为类console.log(Foo.length);//参数个数3console.log(typeofFoo.constructor);//functionconsole.log(typeofFoo.call);//functionconsole.log(typeofFoo.apply);//functionconsole.log(typeofFoo.prototype);//objectobject运行结果:

函数与对象具有相同的语言地位没有类,只有对象函数也是一种对象,所谓的函数对象对象是按引用来传递的

functionFoo(){};varfoo=newFoo();//Foo为foo的构造函数,简单理解为类型console.log(fooinstanceofFoo);//true//但是Function并不是foo的构造函数console.log(fooinstanceofFunction);//false//Function为Foo的构造函数alert(FooinstanceofFunction);//true上面的代码解释了foo和其构造函数Foo和Foo的构造函数Function的关系,Foo是由Function构造得到,可以简单理解为,系统中有一个这样的构造函数:

functionFunction(name,body){}varFoo=newFunction("Foo","");如上面例子中的构造函数,JavaScript中函数也是对象,所以就可以通过_proto_查找到构造函数对象的原型。

Function对象作为一个函数,就会有prototype属性,该属性将对应”function(){}”对象。

Function对象作为一个对象,就有__proto__属性,该属性对应”Function.prototype”,也就是说,”Function._proto_===Function.prototype”。

在这里对“prototype”和“proto”进行简单的介绍:

对于所有的对象,都有__proto__属性,这个属性对应该对象的原型。

对于函数对象,除了__proto__属性之外,还有prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性)

对于Object它是最顶层的对象,所有的对象都将继承Object的原型,但是你也要明确的知道Object也是一个函数对象,所以说Object是被Function构造出来的。

alert(FunctioninstanceofFunction);//truealert(FunctioninstanceofObject);//truealert(ObjectinstanceofFunction);//truefunctionFoo(){};varfoo=newFoo();alert(fooinstanceofFoo);//truealert(fooinstanceofFunction);//falsealert(fooinstanceofObject);//truealert(FooinstanceofFunction);//truealert(FooinstanceofObject);//trueJavaScript原型链

functionA(){this.x="x";};vara=newA();functionB(){this.y="y"};B.prototype=a;varb=newB();functionC(){this.z="z"};C.prototype=b;varc=newC();console.log(cinstanceofC);console.log(cinstanceofB);console.log(cinstanceofA);console.log(cinstanceofObject);console.log(c.x+","+c.y+","+c.z);运行结果:

当查找一个对象的属性时,JavaScript会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是Object.prototype),如果仍然没有找到指定的属性,就会返回undefined。

Object对象本身是一个函数对象。既然是Object函数,就肯定会有prototype属性,所以可以看到”Object.prototype”的值就是”Object{}”这个原型对象。反过来,当访问”Object.prototype”对象的”constructor”这个属性的时候,就得到了Obejct函数。另外,当通过”Object.prototype._proto_”获取Object原型的原型的时候,将会得到”null”,也就是说”Object{}”原型对象就是原型链的终点了。

JavaScript内置了很多对象,如Array、Boolean、Date、Function、Number、Object、String

假设我们想给String类型增加一个repeat方法,实现重复字符,如"a".rpt(),则将输出aa,"a".rpt(5),输出“aaaaa”,因为String是JavaScript中内置的对象,可以通过修改该对象的原型达到目的:

prototype原型varv="hi";String.prototype.rpt=function(n){n=n||2;vartemp="";for(vari=0;i运行结果:

示例中给String对象的原型增加了一个rpt方法,所有的String都是衍生自String.prototype,那所有的String对象都将获得rpt方法。

//扩展String类型,增加trim方法用于删除字符串的首尾空格String.prototype.trim=function(){returnthis.replace(/^\s+|\s+$/igm,'');}console.log("[begin]"+"HelloJavaScript".trim()+"[end]");运行结果:

为了扩展更加方便,可以修改Function的原型,给每一个函数衍生的对象增加方法method用于扩展。

//修改函数对象的原型,添加method方法,扩展所有的函数Function.prototype.method=function(name,fun){//如果当前扩展的函数的原型中不包含名称为name的对象if(!this.prototype[name]){//添加this.prototype[name]=fun;}}String.method("show",function(){console.log("输出:"+this);});"Hello".show();"JavaScript".show();运行结果:

我们可以通过对象调用某个方法,因为这个对象的原型中已经定义好了该方法,其实我们通过原型也可以直接调用某个方法,有些方法只存在原型中,只有当前类型关联了该原型才可以获得该方法,但有时我们需要使用该方法去处理非该原型下的对象,如:

functionadd(x,y,z){vararray1=[].slice.call(arguments,0,3);console.log(array1);vararray2=Array.prototype.slice.apply(arguments,[0,3]);console.log(array2);}add(1,2,8,9,10);运行结果:

varstr1="HelloJavaScript";console.log(str1.toUpperCase());//传统的调用办法varstr2=String.prototype.toUpperCase.apply(str1);//通过原形直接调用console.log(str2);varstr3=String.prototype.toUpperCase.call(str1);//通过原形直接调用console.log(str3);vararray1=[2,3,5,7,8,9,10];vararray2=array1.slice(1,3);console.log(array2);varslice=Array.prototype.slice;console.log(slice.apply(array1,[1,3]));//通过原形直接调用console.log(slice.call(array1,1,3));运行结果:

练习:扩展Date,增加一个显示中文日期的方法,如:newDate().trandition(),输出2016年08月09日23点15分18秒;使用prototype的方式间接调用该方法。

prototype是函数才有的属性,prototype本身就是一个对象,prototype对象中拥有constractor构造器(该构造器反向指回函数)

__proto__是对象带有属性,用于访问创建对象的类型所对应的原型

字面量创建的对象(o={})或Object创建的对象__proto__指向Object.prototype

示例:

/*1、字面量方式*/vara={};console.log(a.__proto__);//Object{}console.log(a.__proto__===a.constructor.prototype);//true/*2、构造器方式*/varA=function(){};vara=newA();console.log(a.__proto__);//A{}console.log(a.__proto__===a.constructor.prototype);//true/*3、Object.create()方式*/vara1={a:1}vara2=Object.create(a1);console.log(a2.__proto__);//Object{a:1}console.log(a.__proto__===a.constructor.prototype);//false(此处即为图1中的例外情况)示例:

结果:

varA=function(){};vara=newA();console.log(a.__proto__);//A{}(即构造器functionA的原型对象)console.log(a.__proto__.__proto__);//Object{}(即构造器functionObject的原型对象)console.log(a.__proto__.__proto__.__proto__);//null示例:

结果:

functionPerson(name,age){this.name=name;this.age=age;}Person.prototype.MaxNumber=9999;Person.__proto__.MinNumber=-9999;varwill=newPerson("Will",28);console.log(will.MaxNumber);//9999console.log(will.MinNumber);//undefined在这个例子中分别给”Person.prototype“和”Person.proto”这两个原型对象添加了”MaxNumber“和”MinNumber”属性,这里就需要弄清”prototype”和”proto”的区别了。

“Person.prototype“对应的就是Person构造出来所有实例的原型,也就是说”Person.prototype“属于这些实例原型链的一部分,所以当这些实例进行属性查找时候,就会引用到”Person.prototype“中的属性。

对象创建方式影响原型链

varJuly={name:"张三",age:28,getInfo:function(){console.log(this.name+"is"+this.age+"yearsold");}}console.log(July.getInfo());当使用这种方式创建一个对象的时候,原型链就变成下图了.July对象的原型是”Object.prototype”也就是说对象的构建方式会影响原型链的形式。

在JavaScript中,每个函数都有一个prototype属性,当一个函数被用作构造函数来创建实例时,这个函数的prototype属性值会被作为原型赋值给所有对象实例(也就是设置实例的`__proto__`属性),也就是说,所有实例的原型引用的是函数的prototype属性。(只有函数对象才会有这个属性!)

使用new关键字调用函数(newClassA(…))的具体步骤:

1.创建空对象;

varobj={};2.设置新对象的constructor属性为构造函数,设置新对象的__proto__属性指向构造函数的prototype对象;

obj.__proto__=ClassA.prototype;3.使用新对象调用构造函数,函数中的this被指向新实例对象:

ClassA.call(obj);//{}.构造函数();4.将初始化完毕的新对象地址,保存到等号左边的变量中

functionCar(name){this.name=name;}//1、直接创建varc1=newCar("BYD");//2、实际创建对象的步骤//2.1、创建空的对象字面量varc2={};//2.2、将对象的__proto__指向构造器的原型对象(prototype)c2.__proto__=Car.prototype;//2.3、调用构造器,初始化创建的对象Car.call(c2,"BYD");//2.4、将创建的对象地址赋值给变量(返回给左边的变量)结果:

注意:若构造函数中返回this或返回值是基本类型(number、string、boolean、null、undefined)的值,则返回新实例对象;若返回值是引用类型的值,则实际返回值为这个引用类型。

new的过程分为三步

varp=newPerson('张三',20);1.varp={};初始化一个对象p。2.p._proto_=Person.prototype;,将对象p的__proto__属性设置为Person.prototype3.Person.call(p,”张三”,20);调用构造函数Person来初始化p。1、prototype是函数才有的属性

2、__proto__是每个对象都有的属性,它不是W3C的标准属性,它指向prototype

3、__proto__可以理解为“构造器原型”,__proto__===constructor.prototype(Object.create()创建的对象不适用)

4、当js引擎查找对象的属性时,先查找对象本身是否存在该属性,如果不存在会在原型链上查找,但不会查找自己的prototype

5、函数的原型对象constructor默认指向函数本身,原型对象除了有原型属性外,为了实现继承,还有一个原型链指针__proto__,该指针指向上一层的原型对象,而上一层的原型对象的结构依然类似,这样利用__proto__一直指向Object的原型对象上,而Object的原型对象用Object.prototype.__proto__=null表示原型链的最顶端,如此变形成了javascript的原型链继承,同时也解释了为什么所有的javascript对象都具有Object的基本方法。

functionFoo(){}varfoo=newFoo();console.log(foo.prototype);//undefinedconsole.log(foo.__proto__===Foo.prototype);//trueconsole.log(Foo.prototype);//[objectObject]console.log(Foo.prototype.prototype);//undefined解释

只有函数对象有prototype属性(一般对象自己加的不算)

1、foo是Foo的一个实例,但是不是一个函数,所以没有prototype;Foo是Function的一个实例,而Function是一个函数,他的实例Foo也是一个函数,所以他们都有prototype。此外ObjectArrayRegExp等也是函数。Math就仅仅是一个newObject(),不是函数。

2、构造函数的prototype,默认情况下就是一个newObject()还额外添加了一个constructor属性。所以说默认是没有prototype只有__proto__的。除了Object.prototype这个对象,其他所有的对象都会有__proto__属性,之后函数才会有prototype属性。

在创建对象的时候会自动创建一个__proto__属性,指向它构造函数的prototype,当访问这个对象的属性的时候会顺带访问__proto__中对应的属性,也就是构造函数prototype这样实现了继承。只有创建函数的时候才会创建一个prototype属性,目的就是为了完成上面的继承方式。

图(橙色箭头是初始的关系,绿色是执行varFish=newFu...创建,蓝色是执行f1=newFish()创建。)

这样f1就可以通过__proto__访问Fish.prototype中的属性(当然这是程序执行的时候自动查找的)。Fish就可以访问Function.prototype定义的属性。所有对象都可以访问Object.prototype中的属性。

1、所有的函数/构造器都拥有prototype属性,原型一定是对象

2、所有原型对象拥有constructor属性指回其构造函数,原型中存放所有构造器创建的对象共有成员

3、JavaScript中通过原型链实现继承,将对象与对象串联起来,查询成员时由近到远

4、所有的对象都将指向其构造器的原型对象,默认不允许直接访问,但chrome等浏览器中可以通过__proto__访问到(所有对象的__proto_指向其构造器的原型对象)

5、JavaScript中一切都是对象,函数创建了对象其本身又是对象,对象都指定原型

6、所有的函数都是Function创建出来的,Function自己创建了自己

7、Object函数是Function创建出来的,Object函数的__proto__指向Function的原型对象

8、Function的原型对象的__proto__指向Object的原型对象,Object的原型对象指向了null,这是原型链的尽头

因为在JavaScript中没有访问修饰符,也没有块级作用域,this所定义的属性默认对外就是公开访问的,如下示例:

functionAnimal(){this.name="动物";this.weight=0;//重量}varcat=newAnimal();cat.name="猫";cat.weight=-90;console.log(cat);输出:

weight是-90,不正确,封装:

functionAnimal(){this.name="动物";varweight=0;//重量this.getWeight=function(){//读returnweight;};this.setWeight=function(_weight){//写if(_weight>0){weight=_weight;}else{throw"动物的重量必须为正数";}}}varcat=newAnimal();cat.name="猫";try{cat.setWeight(-90);}catch(e){console.log(e);}console.log(cat);结果:

functionAnimal(){this.name="动物";this.getName=function(){returnthis.name;}this.setName=function(name){this.name=name;}this.bark=function(){console.log(this.name+"在叫...");}}varanimal=newAnimal();animal.setName("小狗");animal.bark();这里定义的一个构造函数,将name封装成属性,Animal函数本身用于封装动物的属性与行为,运行结果:

JavaScript的继承的实现主要依靠prototype(原型)来实现,再增加两个动物,如狗与猫:

functionAnimal(){this.name="动物";this.getName=function(){returnthis.name;}this.setName=function(name){this.name=name;}this.bark=function(){console.log(this.name+"在叫...");}}functionDog(){this.hunt=function(){console.log("狗在捕猎");};}//指定Dog构造函数的原型对象,简单理解为父类Dog.prototype=newAnimal();functionCat(){this.hunt=function(){console.log("猫在抓老鼠");};}Cat.prototype=newAnimal();vardog=newDog();dog.bark();dog.hunt();varcat=newCat();cat.bark();cat.hunt();运行结果:

java与C#中的多态主要体现在重载与重写上,因为JavaScript是弱类型的,类方法参数是动态指定的所以并没有真正意义上的重载,只能在方法中判断参数达到目的。

JavaScript面向对象functionAnimal(){this.name="动物";this.getName=function(){returnthis.name;}this.setName=function(name){this.name=name;}this.bark=function(){console.log(this.name+"在叫...");}}functionDog(){this.hunt=function(){console.log("狗在捕猎");};}//指定Dog构造函数的原型对象,简单理解为父类Dog.prototype=newAnimal();//重写原型对象中的bark方法Dog.prototype.bark=function(){console.log("汪汪...");}functionCat(){this.hunt=function(){console.log("猫在抓老鼠");};}Cat.prototype=newAnimal();//重写原型对象中的bark方法Cat.prototype.bark=function(){console.log("喵喵...");}functionplay(animal){animal.bark();animal.hunt();}vardog=newDog();varcat=newCat();play(dog);play(cat);运行结果:

//二种重写的办法functionAnimal(name){this.name=name||"动物";this.bark=function(){console.log(this.name+"叫了:嗷嗷...");}};functionCat(){this.hunt=function(){console.log(this.name+"正在捕老鼠!");}}Cat.prototype=newAnimal("猫");Cat.prototype.bark=function(){console.log("喵喵");}varcat=newCat();cat.hunt();cat.bark();functionDog(){this.hunt=function(){console.log(this.name+"正在捕猎!");}this.bark=function(){console.log("汪汪");}}//让Dog继承Animal,修改原型的指向Dog.prototype=newAnimal("狗");vardog=newDog();dog.hunt();dog.bark();//重载的办法functionadd(n){if(typeofn==="number"){return++n;}if(ninstanceofArray){varsum=0;for(vari=0;i

THE END
1.苍蝇也没想到自己成了一个工业时期琥珀创意特效特效合成创意发...苍蝇也没想到 自己成了一个工业时期琥珀2024-11-04 12:46:02 打鱼晒网 河南 举报 0 分享至 0:00 / 0:00 速度 洗脑循环 Error: Hls is not supported. 视频加载失败 打鱼晒网 4237粉丝 河南广播电视台官方账号 00:13 一个敢说一个敢回答 妈妈估计都听不懂吧 00:12 一整个精准打击 轮胎:我...https://www.163.com/v/video/VOF7IJR6T.html
2.北纬30度现象snowmanzhu中国地震局吴庆举博士说:北纬30°现象,有一定的必然性。北纬30°被人称之为地球的脐带,其微量元素矿、磁场、电场、重力场对人与环境都有影响。另外地球自转,引起内部不同的纬度有不同的力作用。百慕大是磁场引起,青藏高原隆起是由于板块碰撞产生的。 世界的北纬30度...http://blog.chinaunix.net/uid-20064600-id-1978582.html
3.浅谈食品安全中的兽药残留及关键控制点论文集动物用药后,药物以原形或代谢物的形式随排泄物排出体外,残留于环境中,而绝大多数排入环境的兽药仍具有活性,将对土壤微生物、水生动物及昆虫等造成不良影响。低剂量的抗菌药长期排入环境中,会造成环境敏感菌耐药性的增加,而且其耐药基因还可以通过水环境扩展和演化。链霉素、土霉素、泰乐菌素,竹桃霉素、螺旋霉素、杆菌...https://www.foodmate.net/haccp/12/lunwenji/1842.html
4.鹿骨鹿骨的动物原形与功效 鹿骨单单从字面上的意思来看在,大多数的人都应该能够明白,鹿骨就是鹿的骨头。鹿在被宰杀过程当中,剔去鹿身上的肉和骨头周围的筋之后,最后剩下来的骨头就是鹿骨了。如果非要给它下个定义的话,那么就是鹿科的动物(如梅花鹿、马鹿)的骨骼称其为鹿骨 ...https://www.meipian.cn/1bwmfcd4
1.史上最全js面试题js面经在实际开发中,根据具体需求和场景来选择同步或异步编程方式,以获得更好的性能和用户体验。 2.怎么添加、移除、复制、创建、和查找节点 (1)创建新节点 createDocumentFragment() //创建一个DOM片段 createElement() //创建一个具体的元素 createTextNode() //创建一个文本节点 ...https://blog.csdn.net/m0_60676278/article/details/131734679
2.中国画中工笔初学入门之——(一)工笔画在长期的历史发展中建立了一套严整的技法体系,从而形成这一画体的独特风格面貌,其特点归纳如下:以线造型是中国画技法的特点,也是工笔画的基础和骨干。工笔画对线的要求是工整、细腻、严谨.一般用中锋笔较多。以固有色为主,一般设色艳丽、沉着、明快、高雅,有统一的色调,具有浓郁的中国民族色彩审美意趣。 http://www.360doc.com/content/18/0221/20/30535600_731278573.shtml
3.2021有哪些左右移动接东西的游戏左右移动接东西的游戏推荐左右接东西的游戏能够锻炼练玩家的反应能力,所以小编为大家总结了2021有哪些左右移动接东西的游戏,这些游戏随着关卡的深入,速度会越来越快,有助于玩家活动脑力锻炼反应能力,都是一些非常不错的游戏,值得玩家一试。 1、《贪吃蛇大作战》 贪吃蛇大作战是一款真人对战的竞技型手游,在这款游戏当中玩家需要操纵自己手中的...https://www.9game.cn/news/5713283.html
4.动物迷思我们要探讨单一神话如何“运作”,是因为这无关作者本人的倾向。相比坎贝尔对诗意幻想的青睐,我们要更强调他对切实的情绪及预言的重视。不这样做的话,我们将面对“小包是不是个想干自己娘的巨根美少女?”这种无法回答的扭曲问题。 另外,《动物朋友》(以下简称《动》)动画会被看作一部完全独立作品,不涉及漫画,游戏...http://bgm.tv/blog/276103
5.准备好了吗?KindleFireHD7国行评测(全文)整机灰黑色的色彩搭配让Kindle Fire HD 7看上去非常的平庸,贯穿机身背部的黑色金属缎带成了该机在外观设计上唯一的亮点,也是辨识这款产品的主要特征。经过杜比认证的双声道立体声扬声器位于这条金属缎带的两端,其中在缎带偏右的位置还刻有“kindle”字样的LOGO,除此之外机身背部再无其它设计元素。 https://pad.zol.com.cn/379/3791179_all.html
6.包豪斯风格的简单几何3d元素.白色设计原形形式.抽象背景库存...免版税 插画 Download preview 选择下载计划 免费免费图像试用 - 15 图像每月续订和计费。 261.63CNY随时付款 - 8 图币套餐包 更多下载计划 加到灯箱 包豪斯风格的简单几何3d元素. 白色设计原形形式. 抽象背景. 包豪斯风格的简单几何3d元素. 白色设计原形形式. 海报横幅印刷...https://cn.dreamstime.com/%E5%8C%85%E8%B1%AA%E6%96%AF%E9%A3%8E%E6%A0%BC%E7%9A%84%E7%AE%80%E5%8D%95%E5%87%A0%E4%BD%95-d%E5%85%83%E7%B4%A0-%E7%99%BD%E8%89%B2%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%BD%A2%E5%BD%A2%E5%BC%8F-%E6%8A%BD%E8%B1%A1%E8%83%8C%E6%99%AF-%E6%B5%B7%E6%8A%A5%E6%A8%AA%E5%B9%85%E5%8D%B0%E5%88%B7%E7%9A%84%E6%8A%BD%E8%B1%A1%E8%83%8C%E6%99%AF-image302336990
7.砷猪传说:猪饲料被指滥用砷锌铜等元素制剂在动物营养学中,砷既是必需微量元素,又是有毒有害元素。有机砷(又称有机胂)制剂属低毒,研究表明80%-90%有机砷几乎是以原形从家禽和猪的体内快速排出。所以,猪肉残留有机砷的可能性不大,但有机砷制剂会对环境造成影响。 研究表明,长期饮用砷含量50μg/L以上的水,会引发肺癌、皮肤癌、肾癌和肌肉萎缩等疾病...http://www.cnfood.com/news/show-124817.html
8.github.com/webrsb/aoetw/commit/1b6c2fcbb83824c07104ae26b8fc...新增元素 + + 文明 + + + + 柏柏:位於北非的部落,擁有強大的海軍與騎兵,準備來一場史詩般的戰爭征服伊比亞半島,獲取異教徒的財富,抵擋那些逐漸團結的伊比利亞半島上的王國。 + + + 馬利:跟隨偉大的曼薩·穆薩,成為西非最偉大的國王,征服周圍的王國,獲取更大的財富,牢牢控制該地區的貿易路線,你能...https://github.com/webrsb/aoetw/commit/1b6c2fcbb83824c07104ae26b8fc6dd18290f7ce.patch
9.为什么成年人也该看《疯狂动物城》?把镜头拉远,格局拉伸,我们还能看到小朋友们看不到的东西,而且很有意思。 片子中的有个剧情前提是动物们告别野蛮,进化出了食肉动物和食草动物的和谐文明形态,这才有了后面故事的展开和角色之间的互动。中间还能看到,一种特别的药,居然还能把食肉动物们打回野蛮原形,威胁整个动物文明的基础。 https://www.jianshu.com/p/4b52da940147
10.类似只狼的电脑游戏有哪些类似只狼的电脑游戏推荐这个合集汇集了与《只狼》类似的电脑游戏,每一款都充满了刺激的动作元素和深度的战斗体验。从精准的剑术对决到激烈的忍者格斗,这些游戏让玩家在充满挑战的环境中展现自己的技巧和智慧。《仁王2》以其精美的画面和丰富的剧情任务而闻名,而《对马岛之魂》则以其广阔的开放世界和自由度极高的玩法著称。https://down.ali213.net/heji/lszlddnyxhj/
11.文字脑洞钟馗送宝攻略图文找出12个动物怎么过抖音文字脑洞是抖音上非常有意思的文字解谜游戏,玩家将会在各种场景当中完成解谜通过!其中关卡钟馗送宝怎么过?在本关中需要玩家找到12个动物,谐音的物品名称也算,玩家可以放大图片,这样找起来会更加的方便。下面是3DM小编给大家带来的《文字脑洞》钟馗送宝找出12个动物攻略图文,感兴趣的小伙伴们一起来看看吧。 https://app.3dmgame.com/gl/437760.html
12.炉石传说猎人卡组推荐速攻抢脸流送葬猎来袭网络游戏游戏攻略判断术士类型就看术士前2费选择铺场还是卖血,上怪就是动物园,卖血或者上电线杆的是巨人术。 由于我们也有大量低费仆从,所以完全不虚动物园对铺场,况且动物园不带aoe(带了也是自残烈焰),我方有爆炸和放狗,就算动物园铺再满一个爆炸或放狗就可以打回原形,只要控制好场面,动物园根本没有胜算。 https://www.jb51.net/gonglue/213474.html