js实例教程-JavaScript的ES3,ES5,ES6三种实现继承方式的教程

发布时间:2018-11-30 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了js实例教程-JavaScript的ES3,ES5,ES6三种实现继承方式的教程脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过。

ES3 继承

在JavaScript中,所谓的类就是函数,函数就是类。一般情况下,我们在函数的PRototyPE上面定义方法,因为这样所有类的实例都可以公用这些方法;在函数内部(构造函数)中初始化属性,这样所有类的实例的属性都是相互隔离的。 我们定义ClassA和ClassB两个类,想让ClassB继承自ClassA。 ClassA代码如下所示:

 function ClassA(name, age) {     this.name = name;     this.age = age; }  ClassA.prototype.sayName = function () {     console.LOG(this.name); };  ClassA.prototype.sayAge = function () {     console.log(this.age); };

ClassA构造函数内部定义了name和age两个属性,并且在其原型上定义了sayName和sayAage两个方法。 ClassB如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; }

ClassB新增了job属性,我们在其构造函数中执行ClassA.apply(this, [name, age]);,相当于在Java类的构造函数中通过super()调用父类的构造函数以初始化相关属性。

此时我们可以通过VAR b = new ClassB(“sunqun”, 28, “developer”);进行实例化,并可以访问b.name、b.age、b.job三个属性,但此时b还不能访问ClassA中定义的sayName和sayAage两个方法。

然后我们新增代码ClassB.prototype = ClassA.prototype;,此时ClassB的代码如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } //新增 ClassB.prototype = ClassA.prototype;

当执行var b = new ClassB(“sunqun”, 28, “developer”);时,b.__proto__指向的是ClassB.prototype,由于通过新增的代码已经将ClassB.prototype指向了ClassA.prototype,所以此时b.__proto__指向了ClassA.prototype。这样当执行b.sayName()时,会执行b.__proto__.sayName(),即最终执行了ClassA.prototype.sayName(),这样ClassB的实例就能调用ClassA中方法了。

此时我们想为ClassB新增加一个sayJob方法用于输出job属性的值,如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } ClassB.prototype = ClassA.prototype; //新增 ClassB.prototype.sayJob = function(){     console.log(this.job); };

此时问题出现了,我们为ClassB.prototype添加sayJob方法时,其实修改了ClassA.prototype,这样会导致ClassA所有的实例也都有了sayJob方法,这显然不是我们期望的。 为了解决这个问题,我们再次修改ClassB的代码,如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } // ClassB.prototype = ClassA.prototype; //修改 ClassB.prototype = new ClassA(); ClassB.prototype.constructor = ClassB; ClassB.prototype.sayJob = function(){     console.log(this.job); };

我们通过执行ClassB.prototype = new ClassA();将ClassA实例化的对象作为ClassB的prototype,这样ClassB仍然能够使用ClassA中定义的方法,但是ClassB.prototype已经和ClassA.prototype完全隔离了。

我们的目的达到了,我们可以随意向ClassB.prototype添加我们想要的方法了。有个细节需要注意,ClassB.prototype = new ClassA();会导致ClassB.prototype.constructor指向ClassA的实例化对象,为此我们通过ClassB.prototype.constructor = ClassB;解决这个问题。

关于此处为什么要设置.constructor可参见这篇博客
https://blog.csdn.net/c_kITe/article/details/78484191

一切貌似完美的解决了,但是这种实现还是存在隐患。我们在执行ClassB.prototype = new ClassA();的时候,给ClassA传递的是空参数,但是ClassA的构造函数默认参数是有值的,可能会在构造函数中对传入的参数进行各种处理,传递空参数很有可能导致报错(当然本示例中的ClassA不会)。于是我们再次修改ClassB的代码如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } //修改 function ClassMiddle() {  } ClassMiddle.prototype = ClassA.prototype; ClassB.prototype = new ClassMiddle(); ClassB.prototype.constructor = ClassB; ClassB.prototype.sayJob = function () {     console.log(this.job); };

这次我们引入了一个不需要形参的函数ClassMiddle作为ClassB和ClassA之间的中间桥梁。

1. ClassMiddle.prototype = ClassA.prototype;: 将ClassMiddle.prototype指向ClassA.prototype,这样ClassMiddle可以访问ClassA中定义的方法。

