一、this

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

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

1.0、猜猜答案

代码如下:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>JavaScript this</title>
  6. </head>
  7. <body>
  8. <h2>JavaScript this</h2>
  9. <input type="button" value="按钮A" id="btnA"/>
  10. <input type="button" value="按钮B" id="btnB" onclick="sayHello()"/>
  11. <script type="text/javascript">
  12. function sayHello(){
  13. alert("Hello Button!");
  14. console.log(this);
  15. };
  16.  
  17. document.getElementById("btnA").onclick=sayHello;
  18.  
  19. </script>
  20. </body>
  21. </html>

请问输出到控制台的结果是什么?相同吗?输出两个什么对象?

答案:

  1. <input type="button" value="按钮A" id="btnA"/>
  2. Window

1.1、JavaScript中函数与方法的区分

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

  1. <script type="text/javascript">
  2. //
  3. function show(){
  4. console.log("这是一个函数");
  5. }
  6.  
  7. //
  8. (function(){
  9. console.log("这是一个函数表达式");
  10. })();
  11.  
  12. //
  13. var obj1={
  14. show:function(){
  15. console.log("这是一个方法");
  16. }
  17. };
  18.  
  19. //
  20. function obj2(){ //obj2是函数,构造函数
  21. this.show=function(){
  22. console.log("这是一个方法,是一个表达式");
  23. }
  24. }
  25. var obj3=new obj2();
  26.  
  27. </script>

可以简单的认为如果调用时没有通过对象没有指定上下文则为函数,否则为方法。

1.2、指向全局对象

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

  1. <script type="text/javascript">
  2. var i=5;
  3. i=6;
  4. console.log(i); //
  5. console.log(window.i); //
  6. console.log(this.i); //
  7. console.log(this); //window
  8. </script>

结果:

  1. <script type="text/javascript">
  2. var name="tom";
  3. console.log(this.name); //顶层对象,一般为window
  4.  
  5. function show()
  6. {
  7. console.log(this.name); //顶层对象,一般为window
  8. return function(){
  9. console.log(this.name); //顶层对象,一般为window,因为返回的是函数
  10. }
  11. }
  12.  
  13. var f1=show();
  14. f1();
  15.  
  16. </script>

运行结果:

1.3、作为方法调用

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

  1. function show()
  2. {
  3. //当obj1.view()时this就是obj1,obj2.view()时this就是obj2
  4. console.log(this.name);
  5. }
  6.  
  7. var obj1={name:"jack",view:show};
  8. obj1.view();
  9.  
  10. var obj2={name:"mark",view:show};
  11. obj2.view();

运行结果:

示例代码:

  1. <script type="text/javascript">
  2. var name="lucy";
  3. this.name="Mali";
  4. function show()
  5. {
  6. //当obj1.view()时this就是obj1,obj2.view()时this就是obj2
  7. console.log(this.name);
  8.  
  9. return function(){
  10. console.log(this.name); //这里的this是调用时动态决定
  11. }
  12. }
  13.  
  14. var obj1={name:"jack",view:show};
  15. obj1.view();
  16.  
  17. var obj2={name:"mark",view:show};
  18. var f1=obj2.view();
  19. f1(); //因为f1属于window(浏览器环境),调用f1时的this也就是window
  20.  
  21. </script>

运行结果:

示例代码:

  1. <script type="text/javascript">
  2. var name="lucy";
  3. this.name="Mali";
  4. function show()
  5. {
  6. //当obj1.view()时this就是obj1,obj2.view()时this就是obj2
  7. console.log(this.name);
  8. that=this; //闭包
  9. return function(){
  10. console.log(that.name); //这里的that指向的是外层函数调用时的对象
  11. }
  12. }
  13.  
  14. var obj1={name:"jack",view:show};
  15. obj1.view();
  16.  
  17. var obj2={name:"mark",view:show};
  18. var f1=obj2.view();
  19. f1();
  20. </script>

运行结果:

1.4、在构造函数中的this

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

示例代码:

  1. <script type="text/javascript">
  2. this.name="吉娃娃";
  3. function Dog(name)
  4. {
  5. this.name=name;
  6. this.bark=function(){
  7. console.log(this.name+"在叫,汪汪...");
  8. }
  9. }
  10.  
  11. var dog1=new Dog("哈士奇");
  12. dog1.bark();
  13. </script>

