理解Javascript的动态语言特征
理解动态执行和关闭的概念
动态执行:Javascript提供eval()在当前背景下的一段文字动态解释和执行功能。
我们需要了解的第一件事就是eval()方法,它具有全局关闭当前功能关闭,如下面的代码,你认为会输出什么
var I=100;
功能myfunc(){
var i =测试;
eval(我=你好。);
}
MyFunc();
警报(i);100
首先我们看一个变量i = 100的第一个定义,然后调用myfunc函数,然后修改局部变量,使他从价值of'test'into'hello ',但我们知道评价的意义是一段文本意义的立即执行;因此上面的代码我们可以写如下代码:
var I=100;
功能myfunc(){
var i =测试;
(函数(){())
返回(i =hello);
});
}
MyFunc();
警报(i);100
这是非常明显的。执行myfunc()方法后,我从测试到你好变化的价值,而是因为它是一个封闭,我的价值是为你好,它不能用于外部,所以浏览器打印100值。
我们都知道,eval()是全球通过Javascript的全局对象提供的方法,如果我们要访问的全局对象,它可以通过在浏览器中,宿主对象设置的窗口,和下面的代码也应该输出100。
var I=100;
功能myfunc(){
var i =测试;
Window.eval(我=你好。);
}
MyFunc();
警报(一);
然后不幸的是:在IE window.eval(EVAL)或()方法的输出是100;但window.eval使用标准的浏览器(),输出hello(EVAL),利用输出的方法100;IE使用Jscript引擎,和标准的浏览器的Javascript引擎SpiderMonkey,它是因为不同的Javascript引擎在eval()的封闭环境有不一样的理解。
的理解,采用全局关闭情况评价
以下代码:
var I=100;
功能myfunc(){
var i =测试;
Window.eval(我=你好。);
}
MyFunc();
警报(一);
在标准浏览器下,hello打印,但在IE下面100;如果使用下面的代码:
var I=100;
功能myfunc(){
var i =测试;
/ / window.eval(我=你好。);
eval.call(窗口,我=你好);
}
MyFunc();
警报(一);
是相同的,但也提供了一个进入全球封闭能力评价方法;但Jscript在IE eval(IE)没有这个能力,打印是100;但你可以用另一种方法在伊江得到完美的结果,window.execscript()方法中的代码总是在全球关闭执行的下面的代码:
var I=100;
功能myfunc(){
var i =测试;
Window.execscript(我=你好。);
//eval.call (window,'i= hello);
}
MyFunc();
警报(i);
Jscript()发动机采用execscript()分离从不同的表达评价全球关闭功能关闭,而Mozilla的Javascript引擎是通过调用eval()函数的不同形式。两种方法不同,但全球关闭可以以不同的方式实现。
理解eval()使用当前函数的闭包
总的来说,eval()总是使用当前功能关闭,下面的代码:
var I=100;
功能myfunc(){
var i =测试;
eval(我=你好。);
}
MyFunc();
警报(i);100
在代码:因为eval函数是函数中的代码,所以输出的是全局变量,我等于100;
总是执行eval代码文本()是一个代码块,和块包含语句,复合语句或语句组。
我们可以使用以下代码获取字符串、数字和布尔值。
eval(真实的); / /真的
eval(这是一个字符 / /串);
eval(3'); / / 3号
但是我们不能用同样的方法来获取一个对象;下面的代码:
eval({姓名:我
上面的代码会报错;错误:意外的查询如下:
事实上,代码写的,{姓名:我
第一个结成为一个标签说明。
{标签声明的左操作数}名称是一个标签。
我的名字已成为直接的字符串的字符串;
值变成变量标识符。
第二个冒号的语法分析不合理,语法分析有一个异常时期。
如果我们只有一个,我们不会犯错误,以下代码:
Eval ('{name: MyName}')
输出我;
那么,如果我们想解决上面的问题呢我们可以添加一个小括号,使之成为表达式语句,下面的代码:
eval('('({姓名:我
输出一个对象{姓名:我
但是下面的匿名函数和括号不包含在IE中,下面的代码:
var = eval(函数(函数){ } '()');
警报(typeof功能); / /即是未定义的
在标准的浏览器,Chrome和Firefox浏览器的打印功能,但在IE的Jscript引擎,它印刷的定义。在这种情况下,我们可以通过name函数实现它。
eval('function)功能({ });
警报(typeof功能); / /打印功能
当我们使用eval,最常见的方式是Ajax请求,服务器端返回一个字符串格式的数据。我们需要将字符串的格式数据转换成JSON格式。
例如,服务器返回的数据是以下字符串,希望将JSON对象转换如下:
var data =name迈克
console.log(eval((+数据+ ))))
打印对象{名称:迈克
可以/或直接如下
console.log(eval((+{的名字:迈克
我们还需要了解使用eval或陈述,他们所有的变化范围的问题,如使用eval如下:
var I=100;
功能myfunc(name){
console.log(价值是:' +我); / / 100
eval(名称);
console.log(价值是:' +我); / / 10
}
MyFunc('var i = 10;);
在代码中,第一个执行的是100,第二调用eval()方法,将范围缩小到一个函数,所以我变成10。
了解动态方法调用(调用和应用)
Javascript有三个执行机构,一个是eval()指定字符串中的入口函数参数字符串总是在语句执行上下文的当前功能,二是新的(功能){ }在传入的字符串,字符串总是作为一个整体,匿名函数闭包在声明第三条被执行;执行机构是一个函数,通过函数调用操作符()来进行的;除了以上三点,我们现在可以使用电话(或应用)方法(方法)来执行下面的代码动态方法:
函数(名称){
警报(++名称);
}
foo.call(null,'longen '); / /电话打印你好:隆根
foo.apply(null,{ 'tugenhua}); / /电话打印你好:tugenhua
调用()方法与应用()方法相同。它被称为函数,但是第二个参数是不同的。应用程序的第二个参数是数组或参数。
理解调用中的引用和应用
如果我们把普通函数称为对象的方法,例如,我现在有一个常见的函数如下:
函数(){
警报(这个名字);
}
现在我们定义如下2个对象:
var obj1 = {姓名:'obj1};
var obj2 =新的对象();
obj2.name = 'obj2;
现在我们使用这2个对象来调用上面普通函数的一个,如下所示:
foo.call(obj1);
foo.call(obj2);
可以看出,这是第一次,以此印刷,印刷和obj2是第二次。也就是说,第一个该指针指向obj的对象,和第二次指向obj2对象。
下面是代码:
函数(){
警报(这个名字);
}
var obj1 = {姓名:'obj1};
var obj2 =新的对象();
obj2.name = 'obj2;
foo.call(obj1); / / obj1
foo.call(obj2); / / obj2
我们可以在方法调用中查询这个引用以获得当前实例,因此我们也可以使用下面的代码来传输这个引用;
例如,下面的代码:
函数(){
警报(这个名字);
}
函数的MyObject(){
this.name = 'myobject;
}
myobject.prototype.doaction =函数(){
foo.call(本);
}
测试
var OBJ3 =新的MyObject();
obj3.doaction();
上面的代码首先实例化MyObject对象,得到OBJ3实例,然后调用这个方法的一个例子doAction,那么当前的this指针,指向OBJ3实例,并obj3.name = myobject;所谓的foo.call(这),这个指针和OBJ3这个例子,所以警报(这名字);MyObject弹出;
使用相同的方法,我们可以传递参数,代码如下所示:
功能calc_area(W,H){
警报(W * H);
}
函数区域(){
this.name = 'myobject;
}
area.prototype.docalc =功能(V1,V2){
calc_area.call(这,V1,V2);
};
var区域=新区域();
Area.doCalc(10,20);
由于使用了调用方法,调用方法来传递上面的2个参数,但是我们也可以使用应用()方法来调用,我们知道(应用)方法和调用()方法是第二个不同的参数,作为调用方法的参数是一个一个传递,但是第二个参数应用是一个数组或参数,但是它们的函数是一样的;
功能calc_area(W,H){
警报(W * H);
}
函数区域(){
this.name = 'myobject;
}
area.prototype.docalc =功能(V1,V2){
/ / calc_area.call(这,V1,V2);
calc_area.apply(,{ V1,V2 })
};
var区域=新区域();
Area.doCalc(10,20);
了解Javascript对象
的object.defineproperty方法,方法是由ecmascript5,这种方法需要3个参数的属性的对象,需要修改对象的属性名称和描述符对象;属性描述符对象必须是可配置的,可数、可写和价值。设置一个或多个值可以修改相应的特征值。
有2个属性,属性的数据,以及在ECMAscript的访问性能
1。数据属性;
数据属性包含数据值的位置。可以在这个位置读取和写入值。数据属性有4个特性来描述它们的行为。
配置:表明我们是否可以删除的属性,使我们可以重新定义属性,我们是否可以修改属性的属性,或者我们可以修改属性访问器的属性。这个属性值默认为true。
枚举:指示属性是否可以返回通过在循环。此属性值默认为true。
可写:表示是否可以修改属性的值。此属性值默认为true。
值:包含此属性的数据值。从该位置读取属性的值;当写入属性值时,将在该位置保存新值,属性值默认为未定义;
目前,标准的浏览器都支持这种方法,和IE8 -不支持此方法。
例如,我们首先定义一个对象,如下所示:
var
名称:'longen
};
我们可以先报警(人的名字);打印弹出肯定是隆根字符串;
理解可写属性;
现在我们使用的object.defineproperty()修改人的对象的名称属性值的方法,如下:
警报(人的名字); / /隆根
object.defineproperty(人,名字
可写的:false,
价值:tugenhua
});
警报(人的名字); / / tugenhua
person.name = 格雷戈;
警报(人的名字); / / tugenhua
对于上面的代码,当我们设置写为false时,我们不能在修改name属性时修改它,但是如果我将写的设置为true或者直接删除行代码,它可以亲自修改name值:
Object.defineProperty (person, name
可写的:false,
价值:tugenhua
});
警报(人的名字); / / tugenhua
person.name = 格雷戈;
警报(人名。);格雷戈
理解可配置属性
继续上述JS代码如下:
var
名称:'longen
};
警报(人的名字); / /隆根
object.defineproperty(人,名字
可配置:false,
价值:tugenhua
});
警报(人的名字); / / tugenhua
删除person.name;
警报(人的名字); / / tugenhua
当配置设置为false,这意味着名义价值不能被删除,所以在顶上弹出窗口会打印出tugenhua字符串。
但是如果我设置配置真或不直接写这个属性,那么最后person.name弹出的将是不确定的。
var
名称:'longen
};
警报(人的名字); / /隆根
object.defineproperty(人,名字
价值:tugenhua
});
警报(人的名字); / / tugenhua
删除person.name;
警报(人名。)
可枚举属性的认识
可枚举属性指示是否可以返回的数据通过在回路,和默认的是真的,如下:
var
名称:'longen
};
object.defineproperty(人,名字
枚举:真,
价值:tugenhua
});
警报(人的名字); / / tugenhua
对于(var本人){
警报(人{ });可以弹出框
}
如上所述,我们设置了可枚举属性设置为true,如果它被设置为假,在回路中的数据将不会返回数据。
var
名称:'longen
};
object.defineproperty(人,名字
枚举:假,
价值:tugenhua
});
警报(人的名字); / / tugenhua
对于(var本人){
警报(人{ }); /不弹出
}
2。访问属性
访问属性的getter和setter函数,当读访问属性时,将调用getter函数,这个函数负责返回写访问属性的有效值,将调用setter函数和新的价值观的介绍,这个功能是负责如何处理数据,访问也有以下4种特点:
配置:表明我们是否可以删除的属性,使我们可以重新定义属性,我们是否可以修改属性的属性,或者我们可以修改属性访问器的属性。这个属性值默认为true。
枚举:指示属性是否可以返回通过在循环。此属性值默认为true。
获取:读取属性时调用的函数,具有未定义的默认值。
设置:在写入属性时调用的函数,具有未定义的默认值。
以下代码:
var图书{ {
_year:2004,
编辑:1
};
Object.defineProperty(书、年
获取:函数(){
这_year返回;
},
设置:功能(价值){
如果(价值> 2004){
这_year =价值;
this.edit =价值2004;
}
}
});
book.year = 2005;
警报(图书编辑);2
首先我们定义一本书的对象有2个属性,_year和编辑,和初始值的对象的书每年新的值是2005,和今年的属性访问器包含一个getter和setter函数功能,所以第一个将电话设置功能,2005是价值,这是_year后。等于2005,this.edit等于2;
目前,支持object.defineproperty方法包括IE9浏览器运用小记+,+,徒步+浏览器,Chrome和opera12 +;
理解多属性的定义
ecmascript5定义object.defineproperties()方法,该方法可以一次性定义多个属性,该方法需要2个参数,第一个参数是添加或修改的第二个参数属性的对象是一个对象,对象的属性和一个参数需要添加或删除一个属性对应;
以下代码:
var图书{ {
_year:2004,
编辑:1
};
object.defineproperties(书,{
{ _year:
价值:2015
},
编辑:{
价值:2
},
年:{
获取:函数(){
这_year返回;
},
设置:功能(价值){
如果(价值>本。_year){
这_year =价值;
这_year this.edit =价值;
}
}
}
});
如上所述,为图书对象设置了3个属性,其中前两个将覆盖原始图书对象的属性,并添加三个属性;
它确实为对象设置了多个属性,那么现在我们如何读取属性呢
ecmascript5给我们object.getownpropertydescriptor()方法来获得一个给定的属性的描述。该方法接收2个参数,其中属性位于对象和属性名称,需要读取描述符,返回值是一个对象。如果是访问属性,该对象的属性具有可配置、可枚举,获取和设置;如果它的数据属性,对象的属性具有可配置、可枚举,写和价值。
让我们先看看数据属性并获得以下代码:
复制代码代码如下所示:
VaR描述= object.getownpropertydescriptor(书、_year );
console.log(广义);
打印如下:
对象:2015,{价值可写:真的,真的,真的可枚举:可配置:}
它是一个对象,现在值为2015。
但如果我们看一下访问性能,下面的代码:
VaR描述= object.getownpropertydescriptor(书,年);
console.log(广义);
打印如下:
上面有四个属性。
object.getownpropertydescriptor方法,支持这种方法的浏览器:
IE9浏览器运用小记+,+,+ +和徒步,opera12铬;
理解构造器
功能犬(姓名,年龄){
this.name =名称;
this.age =年龄;
this.say =函数(){
警报(这个名字);
}
}
作为构造函数,它与普通函数有以下区别:
1首首字母缩写。为了区分构造函数,函数名需要大写。
2。初始化函数时,需要新的;任何函数,只要它是通过新的初始化,然后他们可以使用它作为一个构造函数;
例如,2个对象实例化如下:
VaR DOG1 =新狗(wangwang1
无功dog2 =新狗(wangwang2
那么我们现在可以打印console.log(dog1.say());打印出来是wangwang1,console.log(dog2.say());并打印出wangwang2;
DOG1和dog2救狗不同的实例,和两个对象有一个构造函数(constructor)属性,这个属性点的狗,下面的代码:
警报(dog1.constructor =狗); / /真的
警报(dog2.constructor =狗); / /真的
同时,实例化的对象是对象的所有实例,可用于检测下列代码实例:
警报(DOG1实例对象); / /真的
警报(dog2实例对象); / /真的
警报(DOG1是狗); / /真的
警报(dog2是狗); / /真的
构造函数是缺点:每个需要重新生成一遍在每一种情况下,如2以上的狗对象实例化,分别与dog2 DOG1,DOG1和dog2有说法,但该方法不相同功能的例子,下面的代码:
警报(dog1.say = dog2。说); / /假
因此,我们需要引入原型模型,原型模型是为了解决一个共享问题,我们创建的每一个函数都有一个原型(原型)属性,这个属性是一个指向对象的指针,而对象是利用真实案例的所有属性和方法,如代码共享,上述转换如下:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
dog1.say();
无功dog2 =新狗();
dog2.say();
警报(dog1.say = dog2。说); / /真的
本刊dog1.say = = = dog2.say,它们共享相同的方法;这是为什么呢
我们首先可以理解原型对象;
不管是什么,只要创建一个函数,将基于一组特定的函数来创建一个原型属性的规则,该属性指向原型对象功能;例如,上述功能是狗,然后创建一个dog.prototype这样一个对象的功能,默认情况下,所有的原型对象自动获得一个构造函数(constructor)属性。
任何实例构造函数将指向该构造函数,原型为例,我们可以确定的isprototypeof对象存在()方法。
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
无功dog2 =新狗();
console.log(Dog.prototype.isPrototypeOf(中)); / /真的
console.log(Dog.prototype.isPrototypeOf(中)); / /真的
也就是说,在每一个实例,有一个指针指向Dog.prototype。ecmascript5增添了一种新的方法,Object.getPrototypeOf();该方法可以返回属性值,或上面的代码:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
无功dog2 =新狗();
console.log(Object.getPrototypeOf(中)=狗。原型); / /真的
console.log(Object.getPrototypeOf(中)。名称); / /旺旺
一个对象的原型可以用object.getprototypeof容易获得(),这是非常重要的在一个继承案件由原型。
浏览器支持此方法是IE9 +,Firefox 3.5 + 5 + 12,Safari,Opera和Chrome +。
每一次的代码读取一个对象的属性,进行搜索,目标是一个给定名称的属性。搜索首先从对象实例本身。如果给定名称的属性是一个实例,则返回该属性的值;如果没有找到,那么它继续寻找原型对象的指针指向,并寻找原型对象与给定名称的属性,如果这个属性是在原型对象中找到,则返回该属性的值。
虽然存储在原型中的值可以通过对象实例的访问,这是不可能改写的值在样机通过对象实例。如果加上实例的属性和属性的名称作为实例原型属性一样,我们创建的实例的属性,这将在原型属性的面具。
例如,下面的代码:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
无功dog2 =新狗();
dog1.name =AA;
console.log(DOG1。名称); / / AA
console.log(dog2。名称); / /旺旺
或者我们只是上面说的,想办法找对象2次,第一次发现有这样的属性,如果这个属性对象的一个实例,实例的属性值直接返回,否则继续在原型中找到的属性值,如果有相应的返回值,否则返回未定义,我们给DOG1名称属性的例子,然后再搜索,然后搜索的名称属性的实例,但名称属性实例dog2搜索或原型;但是如果我们需要找到原型名称的属性,我们可以使用DELETE删除本案名称属性;如下代码:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
无功dog2 =新狗();
dog1.name =AA;
console.log(DOG1。名称); / / AA
console.log(dog2。名称); / /旺旺
删除dog1.name;
console.log(DOG1。名称); / /旺旺
但我们可以用hasownproperty()来检测一个属性是否是一个实例方法,或在一个原型,下面的测试代码:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
无功dog2 =新狗();
console.log(dog1.hasownproperty(名称)); / /假
dog1.name =AA;
console.log(DOG1。名称); / / AA
console.log(dog1.hasownproperty(名称)); / /真的
console.log(dog2。名称); / /旺旺
console.log(dog2.hasownproperty(名称)); / /假
删除dog1.name;
console.log(DOG1。名称); / /旺旺
console.log(dog1.hasownproperty(名称)); / /假
理解原型和运算符
有2种方法来使用,在单独使用,并在for循环使用。当单独使用时,运算符在通过对象访问给定属性时返回true,无论是在实例中还是在原型中,例如,以下代码:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
console.log(名字中); / /真的
dog1.name =AA;
console.log(名字中DOG1); / /真的
在上面的代码中,在实例中还是在原型属性,返回的结果都是真实的,我们可以通过在hasownproperty()来确定属性的方法不是在原型中,我们都知道,是不是在实例或原型中返回true,和的hasownproperty()方法被判断为不在本例中,如果在真实的实例返回,所以我们采取的是不实践;下面的代码包:
功能hasprototypeproperty(对象属性){
返回!object.hasownproperty(ATTR)(属性在对象);
}
下面的测试代码如下所示:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
功能hasprototypeproperty(对象属性){
返回!object.hasownproperty(ATTR)(属性在对象);
}
console.log(hasprototypeproperty(DOG1,'name'); / /真实)的原型
dog1.name =AA;
console.log(hasprototypeproperty(DOG1,'name'); / /假)实例
在
在用于循环,返回都是通过访问对象属性的枚举,其中不仅包括示例中的属性,包括在原型属性;如果在IE8屏蔽方法已在原型,那么IE8 -不会有任何反应;下面的代码:
var obj = { {
说明:函数(){
返回AA;
}
};
(我在为var obj){
如果(我= = toString){
警报(1);
}
}
如果我把toString的tostring22 IE,可以打印出1,否则不执行,这是因为他不会屏蔽实例属性的不可数的原型属性返回的循环,因为原型也有toString方法,在伊江,由于对原型的toString()方法的实现在价值{ } } {枚举标记错误,所以应该跳过这个属性,我们将看不到预警结果。
让所有的实例属性,可以列举的对象,你可以使用Object.keys()ECMAscript 5法。这种方法需要一个对象作为参数,并返回包含所有可枚举属性的字符串数组。
下面的代码显示:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗()
VAR键= object.keys(狗。原型);
console.log(键); / / {的名字
对于上面的代码,键将被保存为数组,它的顺序为。如果我们想得到的所有实例的属性,是否可以列举,我们可以用Object.getOwnPropertyNames()方法。
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
VAR键= object.getownpropertynames(狗。原型);
console.log(键); / / {的名字
Object.keys()和object.getownproperty-names()方法可以用来代替实物,浏览器支持这两种方法是IE9,Firefox 4,Safari 5 +,奥佩拉
12 +铬。
让我们回到原型对象的概念;下面的代码:
函数(狗){ };
dog.prototype = { {
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
console.log(DOG1实例对象); / /真的
console.log(DOG1是狗); / /真的
console.log(dog1.constructor = =狗); / /假
console.log(dog1.constructor = =对象); / /真的
为什么上面的第三行打印错误我们知道,每一个功能的创新将同时创建原型对象,该对象将自动获得构造函数属性,当我们实例化一个对象,这是因为我们没有指定构造函数属性,默认情况下它将重写原型对象的构造函数,物业将成为新的构造函数属性对象,不再指向狗的功能,如果我们要把他和狗的功能,我们可以添加在dog.property代码构造函数属性,如下:
函数(狗){ };
dog.prototype = { {
构造函数:狗,
名称:'wangwang,
年龄:会的,
表示:函数(){
警报(这个名称); / /旺旺
}
}
VaR DOG1 =新狗();
console.log(DOG1实例对象); / /真的
console.log(DOG1是狗); / /真的
console.log(dog1.constructor = =狗); / /真的
理解原型的动态
例如,下面的代码:
函数(狗){ };
VaR DOG1 =新狗();
dog.prototype.say =函数(){
警报(1);
}
dog1.say(1); / /
然后我们实例化一个对象,然后添加一个说原型的方法,然后我们用调用的例子的方法也可以调用,也就是说,实例首先会搜索说的方法,如果不去搜索,那么它将在原型里面搜索方法,如果实现可以找到,否则没有错误,这个方法;
虽然您可以随时向原型添加方法和属性,但修改的方法和属性可以从示例中显示出来,但是如果重写整个原型方法,它将不起作用。
函数(狗){ };
VaR DOG1 =新狗();
dog.prototype = { {
构造函数:'dog,
名称:'dog,
年龄:1,
表示:函数(){
警戒(这个年龄);
}
}
(DOG1。说); / /错误
VaR DOG1 =新狗();
实例化一个对象,该指针指向的原型的一个实例,但是如果重写原型可能是削减与原型对象关系,然后继续调用方法调用不会,如上面的代码,如果我继续实例化狗对象重写原型如下打电话的说法,下面的代码是正常的:
函数(狗){ };
VaR DOG1 =新狗();
dog.prototype = { {
构造函数:'dog,
名称:'dog,
年龄:1,
表示:函数(){
警戒(这个年龄);
}
}
( / / DOG1。说); / /错误
无功dog2 =新狗();
dog2.say(1); / /
认识原型的改写
我们知道从上面的原型可以改写,所以原型的改写问题引起的变化在实例的指针指向原来的原型,也就是说在原型如果遗传操作,通过重写原型将发生变化,因此在实际操作中要小心原型,重写从不同的2个实例代码做出相同的实例构造函数如下:
功能(MyObject){ };
var obj1 =新的MyObject();
myobject.prototype.type = 'myobject;
myobject.prototype.value =AA;
var obj2 =新的MyObject();
myobject.prototype = { {
构造函数:'myobject,
类型:'brid,
价值:'BB'
};
var OBJ3 =新的MyObject();
显示对象属性
警报(obj1。型); / / MyObject
警报(obj2。型); / / MyObject
警报(OBJ3。型); / /鸟
上面的代码:两例obj1和obj2指向相同的原型。修改后的原型,OBJ3指向新的构造函数的原型,和下面的测试代码:
显示关系示例
警报(obj1是MyObject); / /假
警报(obj2实例MyObject); / /假
警报(OBJ3实例MyObject); / /真的
我们可能有误会。为什么obj1和obj2不是MyObject的实例吗从中我们可以看到代码,2的情况下确实是实例MyObject,为什么不是现在现在我们来看一下对象实例构造函数属性和下面的测试代码:
复制代码代码如下所示:
console.log(obj1是obj1。构造函数); / /假
console.log(obj1.constructor = MyObject); / /真的
第一行打印错误。可以看出,对象obj1不是obj1.constructor构造函数,第二排印,真的,在obj1.constructor构造函数是指向MyObject对象,和下面的三行代码:
复制代码代码如下所示:
警报(obj1是MyObject); / /假
Console.log (obj1 instanceof obj1.constructor); / / false
console.log(obj1.constructor = MyObject); / /真的
从上面的三行代码,我们可以得出这样的结论:在原型的改写,obj1.constructor构造函数仍然指向MyObject,但以此不是obj1.constructor构造函数,这是一个例子,以此不是MyObject例。
在Javascript中,构造函数的原型可以重写,这意味着在构造函数实例中丢弃以前的原型:
1。旧的示例使用废弃的原型,并受原型的影响。
2。新创建的实例使用重写原型,受新原型的影响。
了解构造函数重写
以上我们知道原型被重写了。下一步我们将解释的重构是重写,我们将继续以后的研究。让我们先看看构造函数的重写演示,如下所示:
功能(MyObject){ };
var obj1 =新的MyObject();
MyObject =函数(){ };
obj2 var = MyObject新();
console.log(obj1是MyObject); / /假
console.log(obj2实例MyObject); / /真的
console.log(obj1是obj1。构造函数); / /真的
以此作为代码实例化,对象是通过以下MyObject构造函数重写,所以以此不是MyObject的实例。obj2是MyObject例。为什么obj1.constructor obj1的实例吗它表明构造函数的重写不影响实例的继承。
以上是重写构造函数,MyObject不是一个命名的功能。让我们来看看名称函数的重写。代码如下:
功能(MyObject){ };
var obj1 =新的MyObject();
功能(MyObject){ };
var obj2 =新的MyObject();
console.log(obj1是MyObject); / /真的
console.log(obj2实例MyObject); / /真的
console.log(obj1是obj1。构造函数); / /真的
从上面的代码;上面的代码结构,obj1和obj2是2种不同的(MyObject)实例构造函数,但从逻辑的角度看,MyObject()构造函数是覆盖在构造函数的前面,所以obj1和obj2的MyObject二实例构造函数;
所以上面的打印是真的;
原型对象的缺点:
1。省略构造函数参数,默认情况下所有实例都具有相同的属性值和方法,这是不好的,例如,我认为实例不需要拥有属性值,B实例需要有它们的属性值和它们自己的方法,所以原型对象不能满足需求;
2。原型最大的优点是它可以共享属性和方法。但是如果我将一个方法添加到实例化中,我不想在B实例化中添加相应的方法,但是因为原型是共享的,所以还有一种方法来添加一个B实例。
对于第二点,我们可以看看演示如下:
函数(狗){ };
dog.prototype = { {
构造函数:狗,
名称:AA,
值:{aa
表示:函数(){
警报(这个名字);
}
}
VaR DOG1 =新狗();
dog1.values.push(CC);
console.log(DOG1。值); / / {AA
无功dog2 =新狗();
console.log(dog2。值); / / {AA
在代码中,我添加了一个价值CC为DOG1实例化的值,然后原型成为
在{ AA、BB、CC },如果dog2实例化,然后继续打印dog2.values值为{ AA,BB,CC };
理解构造函数和原型模式的组合
构造函数用于定义实例私有属性,而原型模式可以定义共享属性和方法,这些属性和方法可以节省内存,同时具有自己的私有属性和方法,这是使用最广泛的方法,例如,以下代码:
功能犬(姓名,年龄){
this.name =名称;
this.age =年龄;
this.values = {AA
};
dog.prototype = { {
构造函数:狗,
表示:函数(){
警报(这个名字);
}
}
VaR DOG1 =新狗(中
dog1.values.push(CC);
console.log(DOG1。值); / / {AA
无功dog2 =新狗(dog2
console.log(dog2。值); / / {AA
console.log(dog1.values = dog2。值); / /假
console.log(dog1.say = dog2。说); / /真的
还有很多其他的机型,我不一一介绍。如果你需要知道,你可以看看Javascript设计模式的书。
理解Javascript的继承性
1:原型链
原型链ECMAscript的概念,与原型链作为继承的主要方法,其目的是建立一个引用类型从上述类型继承另一个引用的属性和方法,我们了解到原型和实例的关系,每一种都有一个原型对象,原型对象包含一个指向构造函数和指针实例包含一个指针指向原型对象的内部指针实例构造函数本身没有什么关系,比如我们现在有一个原型对象是另一个类型的一个实例,原型对象将包含一个指针指向另一个指针。另外还包含了另一个指向另一个构造函数的指针,然后逐渐成为原型链;
以下代码:
函数动物(){
this.name =AA;
}
animal.prototype.fly =函数(){
返回this.name;
};
函数狗(){
this.value =BB;
}
dog.prototype =新的动物();
dog.prototype.fly =函数(){
返回this.name;
};
VaR DOG1 =新狗();
Console.log((DOG1。飞)); / / AA
上面的代码:我们先定义一个动物的构造函数,它有一个名字= AA性能;与原型定义了一个方法飞;然后我定义的狗这样一个构造函数,让原型是等同于动物的一个实例,也用这样的方式让狗构造函数继承动物因此性能和方法,狗有动物这个构造函数的所有属性和方法,然后他们飞法狗的方法定义,它将涵盖动物原型,和指针或指向的动物,所以this.name = AA;所以当我们实例化的狗,参观dog1.fly()方法,打印AA;
正如我们在代码中所知道的,我们知道,如果您想从b继承a,那么继承可以像这样编写:
a.prototype =新的B();
和狗的飞法实际上是原型动物的飞行方式重写;我们继续看DOG1实例和狗和动物之间的关系;下面的代码:
console.log(DOG1是狗); / /真的
console.log(DOG1是动物); / /真的
console.log(DOG1是DOG1。构造函数); / /真的
console.log(dog1.constructor =狗); / /假
console.log(dog1.constructor =动物); / /真的
你可以看到,DOG1是狗和动物的一个例子。DOG1仍然指向dog1.constructor构造函数,但DOG1不再指向狗的实例,但点的动物,这是因为dog1.constructor改写。
通过原型的继承,我们看到dog1.fly()方法,体验下面的搜索步骤,首先搜索的情况下没有飞这个方法,然后寻找狗的原型有这种方法,最遗憾的搜索动物原型;最后将继续看对象有这样的方式,我们都知道所有的对象是对象的一个实例,我们可以看到:
console.log(DOG1实例对象); / /真的
所有函数的原型是对象的一个实例的默认继承,所以默认原型有一个内部指针和Object.prototype;也就是说一个自定义类型都继承和toString()方法和价值()的根本原因的方法,我们知道,原型和测试用例可以用在除了在实例之间的关系。我们还可以使用isprototypeof()方法,下面的代码:
console.log(Object.prototype.isPrototypeOf(中)); / /真的
console.log(Dog.prototype.isPrototypeOf(中)); / /真的
console.log(Animal.prototype.isPrototypeOf(中)); / /真的
注:1。亚型有时需要覆盖的方法或方式supertyping,添加不存在的类型。添加原型的方法必须用原型化的方法来代替。
函数动物(){
this.name =AA;
}
animal.prototype.fly =函数(){
返回this.name;
};
函数狗(){
this.value =BB;
}
动物继承
dog.prototype =新的动物();
重写原型/方法
dog.prototype.fly =函数(){
返回this.name;
};
在它的/中添加一个新方法
dog.prototype.cry =函数(){
返回false;
};
VaR DOG1 =新狗();
Console.log((DOG1。飞)); / / AA
Console.log((DOG1。哭)); / /假
2。当继承原型链时,无法使用对象的文字数量创建原型方法,因为这将重写原型链;下面的代码:
函数动物(){
this.name =AA;
}
animal.prototype.fly =函数(){
返回this.name;
};
函数狗(){
this.value =BB;
}
动物继承
dog.prototype =新的动物();
重写原型/方法
dog.prototype = { {
函数(){
返回this.name;
},
在它的/中添加一个新方法
函数(){
返回false;
}
};
VaR DOG1 =新狗();
Console.log((DOG1。飞)); / /未定义
console.log(DOG1是动物); / /假
如上面的代码所示:dog1.fly打印()打印出来的定义是动物错误的打印方法中,原型对象的文字改写方法的实现方法不能使用,因为它会降低为动物,原型的关系,现在是不是动物的一个实例中,DOG1飞没有这种方法的例子,因为它是不遗传的;
使用原型链的缺点如下:
1。我们都知道原型链的所有属性和方法都是共享的例子,虽然原型可以解决共享的问题,这是他的优点,也是他的缺点,例如,我给一个属性加一个A实例,当我实例化B时,B也有这个属性,下面的代码:
函数动物(){
this.values = {AA
}
函数(狗){ };
dog.prototype =新的动物();
VaR DOG1 =新狗();
dog1.values.push(CC); / /添加CC值
console.log(DOG1。值); / / { AA、BB、CC };
无功dog2 =新狗();
console.log(dog2。值); / / { AA、BB、CC };
2。在创建子类型的实例时,不能将参数传递给超级类型中的构造函数。
理解借用构造函数
对于以上2点,我们需要借用构造函数函数。基本思想是在子类型构造函数内调用超级类型构造函数,因此我们可以使用调用或应用程序调用以下代码。
函数动物(){
this.values = {AA
}
函数狗(){
从动物身上继承的狗
Animal.call(本);
};
VaR DOG1 =新狗();
dog1.values.push(CC); / /添加CC值
console.log(DOG1。值); / / { 'AA','BB','cc}
无功dog2 =新狗();
console.log(dog2。值); / / { 'AA','BB' }
上面的代码:使用电话或申请实现继承,你可以得到你自己的复制值,因此打印出来的'bb'and'cc'} { AA,首次印刷{ AA and'bb}二倍。
我们也可以传递参数,代码如下所示:
功能动物(名称){
this.values = {AA
this.name =名称;
}
函数狗(){
从动物身上继承的狗
Animal.call(这一点,dog22 );
this.age = 22;
};
VaR DOG1 =新狗();
console.log(DOG1。名称); / / dog22
console.log(DOG1。年龄); / / 22
但是,施工人员的借用也有不足之处。
借用构造函数的缺点:
1。构造函数不能重用;
2。该属性或方法在父类定义的不可见的亚型,所有类型只能使用构造函数模式。
了解组合继承
上述2个问题,我们可以考虑使用继承的实现方式是指一个组合模型一起使用构造函数模式的思路是:使用原型链的原型属性和方法的继承,并用结构函数的方式实现的属性实例的继承;通过在函数原型中定义的方法的重用,并能确保每个实例都有自己的特性;下面的代码:
功能动物(名称){
this.values = {AA
this.name =名称;
}
animal.prototype.sayname =函数(){
返回this.name;
}
功能犬(姓名,年龄){
狗继承的属性
Animal.call(这名字);
this.age =年龄;
};
继承方法
dog.prototype =新的动物();
dog.prototype.constructor =狗;
dog.prototype.sayage =函数(){
返回this.age;
}
VaR DOG1 =新狗(dog111
dog1.values.push(CC);
console.log(DOG1。值); / / { 'AA','BB','cc}
Console.log((DOG1。sayage)); / / 12
Console.log((DOG1。sayname)); / / dog111
无功dog2 =新狗(dog222
console.log(dog2。值); / / { 'AA','BB' }
Console.log((dog2。sayage)); / / 14
Console.log((dog2。sayname)); / / dog222
上面的代码:动物的构造函数定义了2个属性名和值,sayname动物原型的定义方法;狗构造函数继承动物传递一个参数的名称,然后定义自己的年龄参数,然后dog.prototpye =新的动物狗的方式来实例化、继承和动物,所以不同狗的设计实例,分别有自己的属性,但也有相同的方法,又节省了空间;
在通过方法继承上面的代码之后,构造函数重写为狗点,如下代码:
dog.prototype.constructor =狗;
因此,最后的狗实例对象的构造函数直接指向狗,我们可以打印以下内容:
console.log(dog1.constructor =狗) / /真的
如果我们对上述dog.prototype.constructor =狗,然后
console.log(dog1.constructor =狗) / /假
它返回false。
理解原型继承
其思想是创建一个临时构造函数,然后使用它作为构造函数的原型的对象,最后返回到临时构造函数的一个新实例。
函数对象(obj){
函数(f){ };
f.prototype = obj;
返回新的f();
}
我们现在可以做一个演示,如下所示:
var
名称:AA,
朋友:{ 'zhangsan ','lisi ','wangwu}
};
无功anthorperson =对象(人);
anthorperson.name =BB;
Anthorperson.firends.push(zhaoliu );
无功aperson2 =对象(人);
aperson2.name = 'cc;
aperson2.firends.push(龙恩);
console.log(人。朋友); / / {zhangsan
这样一个原型继承必须有一个对象作为另一个对象的基础,如果有这样一个对象,它可以将它传递给对象()函数。
object.create ecmascript5(新)标准方法继承了原型,这种方法需要2个参数,第一个是新的对象作为对象的原型,第二个参数是可选的,意思是定义额外的属性,如代码对象的新对象:
var
名称:AA,
朋友:{ 'zhangsan ','lisi ','wangwu}
};
无功anthorperson = object.create(人);
anthorperson.name =BB;
Anthorperson.firends.push(zhaoliu );
无功bperson = object.create(人);
bperson.name = 'longen;
Bperson.firends.push(龙恩);
console.log(人。朋友); / / {zhangsan
该object.create第二参数()方法作为object.defineproperties二参数格式相同()方法:每个属性是由其自身的广义定义。这样指定的属性将覆盖在原型对象的同名属性。
var
名称:AA,
朋友:{ 'zhangsan ','lisi ','wangwu}
};
无功anthorperson = object.create(人,{
名称:{
价值:'BB'
}
});
console.log(anthorperson。名称); / / BB
目前,该浏览器支持的object.create()方法包括IE9浏览器运用小记+,+,+ +和徒步,opera12铬;
理解寄生组合遗传
我们理解组合继承,合并继承的Javascript是最常用的继承方式,但它也有缺点,它将调用两个超级类型构造函数调用,第一次在继承属性中,第二次继承方法调用,下面的代码:
功能动物(名称){
this.values = {AA
this.name =名称;
}
animal.prototype.sayname =函数(){
返回this.name;
}
功能犬(姓名,年龄){
狗继承的属性
Animal.call(这名字);
this.age =年龄;
};
继承方法
dog.prototype =新的动物();
dog.prototype.constructor =狗;
dog.prototype.sayage =函数(){
返回this.age;
}
如上述的继承;animal.call(这名字);
与继承法dog.prototype =新的动物();
当第一个继承的属性将继承名称和值的动物时,当第二个调用继承方法时,这也在新的对象属性中创建了一个名称和值的实例,这个属性将在继承之前创建一个覆盖,因此我们可以使用组合寄生继承;
寄生组合继承的思想是继承属性通过使用构造函数和继承法通过原型链的混合形式。本质上,寄生继承习惯在超类继承的原型,并分配到各亚型的原型。寄生组合的基本模式是以下代码:
功能inheritprototype(狗,动物){
var原型=对象(动物原型);
prototype.constructor =狗;
dog.prototype =原型;
}
inheritprototype方法接受2个参数的构造函数,亚型和超类构造函数,创建一个副本的超级型第一里面的功能。第二步是添加构造函数属性创建的副本来弥补,因为原型的改写了默认构造函数的特性。
最后一步是将新创建的对象(副本)分配到子类型的原型中。通过这种方式,我们可以通过调用继承原型()函数的语句替换以前示例中的子类型原型的语句。
下面的代码显示:
函数对象(obj){
函数(f){ };
f.prototype = obj;
返回新的f();
}
功能inheritprototype(狗,动物){
var原型=对象(动物原型);
prototype.constructor =狗;
dog.prototype =原型;
}
功能动物(名称){
this.values = {AA
this.name =名称;
}
animal.prototype.sayname =函数(){
返回this.name;
}
功能犬(姓名,年龄){
狗继承的属性
Animal.call(这名字);
this.age =年龄;
};
InheritPrototype(狗,动物);
VaR DOG1 =新狗(旺旺
dog1.values.push(CC);
Console.log((DOG1。sayname)); / /旺旺
console.log(DOG1。值); / / {AA
无功dog2 =新狗(二战
Console.log((dog2。sayname)); / /二战
console.log(dog2。值); / / {AA
一个类型被称为只有一次利用寄生组合继承;这是他们的优势!