2. ClassB.prototype = new ClassMiddle();: 将ClassMiddle的实例化对象赋值给ClassB.prototype,这样就相当于执行了ClassB.prototype.__proto__ = ClassMiddle.prototype;,所以ClassB就能使用ClassMiddle中定义的方法,又因为ClassMiddle.prototype指向了ClassA.prototype,所以ClassB.prototype.__proto__也指向了ClassA.prototype,这样ClassB能使用ClassA中定义的方法。

以上思路的精妙之处在于ClassMiddle是无参的,它起到了ClassB和ClassA之间的中间桥梁的作用。 现在我们为ClassA添加一些静态属性和方法,ClassA新增如下代码:

 ...  //为ClassA添加静态属性 ClassA.staticValue = "static value";  //为ClassA添加静态方法 ClassA.getStaticValue = function() {     return ClassA.staticValue; }; ClassA.setStaticValue = function(value) {     ClassA.staticValue = value; };

静态属性和方法不属于某一个实例,而是属于类本身。ClassA.prototype上面定义的方法是实例方法,不是静态的。静态属性和方法是直接添加在ClassA上的。 为了使ClassB也能继承ClassA的静态属性和方法,我们需要为ClassB添加如下代码:

 ...  //ClassB继承ClassA的静态属性和方法 for (var p in ClassA) {     if (ClassA.hasOwnProperty(p)) {         ClassB[p] = ClassA[p];     } }

我们最终可以将上述继承代码的公共部分抽离成一个extendsClass方法,如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     function ClassMiddle() {      }     ClassMiddle.prototype = Father.prototype;     Child.prototype = new ClassMiddle();     Child.prototype.constructor = Child;      //继承父类的静态属性和方法     for (var p in Father) {         if (Father.hasOwnProperty(p)) {             Child[p] = Father[p];         }     } }

我们只需要执行extendsClass(ClassB, ClassA);就可以完成大部分继承的逻辑。 最终ClassA的完整代码如下所示:

 function ClassA(name, age) {     this.name = name;     this.age = age; }  ClassA.prototype.sayName = function() {     console.log(this.name); };  ClassA.prototype.sayAge = function() {     console.log(this.age); };  ClassA.staticValue = "static value";  ClassA.getStaticValue = function() {     return ClassA.staticValue; };  ClassA.setStaticValue = function(value) {     ClassA.staticValue = value; };

ClassB的完整代码如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; }  extendsClass(ClassB, ClassA);  ClassB.prototype.sayJob = function() {     console.log(this.job); };

ES5继承

ES5.1规范中新增了Object.create()方法,该方法会传入一个对象,然后会返回一个对象,返回的对象的原型指向传入的对象,比如执行代码var output = Object.create(input),相当于执行代码output.__proto__ = input;,output的原型是input。我们可以简化之前的代码,不再需要ClassMiddle,只需要执行ClassB.prototype = Object.create(ClassA.prototype);即可,相当于执行代码ClassB.prototype.__proto__ = ClassA.prototype;。

而且ES5.1中新增了Object.keys()方法用以获取对象自身的属性数组,我们可以用该方法简化继承父类静态属性和方法的过程。

根据以上两点,我们修改extendsClass方法如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     Child.prototype = Object.create(Father.prototype);     Child.prototype.constructor = Child;      //继承父类的静态属性和方法     Object.keys(Father).for@R_512_2428@(function(key) {         Child[key] = Father[key];     }); }

ES6 继承

我们之前提到,ES6规范定义了Object.prototype.proto属性,该属性既可读又可写,通过__proto__属性我们可以直接指定对象的原型。于是在ES6中我们将extendsClass修改为如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     Child.prototype.__proto__ = Father.prototype;//暴力直接,利用__proto__属性设置对象的原型      //继承父类的静态属性和方法     Child.__proto__ = Father; }

直接修改对象的__proto__属性值不是最佳选择,ES6规范中还定义了Object.setPrototypeOf()方法,通过执行Object.setPrototypeOf(b, a)会将a对象作为b对象的原型,即相当于执行了b.__proto__ = a;。为此我们利用该方法再次精简我们的extendsClass方法,如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     Object.setPrototypeOf(Child.prototype, Father.prototype);      //继承父类的静态属性和方法     Object.setPrototypeOf(Child, Father); }

Object.setPrototypeOf(Child.prototype, Father.prototype);相当于执行代码Child.prototype.__proto__ = Father.prototype;,使得Child能够继承Father中的实例属性和方法。

Object.setPrototypeOf(Child, Father);相当于执行代码Child.__proto__ = Father;,使得Child能够继承Father中的静态属性和方法。