运行结果:

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

  1. this.name="吉娃娃";
  2. function Dog(name)
  3. {
  4. this.name=name;
  5. this.bark=function(){
  6. console.log(this.name+"在叫,汪汪...");
  7. }
  8. return this.bark;
  9. }
  10.  
  11. var dog1=new Dog("哈士奇");
  12. dog1();

运行结果:

1.5、指定this指向的对象

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

示例代码:

  1. this.name="伽啡";
  2. function Cat(name)
  3. {
  4. this.name=name;
  5. }
  6. var bark=function(n){
  7. console.log(this.name+"叫了"+(n||1)+"声喵喵...");
  8. }
  9.  
  10. var cat1=new Cat("波斯");
  11. var cat2=new Cat("龙猫");
  12.  
  13. bark.call(cat1,5); //调用时this是cat1
  14. bark.apply(cat2,[8]); //调用时this是cat2
  15. bark.apply(window,[9]); //调用时this是window
  16. bark.apply(); //调用时this是顶层对象

运行结果:

1.6、作为事件时的this

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

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>this</title>
  6. </head>
  7. <body>
  8. <input type="button" value="按钮A" class="btn"/>
  9. <input type="button" value="按钮B" class="btn"/>
  10. <input type="button" value="按钮C" class="btn"/>
  11. <input type="button" value="按钮D" onclick="handler()"/>
  12. <!--handler中的this指向window或顶层对象-->
  13. <input type="button" value="按钮E" id="btnE"/>
  14. <script type="text/javascript">
  15. var buttons = document.querySelectorAll(".btn");
  16.  
  17. for (var i=0;i<buttons.length;i++) {
  18. //handler中的this指向按钮对象
  19. buttons[i].onclick=handler;
  20. }
  21.  
  22. function handler(){
  23. alert(this.value);
  24. }
  25.  
  26. //handler中的this指向btnE
  27. document.getElementById("btnE").addEventListener("click",handler,false);
  28. </script>
  29. </body>
  30. </html>

当点击A-C时的效果:

当点击D时的效果:

当点击按钮E时的效果:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>this</title>
  7. </head>
  8.  
  9. <body>
  10. <input type="button" value="按钮F的值" id="btnF" />
  11. <input type="button" value="按钮G的值" id="btnG" onclick="app.show()"/>
  12. <script type="text/javascript">
  13. value="window的值"
  14. var app = {
  15. value: "app的值",
  16. show: function() {
  17. alert(this.value); //如果show为事件,则this指向触发事件的对象
  18. },
  19. init: function() {
  20. //handler中的this指向btnE
  21. document.getElementById("btnF").addEventListener("click", this.show, false);
  22. }
  23. };
  24.  
  25. app.show(); //"app的值",show方法中的this指向app这个对象
  26. app.init(); //init中的this指向谁app对象
  27.  
  28. </script>
  29. </body>
  30. </html>

加载时运行结果:

点击按钮F时的效果:

点击按钮G时的效果:

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

1.7、小结

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

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个参数,指向调用时的上下文。

二、原型(prototype)与原型链

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

JavaScript藏宝图

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

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

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

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

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

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

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

实例说明:

代码:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title></title>
  7. </head>
  8.  
  9. <body>
  10. <script type="text/javascript">
  11. //构造器,函数,对象
  12. function Cat(nickname, color) {
  13. //各个对象独有的
  14. this.nickname = nickname;
  15. this.color = color;
  16. }
  17.  
  18. //所有对象公有的
  19. Cat.prototype.life = 9;
  20. Cat.prototype.bark = function() {
  21. console.log(this.nickname, this.color, this.life, "喵喵...");
  22. }
  23.  
  24. var c1 = new Cat("波斯", "绿色");
  25. c1.bark();
  26. var c2 = new Cat("加菲", "红色");
  27. c2.bark();
  28. </script>
  29. </body>
  30.  
  31. </html>

控制台:

关系图:

(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的成员。

JavaScript Object Layout:

Object Relationship Diagram with Inheritance

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

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

1.1、为什么需要prototype

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

  1. //构造方法,用于创建学生对象
  2. function Student(name) {
  3. this.name = name;
  4. }
  5.  
  6. var tom=new Student("tom");
  7. tom.show=function(){
  8. console.log(this.name);
  9. }
  10.  
  11. var rose=new Student("rose");
  12. rose.show=function(){
  13. console.log(this.name);
  14. }
  15.  
  16. tom.show();
  17. rose.show();

运行结果:

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

  1. //构造方法,用于创建学生对象
  2. function Student(name) {
  3. this.name = name;
  4. this.show = function() {
  5. console.log(this.name);
  6. }
  7. }
  8.  
  9. var tom = new Student("tom");
  10. var rose = new Student("rose");
  11.  
  12. tom.show();
  13. rose.show();

但是如果Student构造函数是一个内置的函数或是其它框架定义的类型,则修改就比较麻烦了,可以不修改源码的情况扩展该对象的原型也可以达到目的,如下所示:

  1. //构造方法,用于创建学生对象
  2. function Student(name) {
  3. this.name = name;
  4. }
  5.  
  6. //修改Student对象的原型,增加show方法
  7. Student.prototype.show = function() {
  8. console.log(this.name);
  9. }
  10.  
  11. var tom = new Student("tom");
  12. var rose = new Student("rose");
  13.  
  14. tom.show();
  15. rose.show();

在示例中我们并没有修改Student这个构造函数而是修改了了Student的原型对象,类似它的父类,如下图所示:

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

  1. var mark=new Object();
  2. mark.name="mark";
  3.  
  4. var lucy={name:"lucy"};
  5. //mark.show();
  6. //lucy.show();

此处的两个show方法是错误的。总之原型的主要作用就是为了实现继承与扩展对象。

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

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

1.2、typeof与instanceof

1.2.1、typeof

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

  1. var str1="Hello";
  2. var str2=new String("Hello");
  3.  
  4. console.log(typeof 1);
  5. console.log(typeof(true));
  6. console.log(typeof str1);
  7. console.log(typeof str2);
  8. console.log(typeof([1,2,3]));
  9. console.log(typeof Date);
  10. console.log(typeof undefined);
  11. console.log(typeof null);
  12. console.log(typeof zhangguo);

运行结果:

1)、数字类型, typeof 返回的值是 number。比如说:typeof(1),返回值是number
2)、字符串类型, 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。

1.2.2、instanceof

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

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

例如:
var oStringObject = new String("hello world");
console.log(oStringObject instanceof String); // 输出 "true"

  1. var str1="Hello";
  2. var str2=new String("Hello");
  3.  
  4. console.log(str1 instanceof String); //string false
  5. console.log(str2 instanceof String); //object true
  6.  
  7. console.log(1 instanceof Number); //false
  8.  
  9. function Foo(){};
  10.  
  11. var f1=new Foo();
  12. console.log(f1 instanceof Foo);

运行结果:

1.3、Function与Object

1.3.1、Function

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

先来看一个示例:

  1. function Foo(a, b, c) { //Foo这个构造函数由Function构造,函数也是对象
  2. return a * b * c;
  3. }
  4.  
  5. var f1=new Foo(); //f1由Foo构造,Foo是一个构造函数,可以理解为类
  6.  
  7. console.log(Foo.length); //参数个数 3
  8. console.log(typeof Foo.constructor); //function
  9. console.log(typeof Foo.call); //function
  10. console.log(typeof Foo.apply); //function
  11. console.log(typeof Foo.prototype); //object object

运行结果:

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

  1. function Foo() {};
  2. var foo = new Foo();
  3. //Foo为foo的构造函数,简单理解为类型
  4. console.log(foo instanceof Foo); // true
  5.  
  6. //但是Function并不是foo的构造函数
  7. console.log(foo instanceof Function); // false
  8.  
  9. //Function为Foo的构造函数
  10. alert(Foo instanceof Function); //true

上面的代码解释了foo和其构造函数Foo和Foo的构造函数Function的关系,Foo是由Function构造得到,可以简单理解为,系统中有一个这样的构造函数:

  1. function Function(name,body)
  2. {
  3. }
  4.  
  5. var Foo=new Function("Foo","");

如上面例子中的构造函数,JavaScript中函数也是对象,所以就可以通过_proto_查找到构造函数对象的原型。

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

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

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

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

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

1.3.2、Object

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

  1. alert(Function instanceof Function);//true
  2. alert(Function instanceof Object);//true
  3. alert(Object instanceof Function);//true
  4.  
  5. function Foo() {};
  6. var foo = new Foo();
  7. alert(foo instanceof Foo); // true
  8. alert(foo instanceof Function); // false
  9. alert(foo instanceof Object); // true
  10. alert(Foo instanceof Function); // true
  11. alert(Foo instanceof Object); // true

JavaScript 原型链

  1. function A() {this.x="x";};
  2. var a=new A();
  3.  
  4. function B() {this.y="y"};
  5. B.prototype=a;
  6. var b=new B();
  7.  
  8. function C() {this.z="z"};
  9. C.prototype=b;
  10. var c=new C();
  11.  
  12. console.log(c instanceof C);
  13. console.log(c instanceof B);
  14. console.log(c instanceof A);
  15. console.log(c instanceof Object);
  16.  
  17. 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 {}”原型对象就是原型链的终点了。

1.4、通过prototype扩展对象

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

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

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>prototype原型</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. var v="hi";
  10.  
  11. String.prototype.rpt=function(n)
  12. {
  13. n=n||2;
  14. var temp="";
  15. for(var i=0;i<n;i++) temp+=this;
  16. return temp;
  17. }
  18.  
  19. console.log(v.rpt());
  20. console.log(v.rpt(10));
  21. </script>
  22. </body>
  23. </html>

运行结果:

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

  1. //扩展String类型,增加trim方法用于删除字符串的首尾空格
  2. String.prototype.trim=function()
  3. {
  4. return this.replace(/^\s+|\s+$/igm,'');
  5. }
  6.  
  7. console.log("[begin]"+" Hello JavaScript ".trim()+"[end]");

运行结果:

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

  1. //修改函数对象的原型,添加method方法,扩展所有的函数
  2. Function.prototype.method=function(name,fun){
  3. //如果当前扩展的函数的原型中不包含名称为name的对象
  4. if(!this.prototype[name]){
  5. //添加
  6. this.prototype[name]=fun;
  7. }
  8. }
  9.  
  10. String.method("show",function(){
  11. console.log("输出:"+this);
  12. });
  13.  
  14. "Hello".show();
  15. "JavaScript".show();

运行结果:

1.5、通过prototype调用函数

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

  1. function add(x,y,z)
  2. {
  3. var array1=[].slice.call(arguments,0,3);
  4. console.log(array1);
  5. var array2=Array.prototype.slice.apply(arguments,[0,3]);
  6. console.log(array2);
  7. }
  8. add(1,2,8,9,10);

运行结果:

示例代码:

  1. var str1 = "Hello JavaScript";
  2. console.log(str1.toUpperCase()); //传统的调用办法
  3.  
  4. var str2=String.prototype.toUpperCase.apply(str1); //通过原形直接调用
  5. console.log(str2);
  6.  
  7. var str3=String.prototype.toUpperCase.call(str1); //通过原形直接调用
  8. console.log(str3);
  9.  
  10. var array1=[2,3,5,7,8,9,10];
  11. var array2=array1.slice(1,3);
  12. console.log(array2);
  13.  
  14. var slice=Array.prototype.slice;
  15. console.log(slice.apply(array1,[1,3]));//通过原形直接调用
  16. console.log(slice.call(array1,1,3));

运行结果:

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

1.6、prototype和__proto__的区别

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

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

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