由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的,这不仅仅限于 obj.__proto__ = ... 语句上的时间花费,而且可能会延伸到任何代码,那些可以访问任何[[Prototype]]已被更改的对象的代码。如果你关心性能,你应该避免设置一个对象的 [[Prototype]]。相反,你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。

ES6中引入了class关键字,可以用class直接定义类,通过extends关键字实现类的继承,还可以通过static关键字定义类的静态方法。

我们用class等关键字重新实现ClassA和ClassB的代码,如下所示:

 class ClassA{     constructor(name, age){         this.name = name;         this.age = age;     }      sayName(){         console.log(this.name);     }      sayAge(){         console.log(this.age);     }      static getStaticValue(){         return ClassA.staticValue;     }      static setStaticValue(value){         ClassA.staticValue = value;     } }  ClassA.staticValue = "static value";  class ClassB extends ClassA{     constructor(name, age, job){         super(name, age);         this.job = job;     }      sayJob(){         console.log(this.job);     } }

ES6中不能通过static定义类的静态属性,我们可以直接通过ClassA.staticValue = "static value";定义类的静态属性。

需要注意的是,class关键字只是原型的语法糖,JavaScript继承仍然是基于原型实现的。

并不是所有的浏览器都支持class关键字,在生产环境中,我们可以编写ES6的代码,然后用Babel或TypeScript将其编译为ES5等主流浏览器支持的语法格式。

ES6 Class和之前几种继承区别

一个很重要的区别在于, ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面, 例如上面的说的例子

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; }

ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

总结

执行var x = new X();时,浏览器会执行x.__proto__ = X.prototype,会将实例化对象的原型设置为对应的类的prototype对象。

实现类继承的关键是Child.prototype.__proto__ = Father.prototype;,这样会将Father.prototype作为Child.prototype的原型。Object.prototype.__proto__属性是在ES6规范中所引入的,为了在ES3和ES5中需要通过各种方式模拟实现对Object.prototype.__proto__进行赋值。

通过执行Child.__proto__ = Father;可以实现继承父类的静态属性和方法。

@H_341_126@

ES3 继承

在JavaScript中,所谓的类就是函数,函数就是类。一般情况下,我们在函数的prototype上面定义方法,因为这样所有类的实例都可以公用这些方法;在函数内部(构造函数)中初始化属性,这样所有类的实例的属性都是相互隔离的。 我们定义ClassA和ClassB两个类,想让ClassB继承自ClassA。 ClassA代码如下所示:

 function ClassA(name, age) {     this.name = name;     this.age = age; }  ClassA.prototype.sayName = function () {     console.log(this.name); };  ClassA.prototype.sayAge = function () {     console.log(this.age); };

ClassA构造函数内部定义了name和age两个属性,并且在其原型上定义了sayName和sayAage两个方法。 ClassB如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; }

ClassB新增了job属性,我们在其构造函数中执行ClassA.apply(this, [name, age]);,相当于在Java类的构造函数中通过super()调用父类的构造函数以初始化相关属性。

此时我们可以通过var b = new ClassB(“sunqun”, 28, “developer”);进行实例化,并可以访问b.name、b.age、b.job三个属性,但此时b还不能访问ClassA中定义的sayName和sayAage两个方法。

然后我们新增代码ClassB.prototype = ClassA.prototype;,此时ClassB的代码如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } //新增 ClassB.prototype = ClassA.prototype;

当执行var b = new ClassB(“sunqun”, 28, “developer”);时,b.__proto__指向的是ClassB.prototype,由于通过新增的代码已经将ClassB.prototype指向了ClassA.prototype,所以此时b.__proto__指向了ClassA.prototype。这样当执行b.sayName()时,会执行b.__proto__.sayName(),即最终执行了ClassA.prototype.sayName(),这样ClassB的实例就能调用ClassA中方法了。

此时我们想为ClassB新增加一个sayJob方法用于输出job属性的值,如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } ClassB.prototype = ClassA.prototype; //新增 ClassB.prototype.sayJob = function(){     console.log(this.job); };

此时问题出现了,我们为ClassB.prototype添加sayJob方法时,其实修改了ClassA.prototype,这样会导致ClassA所有的实例也都有了sayJob方法,这显然不是我们期望的。 为了解决这个问题,我们再次修改ClassB的代码,如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } // ClassB.prototype = ClassA.prototype; //修改 ClassB.prototype = new ClassA(); ClassB.prototype.constructor = ClassB; ClassB.prototype.sayJob = function(){     console.log(this.job); };