示例:

  1. var a = {};
  2. console.log(a.prototype); //undefined
  3. console.log(a.__proto__); //Object {}
  4.  
  5. var b = function(){}
  6. console.log(b.prototype); //b {}
  7. console.log(b.__proto__); //function() {}
  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title></title>
  7. </head>
  8.  
  9. <body>
  10. <script>
  11. //构造方法,类,函数
  12. function Foo(name) {
  13. this.name = name;
  14. }
  15.  
  16. var f1 = new Foo("zhangguo");
  17.  
  18. //prototype是函数才有的属性,prototype本身就是一个对象,prototype对象中拥有constractor构造器(该构造器反向指回函数)
  19. console.log(f1.prototype); //undefined
  20. console.log(Foo.prototype); //function Foo.prototype
  21. //__proto__是对象带有属性,用于访问创建对象的类型所对应的原型
  22. console.log(f1.__proto__); //function Foo.prototype
  23. console.log(Foo.__proto__); //function(){}
  24. //Foo.__proto__ 就是Function.prototype
  25.  
  26. console.log(Foo.__proto__===Function.prototype); //true
  27. console.log(Foo.prototype===f1.__proto__); //true
  28.  
  29. //字面量创建的对象(o={})或Object创建的对象__proto__指向Object.prototype
  30. var o={};
  31. console.log(o.__proto__===Object.prototype); //true
  32. var obj=new Object();
  33. console.log(obj.__proto__===Object.prototype); //true
  34. var obj2=Object.create({});
  35. console.log(obj2.__proto__===Object.prototype); //false
  36.  
  37. // console.log(obj1.prototype);
  38. // console.log(obj1.__proto__);
  39. // console.log(Foo.prototype);
  40. </script>
  41. </body>
  42.  
  43. </html>

结果:

1.7、__proto__属性指向

  1. /*1、字面量方式*/
  2. var a = {};
  3. console.log(a.__proto__); //Object {}
  4.  
  5. console.log(a.__proto__ === a.constructor.prototype); //true
  6.  
  7. /*2、构造器方式*/
  8. var A = function(){};
  9. var a = new A();
  10. console.log(a.__proto__); //A {}
  11.  
  12. console.log(a.__proto__ === a.constructor.prototype); //true
  13.  
  14. /*3、Object.create()方式*/
  15. var a1 = {a:1}
  16. var a2 = Object.create(a1);
  17. console.log(a2.__proto__); //Object {a: 1}
  18.  
  19. console.log(a.__proto__ === a.constructor.prototype); //false(此处即为图1中的例外情况)

示例:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title></title>
  7. </head>
  8.  
  9. <body>
  10. <script>
  11. //构造方法,类,函数
  12. function Foo(name) {
  13. this.name = name;
  14. }
  15.  
  16. var f1 = new Foo("zhangguo");
  17.  
  18. console.log(f1.constructor === Foo); //true
  19. console.log(f1.__proto__ === Foo.prototype); //true
  20.  
  21. /*1、字面量方式*/
  22. var a = {};
  23. //a的__proto__是指向了a的构造器所指向的原型
  24. //字面量创建的对象的__proto__指向了Object的原型
  25. console.log(a.__proto__ === a.constructor.prototype); //true
  26.  
  27. /*2、构造器方式*/
  28. var A = function() {};
  29.  
  30. var a = new A();
  31.  
  32. console.log(a.__proto__); //A的原型
  33.  
  34. console.log(a.__proto__ === a.constructor.prototype); //true
  35. console.log(a.__proto__ === A.prototype); //true
  36.  
  37. /*3、Object.create()方式*/
  38. var a1 = {a: 1}
  39. var a2 = Object.create(a1);
  40.  
  41. console.log(a2.__proto__===a1); //true,a1就是a2的原型(父类)
  42. </script>
  43. </body>
  44.  
  45. </html>

结果:

1.8、原型链

示例:

  1. var A = function(){};
  2. var a = new A();
  3. console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
  4. console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
  5. console.log(a.__proto__.__proto__.__proto__); //null

示例:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title></title>
  7. </head>
  8.  
  9. <body>
  10. <script>
  11. //构造方法,类,函数
  12. function Foo(name) {
  13. this.name = name;
  14. }
  15.  
  16. var f1 = new Foo("zhangguo");
  17. //1、var f1={};
  18. //2、f1.__proto__=Foo.prototype;
  19. //3、Foo.call(f1,"zhangguo");
  20.  
  21. //在Foo的原型中添加属性age
  22. Foo.prototype.age = 80;
  23. Foo.prototype.show = function() {
  24. console.log("name:" + this.name + ",age:" + this.age);
  25. }
  26.  
  27. var f2 = new Foo("zhangsan");
  28.  
  29. console.log(f1.age == f2.age);
  30. f1.show();
  31. f2.show();
  32.  
  33. var A = function() {};
  34. var a = new A();
  35. console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
  36. console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
  37. console.log(a.__proto__.__proto__.__proto__); //null
  38. </script>
  39. </body>
  40.  
  41. </html>

结果:

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

  1. function Person(name, age){
  2. this.name = name;
  3. this.age = age;
  4. }
  5. Person.prototype.MaxNumber = 9999;
  6. Person.__proto__.MinNumber = -9999;
  7. var will = new Person("Will", 28);
  8. console.log(will.MaxNumber); // 9999
  9. console.log(will.MinNumber); // undefined

在这个例子中分别给”Person.prototype “和” Person.proto”这两个原型对象添加了”MaxNumber “和”MinNumber”属性,这里就需要弄清”prototype”和”proto”的区别了。

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

对象创建方式影响原型链

  1. var July = {
  2. name: "张三",
  3. age: 28,
  4. getInfo: function(){
  5. console.log(this.name + " is " + this.age + " years old");
  6. }
  7. }
  8. console.log(July.getInfo());

当使用这种方式创建一个对象的时候,原型链就变成下图了. July对象的原型是”Object.prototype”也就是说对象的构建方式会影响原型链的形式。

1.9、构造对象

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

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

1. 创建空对象;

  1. var obj = {};

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

  1. obj.__proto__ = ClassA.prototype;

3. 使用新对象调用构造函数,函数中的this被指向新实例对象:

  1. ClassA.call(obj);  //{}.构造函数();      

4. 将初始化完毕的新对象地址,保存到等号左边的变量中

示例:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9.  
  10. function Car(name){
  11. this.name=name;
  12. }
  13.  
  14. //1、直接创建
  15. var c1=new Car("BYD");
  16.  
  17. //2、实际创建对象的步骤
  18. //2.1、创建空的对象字面量
  19. var c2={};
  20. //2.2、将对象的__proto__指向构造器的原型对象(prototype)
  21. c2.__proto__=Car.prototype;
  22. //2.3、调用构造器,初始化创建的对象
  23. Car.call(c2,"BYD");
  24. //2.4、将创建的对象地址赋值给变量(返回给左边的变量)
  25. </script>
  26. </body>
  27. </html>

结果:

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

new 的过程分为三步

  1. var p = new Person('张三',20);
  2.  
  3. 1. var p={}; 初始化一个对象p
  4.  
  5. 2. p._proto_=Person.prototype;,将对象p __proto__ 属性设置为 Person.prototype
  6.  
  7. 3. 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的基本方法。

引用

  1. function Foo() {}
  2. var foo = new Foo();
  3. console.log(foo.prototype);// undefined
  4. console.log(foo.__proto__ === Foo.prototype);// true
  5. console.log(Foo.prototype);// [object Object]
  6. console.log(Foo.prototype.prototype);// undefined

解释

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

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

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

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

图(橙色箭头是初始的关系,绿色是执行var Fish = new Fu...创建,蓝色是执行f1= new Fish()创建。)

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

1.10、小结

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面向对象(OOP)

3.1、封装

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

  1. function Animal(){
  2. this.name="动物";
  3. this.weight=0; //重量
  4. }
  5.  
  6. var cat=new Animal();
  7. cat.name="猫";
  8. cat.weight=-90;
  9. console.log(cat);

输出:

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

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title></title>
  7. </head>
  8.  
  9. <body>
  10. <script type="text/javascript">
  11. function Animal() {
  12. this.name = "动物";
  13. var weight = 0; //重量
  14. this.getWeight = function() { //读
  15. return weight;
  16. };
  17. this.setWeight = function(_weight) { //写
  18. if(_weight > 0) {
  19. weight = _weight;
  20. } else {
  21. throw "动物的重量必须为正数";
  22. }
  23. }
  24. }
  25.  
  26. var cat = new Animal();
  27. cat.name = "猫";
  28. try{
  29. cat.setWeight(-90);
  30. }catch(e){
  31. console.log(e);
  32. }
  33. console.log(cat);
  34. </script>
  35. </body>
  36.  
  37. </html>

结果:

  1. function Animal()
  2. {
  3. this.name="动物";
  4. this.getName=function(){
  5. return this.name;
  6. }
  7. this.setName=function(name){
  8. this.name=name;
  9. }
  10. this.bark=function(){
  11. console.log(this.name+"在叫...");
  12. }
  13. }
  14. var animal=new Animal();
  15. animal.setName("小狗");
  16. animal.bark();