我们通过执行ClassB.prototype = new ClassA();将ClassA实例化的对象作为ClassB的prototype,这样ClassB仍然能够使用ClassA中定义的方法,但是ClassB.prototype已经和ClassA.prototype完全隔离了。

我们的目的达到了,我们可以随意向ClassB.prototype添加我们想要的方法了。有个细节需要注意,ClassB.prototype = new ClassA();会导致ClassB.prototype.constructor指向ClassA的实例化对象,为此我们通过ClassB.prototype.constructor = ClassB;解决这个问题。

关于此处为什么要设置.constructor可参见这篇博客
https://blog.csdn.net/c_kite/article/details/78484191

一切貌似完美的解决了,但是这种实现还是存在隐患。我们在执行ClassB.prototype = new ClassA();的时候,给ClassA传递的是空参数,但是ClassA的构造函数默认参数是有值的,可能会在构造函数中对传入的参数进行各种处理,传递空参数很有可能导致报错(当然本示例中的ClassA不会)。于是我们再次修改ClassB的代码如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; } //修改 function ClassMiddle() {  } ClassMiddle.prototype = ClassA.prototype; ClassB.prototype = new ClassMiddle(); ClassB.prototype.constructor = ClassB; ClassB.prototype.sayJob = function () {     console.log(this.job); };

这次我们引入了一个不需要形参的函数ClassMiddle作为ClassB和ClassA之间的中间桥梁。

1. ClassMiddle.prototype = ClassA.prototype;: 将ClassMiddle.prototype指向ClassA.prototype,这样ClassMiddle可以访问ClassA中定义的方法。

2. ClassB.prototype = new ClassMiddle();: 将ClassMiddle的实例化对象赋值给ClassB.prototype,这样就相当于执行了ClassB.prototype.__proto__ = ClassMiddle.prototype;,所以ClassB就能使用ClassMiddle中定义的方法,又因为ClassMiddle.prototype指向了ClassA.prototype,所以ClassB.prototype.__proto__也指向了ClassA.prototype,这样ClassB能使用ClassA中定义的方法。

以上思路的精妙之处在于ClassMiddle是无参的,它起到了ClassB和ClassA之间的中间桥梁的作用。 现在我们为ClassA添加一些静态属性和方法,ClassA新增如下代码:

 ...  //为ClassA添加静态属性 ClassA.staticValue = "static value";  //为ClassA添加静态方法 ClassA.getStaticValue = function() {     return ClassA.staticValue; }; ClassA.setStaticValue = function(value) {     ClassA.staticValue = value; };

静态属性和方法不属于某一个实例,而是属于类本身。ClassA.prototype上面定义的方法是实例方法,不是静态的。静态属性和方法是直接添加在ClassA上的。 为了使ClassB也能继承ClassA的静态属性和方法,我们需要为ClassB添加如下代码:

 ...  //ClassB继承ClassA的静态属性和方法 for (var p in ClassA) {     if (ClassA.hasOwnProperty(p)) {         ClassB[p] = ClassA[p];     } }

我们最终可以将上述继承代码的公共部分抽离成一个extendsClass方法,如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     function ClassMiddle() {      }     ClassMiddle.prototype = Father.prototype;     Child.prototype = new ClassMiddle();     Child.prototype.constructor = Child;      //继承父类的静态属性和方法     for (var p in Father) {         if (Father.hasOwnProperty(p)) {             Child[p] = Father[p];         }     } }

我们只需要执行extendsClass(ClassB, ClassA);就可以完成大部分继承的逻辑。 最终ClassA的完整代码如下所示:

 function ClassA(name, age) {     this.name = name;     this.age = age; }  ClassA.prototype.sayName = function() {     console.log(this.name); };  ClassA.prototype.sayAge = function() {     console.log(this.age); };  ClassA.staticValue = "static value";  ClassA.getStaticValue = function() {     return ClassA.staticValue; };  ClassA.setStaticValue = function(value) {     ClassA.staticValue = value; };

ClassB的完整代码如下所示:

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; }  extendsClass(ClassB, ClassA);  ClassB.prototype.sayJob = function() {     console.log(this.job); };

ES5继承