这里定义的一个构造函数,将name封装成属性,Animal函数本身用于封装动物的属性与行为,运行结果:

3.2、继承

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

  1. function Animal()
  2. {
  3. this.name="动物";
  4. this.getName=function(){
  5. return this.name;
  6. }
  7. this.setName=function(name){
  8. this.name=name;
  9. }
  10. this.bark=function(){
  11. console.log(this.name+"在叫...");
  12. }
  13. }
  14.  
  15. function Dog(){
  16. this.hunt=function(){console.log("狗在捕猎");};
  17. }
  18. //指定Dog构造函数的原型对象,简单理解为父类
  19. Dog.prototype=new Animal();
  20.  
  21. function Cat(){
  22. this.hunt=function(){console.log("猫在抓老鼠");};
  23. }
  24. Cat.prototype=new Animal();
  25.  
  26. var dog=new Dog();
  27. dog.bark();
  28. dog.hunt();
  29.  
  30. var cat=new Cat();
  31. cat.bark();
  32. cat.hunt();

运行结果:

3.3、多态

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

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>JavaScript面向对象</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. function Animal()
  10. {
  11. this.name="动物";
  12. this.getName=function(){
  13. return this.name;
  14. }
  15. this.setName=function(name){
  16. this.name=name;
  17. }
  18. this.bark=function(){
  19. console.log(this.name+"在叫...");
  20. }
  21. }
  22.  
  23. function Dog(){
  24. this.hunt=function(){console.log("狗在捕猎");};
  25. }
  26. //指定Dog构造函数的原型对象,简单理解为父类
  27. Dog.prototype=new Animal();
  28. //重写原型对象中的bark方法
  29. Dog.prototype.bark=function(){
  30. console.log("汪汪...");
  31. }
  32.  
  33. function Cat(){
  34. this.hunt=function(){console.log("猫在抓老鼠");};
  35. }
  36. Cat.prototype=new Animal();
  37. //重写原型对象中的bark方法
  38. Cat.prototype.bark=function(){
  39. console.log("喵喵...");
  40. }
  41.  
  42. function play(animal)
  43. {
  44. animal.bark();
  45. animal.hunt();
  46. }
  47.  
  48. var dog=new Dog();
  49. var cat=new Cat();
  50. play(dog);
  51. play(cat);
  52. </script>
  53. </body>
  54. </html>

运行结果:

示例:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <title></title>
  7. </head>
  8.  
  9. <body>
  10. <script type="text/javascript">
  11. //二种重写的办法
  12. function Animal(name) {
  13. this.name = name || "动物";
  14. this.bark = function() {
  15. console.log(this.name + "叫了:嗷嗷...");
  16. }
  17. };
  18.  
  19. function Cat() {
  20. this.hunt = function() {
  21. console.log(this.name + "正在捕老鼠!");
  22. }
  23. }
  24. Cat.prototype = new Animal("猫");
  25. Cat.prototype.bark = function() {
  26. console.log("喵喵");
  27. }
  28. var cat = new Cat();
  29. cat.hunt();
  30. cat.bark();
  31.  
  32. function Dog() {
  33. this.hunt = function() {
  34. console.log(this.name + "正在捕猎!");
  35. }
  36. this.bark = function() {
  37. console.log("汪汪");
  38. }
  39. }
  40. //让Dog继承Animal,修改原型的指向
  41. Dog.prototype = new Animal("狗");
  42. var dog = new Dog();
  43. dog.hunt();
  44. dog.bark();
  45.  
  46. //重载的办法
  47. function add(n) {
  48. if(typeof n === "number") {
  49. return ++n;
  50. }
  51. if(n instanceof Array){
  52. var sum=0;
  53. for(var i=0;i<n.length;i++){
  54. sum+=n[i];
  55. }
  56. return sum;
  57. }
  58. }
  59. console.log(add(100));
  60. console.log(add([1, 2, 3, 4, 5]));
  61. </script>
  62. </body>
  63.  
  64. </html>

结果:

练习:请使用javascript完成一个简单工厂设计模式。

四、示例下载

https://github.com/zhangguo5/javascript003.git

https://git.coding.net/zhangguo5/javascript_01.git

https://git.dev.tencent.com/zhangguo5/javascriptpro.git

五、视频

http://www.bilibili.com/video/av17173253/

JavaScript学习总结(四)——this、原型链、javascript面向对象的更多相关文章

  1. JavaScript 原型链学习(四)原型链的基本概念、原型链实现继承

    简单回顾一下构造函数.原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针.那么,假如我们让原型对象等于另一个类型的实例,结果会 ...

  2. JavaScript学习记录四

    title: JavaScript学习记录四 toc: true date: 2018-09-16 20:31:22 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  3. javascript学习笔记(四) Number 数字类型

    数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数  toExponential() 方法 用科学 ...

  4. jquery学习笔记---闭包,原型链,this关键字

    网上的资料很多,关于闭包,原型链,面向对象之内的.本人也有一点自己的总结. 关于this: this 的值取决于 function 被调用的方式,一共有四种, 如果一个 function 是一个对象的 ...

  5. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

  6. Javascript之其实我觉得原型链没有难的那么夸张!

    原型链.闭包.事件循环等,可以说是js中比较复杂的知识了,复杂的不是因为它的概念,而是因为它们本身都涉及到很多的知识体系.所以很难串联起来,有一个完整的思路.我最近想把js中有点意思的知识都总结整理一 ...

  7. JavaScript学习总结(四)——jQuery插件开发与发布

    jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...

  8. javascript中的对象,原型,原型链和面向对象

    一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...

  9. 《JAVASCRIPT高级程序设计》根植于原型链的继承

    继承是面向对象的语言中,一个最为津津乐道并乐此不疲的话题之一.JAVASCRIPT中的继承,主要是依靠原型链来实现的.上一篇文章介绍过,JAVASCRIPT中,每一个对象都有一个prototype属性 ...

随机推荐

  1. unidbgrid列排序

    unidbgrid列排序 1)指定列的.sortable:=true; 2)unidbgrid.columnsort事件添加如下代码: if SameText(Column.FieldName, 'I ...

  2. socket粗解

    百度定义:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket通信流程: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一 ...

  3. JS学习笔记6_事件

    1.事件冒泡 由内而外的事件传播(从屏幕里飞出来一支箭的感觉) 2.事件捕获 由表及里的事件传播(力透纸背的感觉) 3.DOM事件流(DOM2级) 事件捕获阶段 -> 处于目标阶段 -> ...

  4. 【Win】Clso QR Tool 二维码小工具

    一个可以生成并识别二维码的windows小工具,纯绿色.不含糖. 可以通过输入文本生成二维码,或者加载本地图片.剪贴板内的图片,直接解析出二维码内容. 支持自定义LOGO. 下载文件 (当前版本:1. ...

  5. 201621123018《Java程序设计》第10周学习报告

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1. 常用异常 1.1 自己以前编写的代码中经常出现什么异常.需要捕获吗(为 ...

  6. 《Python黑帽子:黑客与渗透测试编程之道》 玩转浏览器

    基于浏览器的中间人攻击: #coding=utf-8 import win32com.client import time import urlparse import urllib data_rec ...

  7. word2vec的原理(一)

    最近上了公司的新员工基础培训课,又对NLP重新产生的兴趣.NLP的第一步大家知道的就是不停的写正则,那个以前学的还可以就不看了.接着就是我们在把NLP的词料在传入神经网络之前的一个预处理,最经典的就是 ...

  8. linux的RPM软件包管理工具

    RPM(Redhat Package Manage)原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采 ...

  9. WebRTC开发基础(WebRTC入门系列1:getUserMedia)

    什么是WebRTC WebRTC由IETF(Internet Engineering Task Force——互联网工程任务组)和W3C(World Wide Web Consortium——万维网联 ...

  10. Python之Pyautogui模块20180125《PYTHON快速上手让繁琐的工作自动化》18章

    复习 PyAutoGUI 的函数本章介绍了许多不同函数,下面是快速的汇总参考:moveTo(x,y)将鼠标移动到指定的 x.y 坐标.moveRel (xOffset,yOffset)相对于当前位置移 ...