ES5.1规范中新增了Object.create()方法,该方法会传入一个对象,然后会返回一个对象,返回的对象的原型指向传入的对象,比如执行代码var output = Object.create(input),相当于执行代码output.__proto__ = input;,output的原型是input。我们可以简化之前的代码,不再需要ClassMiddle,只需要执行ClassB.prototype = Object.create(ClassA.prototype);即可,相当于执行代码ClassB.prototype.__proto__ = ClassA.prototype;。

而且ES5.1中新增了Object.keys()方法用以获取对象自身的属性数组,我们可以用该方法简化继承父类静态属性和方法的过程。

根据以上两点,我们修改extendsClass方法如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     Child.prototype = Object.create(Father.prototype);     Child.prototype.constructor = Child;      //继承父类的静态属性和方法     Object.keys(Father).forEach(function(key) {         Child[key] = Father[key];     }); }

ES6 继承

我们之前提到,ES6规范定义了Object.prototype.proto属性,该属性既可读又可写,通过__proto__属性我们可以直接指定对象的原型。于是在ES6中我们将extendsClass修改为如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     Child.prototype.__proto__ = Father.prototype;//暴力直接,利用__proto__属性设置对象的原型      //继承父类的静态属性和方法     Child.__proto__ = Father; }

直接修改对象的__proto__属性值不是最佳选择,ES6规范中还定义了Object.setPrototypeOf()方法,通过执行Object.setPrototypeOf(b, a)会将a对象作为b对象的原型,即相当于执行了b.__proto__ = a;。为此我们利用该方法再次精简我们的extendsClass方法,如下所示:

 function extendsClass(Child, Father) {     //继承父类prototype中定义的实例属性和方法     Object.setPrototypeOf(Child.prototype, Father.prototype);      //继承父类的静态属性和方法     Object.setPrototypeOf(Child, Father); }

Object.setPrototypeOf(Child.prototype, Father.prototype);相当于执行代码Child.prototype.__proto__ = Father.prototype;,使得Child能够继承Father中的实例属性和方法。

Object.setPrototypeOf(Child, Father);相当于执行代码Child.__proto__ = Father;,使得Child能够继承Father中的静态属性和方法。

由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的,这不仅仅限于 obj.__proto__ = ... 语句上的时间花费,而且可能会延伸到任何代码,那些可以访问任何[[Prototype]]已被更改的对象的代码。如果你关心性能,你应该避免设置一个对象的 [[Prototype]]。相反,你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。

ES6中引入了class关键字,可以用class直接定义类,通过extends关键字实现类的继承,还可以通过static关键字定义类的静态方法。

我们用class等关键字重新实现ClassA和ClassB的代码,如下所示:

 class ClassA{     constructor(name, age){         this.name = name;         this.age = age;     }      sayName(){         console.log(this.name);     }      sayAge(){         console.log(this.age);     }      static getStaticValue(){         return ClassA.staticValue;     }      static setStaticValue(value){         ClassA.staticValue = value;     } }  ClassA.staticValue = "static value";  class ClassB extends ClassA{     constructor(name, age, job){         super(name, age);         this.job = job;     }      sayJob(){         console.log(this.job);     } }

ES6中不能通过static定义类的静态属性,我们可以直接通过ClassA.staticValue = "static value";定义类的静态属性。

需要注意的是,class关键字只是原型的语法糖,JavaScript继承仍然是基于原型实现的。

并不是所有的浏览器都支持class关键字,在生产环境中,我们可以编写ES6的代码,然后用Babel或TypeScript将其编译为ES5等主流浏览器支持的语法格式。

ES6 Class和之前几种继承区别

一个很重要的区别在于, ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面, 例如上面的说的例子

 function ClassB(name, age, job) {     ClassA.apply(this, [name, age]);     this.job = job; }

ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

总结

执行var x = new X();时,浏览器会执行x.__proto__ = X.prototype,会将实例化对象的原型设置为对应的类的prototype对象。

实现类继承的关键是Child.prototype.__proto__ = Father.prototype;,这样会将Father.prototype作为Child.prototype的原型。Object.prototype.__proto__属性是在ES6规范中所引入的,为了在ES3和ES5中需要通过各种方式模拟实现对Object.prototype.__proto__进行赋值。

通过执行Child.__proto__ = Father;可以实现继承父类的静态属性和方法。

觉得可用,就经常来吧!Javascript技巧 脚本宝典 欢迎评论哦! js技巧,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的js实例教程-JavaScript的ES3,ES5,ES6三种实现继承方式的教程全部内容,希望文章能够帮你解决js实例教程-JavaScript的ES3,ES5,ES6三种实现继承方式的教程所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。