《JavaScript面向对象的编程指南》--读书笔记

第一章、引言

1.5 面向对象的程序设计常用概念

对象(名词):是指“事物”在程序设计语言中的表现形式。
这里的事物可以是任何东西,我们可以看到它们具有某些明确特征,能执行某些动作。
这些对象特征就叫做属性(形容词),动作称之为方法(动词)。

**类:**实际上就是对象的设计蓝图或制作配方。类更多的是一种模板,而对象就是在这些模版的基础上被创建出来的。

**封装:**主要阐述对象中包含的内容。通常包括:

  • 相关数据(用于存储属性)
  • 基于这些数据所能做的事(所能调用的方法)

**聚合:**将几个现有对象合并成一个新对象的过程
**继承:**实现代码重用
**多态:**不同对象通过相同的方法调用来实现各自行为的能力

第二章、基本数据类型、数组、循环及条件表达式

2.3 基本数据类型

2.3.2 指数表示法

2e+3 表示在数字 2 后面加 3 个 0,即 2000

typeof Infinity; // number
typeof NaN; // number
typeof null; // object   null值表示一个空指针对象
2.3.4 惰性求值

Javascript 引擎在一个逻辑表达式中遇到一个非布尔类型操作数,
那么该操作数的值就会成为该表达式返回的结果。

true || "something"; //true
true && "something"; //"something"

2.9 练习题

var s = "1s"; //隐式转换Number()用于任何数据类型
s++; //NaN
10 % "0"; //NaN   如果被除数是有限大的数值而除数是零,则结果是NaN
//乘法口诀程序代码
for (var i = 1; i < 10; i++) {
  for (var j = 1; j <= i; j++) {
    document.write(j + "*" + i + "=" + i * j + " ");
  }
  document.write("<br>");
}

第三章、函数

3.1 函数

3.1.2 函数参数

函数内部都有一个内建的 arguments 数组,能返回函数所接收的所有参数

function sumOnSteroids() {
  var i,
    res = 0;
  for (i = 0; i < arguments.length; i++) {
    res += arguments[i];
  }
  return res;
}
sumOnSteroids(1, 2, 3, 4, 5, 6); //21

3.3 函数的作用域

var a = 123;
function f() {
  alert(a); //undefined  这是因为函数域优先于全局域
  var a = 1;
  alert(a); //1
}
f();
3.4.2 回调函数

当我们将函数 B 传递给函数 A,并由 A 来执行 B 时,B 就成了一个回调函数

function A(a, b, c, callback) {
  var i = 0,
    ar = [];
  for (i = 0; i < 3; i++) {
    ar[i] = callback(arguments[i] * 2);
  }
  return ar;
}
function B(a) {
  //回调函数
  return a + 1;
}
A(a, b, c, B);
3.4.4 自调函数
(function (name) {
  alert("Hello " + name + " !");
})("Jesse"); //Hello Jesse !
//第二对括号起到的是立即调用的作用,同时也是向函数传递参数的地方

使用自调函数的好处是不会产生任何全局变量,缺点是无法重复执行,这使得匿名自调函数最合适于执行一些一次性的或者初始化的任务

3.4.5 私有函数
function a(param) {
  function b(theinput) {
    //私有函数
    return theinput * 2;
  }
  return "The result is " + b(param);
}

使用私有函数的好处:

  • 有助于全局命名空间的纯净性(命名冲突的机会很小)
  • 私有性–不被外部其他用用程序所用
3.4.7 能重写自己的函数

这对于要执行某些一次性初始化工作的函数非常有用

function a() {
  alert("A"); //第一次调用该函数时该语句会被执行
  a = function () {
    //第一次调用时a被赋予新函数
    alert("B"); //第二次调用该函数时该语句会被执行
  };
}
var a = (function () {
  function someSetup() {
    var setup = "done";
  }
  function actualWork() {
    alert("work");
  }
  someSetup();
  return actualWork;
})();

3.5 闭包

3.5.1 作用域链

在函数内定义的变量在函数外是不可见的,
但是如果该变量是在某个代码块中定义的(if 或 for 语句中),它在代码块外是可见的。

3.5.2 词法作用域

在 javascript 中每个函数都有一个属于自己的词法作用域,也就是说每个函数
在被定义时(而非执行时)都会创建一个属于自己的环境(即作用域)

function f1() {
  var a = 1;
  f2();
}
function f2() {
  return a;
} //f2()被定义时a是不可见的,只能访问自身作用域和全局作用域
f1(); //a is not defined
3.5.3 利用闭包突破作用域链
3.5.3.1 闭包#1
function f() {
  var b = "m";
  return function () {
    //有着私有作用域,可以访问f()的作用域和全局作用域
    return b;
  };
}
var n = f();
n(); //m

f()是全局函数,我们可以将它的返回值赋值给另一个全局变量,
从而生成一个可以访问 f()私有空间的新全局函数

3.5.3.3 相关定义与闭包#3

如果一个函数在其父函数返回之后想留住对父级作用域的链接,就必须要为此建立一个闭包

3.5.3.4 循环中的闭包
function f() {
  var a = [];
  for (var i = 0; i < 3; i++) {
    a[i] = function () {
      return i;
    };
  }
  return a;
}
var s = f();
s[0](); //3
s[1](); //3
s[2](); //3

我们在这里创建了 3 个闭包,它们都指向一个共同的局部变量 i,
但是闭包不会记录它们的值,他们所拥有的只是一个 i 的引用,
因此只能返回 i 的当前值(循环结束时 i=3).

function f() {
  var a = [];
  for (var i = 0; i < 3; i++) {
    a[i] = (function (x) {
      return function () {
        return x;
      };
    })(i);
  }
  return a;
}
var s = f();
s[0](); //0
s[1](); //1
s[2](); //2

3.7 练习题

1.十六进制值转为颜色函数 getRGB()

function getRGB(hex) {
  var rgb = [0, 0, 0];
  if (/#(..)(..)(..)/g.test(hex)) {
    rgb = [
      parseInt(RegExp.$1, 16),
      parseInt(RegExp.$2, 16),
      parseInt(RegExp.$3, 16),
    ];
  }
  return "rgb(" + rgb.join(",") + ")";
}
getRGB("#00ff00"); //"rgb(0,255,0)"

第四章、对象

4.1 从数组到对象

用[]定义数组的方法我们称之为数组文本标识法
用{}定义对象的方法我们称之为对象文本标识法

4.1.2 哈希表、关联型数组

在 javascript 中我们用数组表示索引型数组,用对象表示关联型数组

4.1.3 访问对象属性

一般通过以下两种方式访问对象的属性:

  • 中括号表示法:hero[‘name’]
  • 点号表示法:hero.name
4.1.7 构造器函数
function Hero(name) {
  //构造器函数首字母大写
  this.name = name;
  this.occupation = "ninja";
}
var hero = new Hero("jesse"); //使用new操作符创建新对象
hero.name; //ninja

使用构造器函数的好处是能利用同一个构造器函数通过传参从而创建出不同的对象。

4.1.8 全局对象

事实上程序所在的宿主环境一般都会为其提供一个全局对象,
而所谓的全局变量其实只不过是该对象的属性

4.1.9 构造器属性

构造器属性实际上是一个指向用于创建该对象的构造器函数的引用

hero.contructor //Hero

通过 instanceof 操作符,我们可以测试一个对象是不是由某个指定的构造器函数所创建的

hero instanceof Hero; //true

4.1.12 传递对象

引用类型,因为其值大小不固定,因此栈内存中存放的只是该对象的访问地址,(即该对象的引用)
堆内存为这个值分配空间。因此我们在引用上所做的任何改动,都会影响到他所引用的源对象。

4.2 内建对象

4.2.1 Object

所有对象都继承自 Object 对象,因此都具有 toLocaleString()、toString()和 valueOf()方法。

var o = new Object();
var o = {};
alert(o); //[object,Object]

由于 alert()要接收字符串参数,所以它会在后台调用 toString()方法

Object 构造器的成员:

Object构造器的成员

用 Object()构造器所建对象的成员:

用Object()构造器所建对象的成员
用Object()构造器所建对象的成员
用Object()构造器所建对象的成员

4.2.2 Array
var a = new Array();
var a = [];
typeof a; //'object' 数组也是对象

值得关注的数组的属性与方法

  • length 属性:定义数组时会自动生成 length 属性,而一般对象中没有
  • sort()、join()、slice()、splice()

Array 对象的成员:

Array对象的成员
Array对象的成员
Array对象的成员
Array对象的成员

4.2.3 Function

函数实际上也是一种对象,函数对象的内建构造器是 Function()

定义函数的三种方式:

  • function sum(a,b){return a + b;}; //函数声明
  • var sum = function(a,b){return a + b;}; //函数表达式
  • var sum = new Function('a','b','return a + b;'); //Function构造器 避免使用
4.2.3.1 Function 对象的属性:
  • prototype 属性详见第五章
  • length:用于记录该函数所拥有的参数数量
  • caller:返回一个调用该函数对象的外层函数引用
function A() {
  return A.caller;
}
function B() {
  return A();
}
B(); //function B(){return A();}
4.2.3.2 Function 对象的方法

Function 对象继承自 Object 对象,默认拥有 Object 对象的所有方法

call()、apply()方法都能让对象去借用其他对象中的方法为己所用,这也是一种代码重用的方式。

  • call()方法:
var someObj = {
  name: "Ninja",
  say: function (who) {
    return "Hello " + who + ", my name is " + this.name;
  },
};
var myObj = {
  name: "Jesse",
};
someObj.say.call(myObj, "Dude"); //"Hello Dude, my name is Jesse"
//当say()被调用时其中的this就被自动设置成myObj对象的引用

如果我们调用 call 方法时需要传递更多的参数,可以在后面依次加入他们

someObj.say.call(myObj,'a','b','c')

如果我们没有将对象传递给 call()的首参数,或者传递的是 null,则它的调用对象默认为全局对象

  • apply()方法:
    apply()的工作方式与 call()基本相同,唯一的不同之处在于第二个参数的传递形式 apply()方法的第二个参数是通过一个数组来传递的

someObj.say.apply(myObj,['a','b','c'])

4.2.3.3 重新认识 arguments 对象
  1. 在函数中通过 arguments 访问传递给函数的所有参数
  2. arguments 对象的 callee 属性,该属性返回的是当前被调用的函数对象
  3. 通过 arguments.callee 属性实现匿名函数的递归调用
(function (count) {
  if (count < 5) {
    console.log(count);
    arguments.callee(++count);
  }
})(1); //1,2,3,4

Function 对象的成员

Function对象的成员
Function对象的成员

4.2.4 Boolean
var b = new Boolean();
typeof b; //'object'
typeof b.valueOf(); // 'boolean'
4.2.5 Number

Number 对象的 toString()方法有一个可选的 radix 参数(默认 10)

var n = new Number(255);
n.toString(16); // 'ff'

Number()构造器的成员
Number()构造器的成员
Number()构造器的成员

Number 对象的成员
Number对象的成员
Number对象的成员

4.2.6 String

当我们将一个基本字符串当做对象来使用时,后台会执行相应的 String 对象创建操作

String()构造器的成员
String()构造器的成员

String 对象的成员
String对象的成员
String对象的成员
String对象的成员
String对象的成员

4.2.7 Math

Math 对象既不能当做一般函数来使用,也不能用 new 操作符创建对象,只是一个包含一系列方法和属性的内建对象

获取某个 max 和 min 之间的值,公式((max-min)*Math.random())+min

Math 对象的成员
Math对象的成员
Math对象的成员

4.2.8 Date

Date()构造器成员
Date()构造器成员

Date 对象的成员
Date对象的成员
Date对象的成员
Date对象的成员
Date对象的成员
Date对象的成员

4.2.9 RegExp
var reg = new RegExp("j.*t");
var reg = /j.*t/; //匹配任何以j开头t结尾的字符串,且这俩字符之间包含1个或多个字符
4.2.9.1 RegExp 对象的属性
  • global:如果该值为 false(默认),相关搜索在找到第一个匹配位置时就会停止,如果为 true 则会找出所有匹配位置,简写为‘g’
  • ignoreCase:设置是否忽略大小写,默认为 false,简写为’i’
  • multiline:设置是否跨行搜索,默认为 false,简写为’m’
  • lastIndex:搜索开始的索引位置,默认为 0。在对象创建之后可以修改
  • source:用于存储正则表达式匹配模式

var reg = /j.*t/img;

4.2.9.2 RegExp 对象的方法
  • test():返回的是一个布尔值(找到匹配内容为 true,否则为 false)
  • exec():返回的是一个由匹配字符串组成的数组
/j.*t/i.test('Javascript')   //true
/j.*t/i.exec('Javascript')[0]  //Javascript
4.2.9.3 以正则表达式为参数的字符串方法
  • match():返回的是一个包含匹配内容的数组
  • search():返回的是第一个匹配内容所在的位置
  • replace():将匹配的文本替换成指定的字符串
  • split():根据指定的正则表达式将目标字符串分割成若干数组元素
var s = new String("HelloJavascriptWorld");
s.match(/j.*a/gi); //['Java']
s.search(/j.*a/i); //5
//当某个匹配对象被找到时,如果我们想让相关的替换字符串中包含匹配的文本,可以使用$&修饰符
s.replace(/[A-Z]/g, "_$&"); //"_Hello_Javascript_World"
//如果正则表达式分了组(即带括号),那么可以用$1代表匹配分组中的第一组,$2代表第二组
s.replace(/[A-Z]/g, "_$1"); //"_Hello_Javascript_World"
var csv = "one, two,three ,four";
csv.split(/\s*,\s*/); //["one", "two", "three", "four"]
// \s*匹配0个或多个空格
//以上的4个方法可以接受的参数也包括字符串
"test".replace("t", "r"); //"rest"

RegExp 对象的成员
RegExp对象的成员
RegExp对象的成员

4.2.10 Error 对象
try {
  //可能会导致错误的代码
} catch (e) {
  //在发生错误时处理代码
} finally {
  //可选的
  //无论如何都会执行的代码
}

4.4 练习题

c = [1, 2, [1, 2]];
c.sort(); //[1, [1,2], 2]

4、在 String()构造器不存在时,自定义 MyString()构造器函数并通过以下测试

function MyString(string) {
  //this.length =
  this.toString = function () {
    return string.toString();
  };
  this.valueOf = function () {
    return string.valueOf();
  };
  this.reverse = function () {
    return Array.prototype.reverse.apply(string.split("")).join("");
  };
}
var s = new MyString("hello");
s.length; //5
s[0]; //'h'
s.toString(); //'hello'
s.valueOf(); //'hello'
s.chatAt(1); //'e'
s.concat(" world!"); //'hello world!'
s.slice(0, -1); //'hell'
s.split("l"); //['he','','o']

6、在 Array()不存在时,创建 MyArray()构造器并通过以下测试

var a = new MyArray(1,2,3,'test');
a.length;//4
a.toString();//'1,2,3,test'
a[a.length - 1];//'test'
a.push('boo');//5
a.pop();//'1,2,3,test'
a.join(',');//'1,2,3,test'
function MyArray(){
    this.length =
}

第五章、原型

5.1 原型属性

5.1.4 利用自身属性重写原型属性

如果在一个对象自身属性中没有找到指定的属性,就可以去原型链中查找相关属性。但是如果遇上对象自身属性与原型链属性同名时,那么对象自身属性的优先级高于原型链属性。

function Gadget(name, color) {
  this.name = name;
  this.color = color;
  this.method = function () {
    return 1;
  };
}
Gadget.prototype.price = 10;
Gadget.prototype.rating = 3;
var newtoy = new Gadget("webcam", "back");
for (var prop in newtoy) {
  console.log(prop + "=" + newtoy[prop]);
}
//name=webcam
//color=back
//method=function (){return 1;}
//price=10
//rating=3

hasOwnProperty()方法用于区分对象自身属性(返回 true)与原型属性(返回 false)

newtoy.hasOwnProperty("name"); //true
newtoy.hasOwnProperty("price"); //false

propertyIsEnumerable()方法对所有非内建对象属性返回 true,表示可通过 for-in 枚举;

newtoy.propertyIsEnumerable('name'); //true

isPrototypeOf()方法会告诉我们当前对象是否是另一个对象的原型

var monkey = {
  hair: true,
  feeds: "bananas",
  breathes: "air",
};
function Human(name) {
  this.name = name;
}
Human.prototype = monkey;
var jesse = new Human("Jesse");
monkey.isPrototypeOf(jesse); //true

5.2 扩展内建对象

为 Array 对象添加 inArray()方法,用于查询数组中是否存在某个特定的值

if (!Array.prototype.inArray) {
  //如果想通过原型为某个对象添加新属性,请务必检查该属性是否已存在
  Array.prototype.inArray = function (needle) {
    for (var i = 0; i < this.length; i++) {
      if (this[i] == needle) {
        return true;
      }
    }
    return false;
  };
}
var a = ["a", "b", "c"];
a.inArray("d"); //false

为 String 对象添加 reverse()方法,用于反向输出该字符串

if (!String.prototype.reverse) {
  //如果想通过原型为某个对象添加新属性,请务必检查该属性是否已存在
  String.prototype.reverse = function () {
    return Array.prototype.reverse.apply(this.split("")).join("");
  };
}
"Jesse".reverse(); //"esseJ"
//首先利用this.split('')将目标字符串转为数组,并作为apply()的第二个参数,第一个参数不传值时默认为全局对象
//再调用数组的reverse()方法生成反向数组
//最后通过join()方法将数组转化为字符串
5.2.2 原型陷阱
  • 当我们对原型对象完全替换时,可能会触发异常
  • prototype.constructor 属性不可靠

解决方法:当我们重写某对象的 prototype 时,必须重置相应的 constructor 属性

5.4 练习题

var shape = {
  type: "triangle",
  getType: function () {
    return this.type;
  },
};
function Triangle(a, b, c) {
  this.a = a;
  this.b = b;
  this.c = c;
}
Triangle.prototype = shape;
//当我们重写某对象的prototype时,必须重置相应的constructor属性
Triangle.prototype.constructor = Triangle;
Triangle.prototype.getPerimeter = function () {
  return this.a + this.b + this.c;
};
var t = new Triangle(1, 2, 3);
for (var prop in t) {
  if (t.hasOwnProperty(prop)) {
    console.log(prop + "=" + t[prop]);
  }
}
t.constructor; //Trianle(a,b,c)
shape.isPrototypeOf(t); //true
t.getPerimeter(); //6
t.getType(); //"triangle"

第六章、继承

6.1 原型链

6.1.1 原型链示例
function Shape() {
  this.name = "shape";
  this.toString = function () {
    return this.name;
  };
}
function TwoDShape() {
  this.name = "2D shape";
}
function Triangle(side, height) {
  this.name = "Triangle";
  this.side = side;
  this.height = height;
  this.getArea = function () {
    return (this.side * this.height) / 2;
  };
}
TwoDShape.prototype = new Shape();
Triangle.prototype = new TwoDShape();
//我们用构造器Shape()另建了一个新的实体,然后用它去覆盖该对象的原型
//这确保了在继承实现之后,我们对Shape()所进行的任何修改、重写、删除都不会对TwoShape()产生影响
TwoDShape.prototype.constructor = TwoDShape;
Triangle.prototype.constructor = Triangle;
var my = new Triangle(5, 10);
my.getArea(); //25
my.toString(); // Triangle
6.1.2 将共享属性迁移到原型中
function Shape() {}
Shape.prototype.name = "shape";
Shape.prototype.toString = function () {
  return this.name;
};
function TwoDShape() {}
TwoDShape.prototype = new Shape();
TwoDShape.prototype.constructor = TwoDShape;
//我们需要在对原型对象进行扩展之前,先完成相关继承关系的构建
TwoDShape.prototype.name = "2D shape";
function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
Triangle.prototype = new TwoDShape();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = "Triangle";
Triangle.prototype.getArea = function () {
  return (this.side * this.height) / 2;
};

6.2 只继承于原型

function Shape() {}
Shape.prototype.name = "shape";
Shape.prototype.toString = function () {
  return this.name;
};
function TwoDShape() {}
//TwoDShape.prototype = new Shape(); new Shape()会将Shape的属性设定为对象自身属性,这样的代码是不可重用的
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = "2D shape";
function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
Triangle.prototype = TwoDShape.prototype;
//这样固然可以提高效率,但是子对象和父对象都指向同一对象,一旦对原型属性进行修改,继承的对象相关属性也随之改变
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = "Triangle";
Triangle.prototype.getArea = function () {
  return (this.side * this.height) / 2;
};
var s = new Shape();
s.name; //"Triangle"

6.3 uber–子对象访问父对象的方式

在构建继承关系的过程中引入一个 uber 属性,并令其指向其父级原型对象

6.8 深拷贝

当对象类型的属性拷贝时,实际上拷贝的只是该对象在内存中的位置指针,这一过程就是浅拷贝

//浅拷贝
function extendCopy(p) {
  var c = {};
  for (var i in p) {
    c[i] = p[i];
  }
  c.uber = p;
  return c;
}
//深拷贝
function deepCopy(p, c) {
  var c = c || {};
  for (var i in p) {
    if (typeof p[i] === "object") {
      c[i] = p[i].constructor == Array ? [] : {};
      deepCopy(p[i], c[i]); //在遇到一个对象引用型的属性时,需要再次调用深拷贝
    } else {
      c[i] = p[i];
    }
  }
  return c;
}
var parent = {
  numbers: [1, 2, 3],
  letters: ["a", "b", "c"],
  obj: { prop: 1 },
  bool: true,
};
var mydeep = deepCopy(parent);
var myshallow = extendCopy(parent);
mydeep.numbers.push(4, 5, 6); //6
mydeep.numbers; //[1, 2, 3, 4, 5, 6]
parent.numbers; //[1, 2, 3]
myshallow.numbers.push(10); //4
myshallow.numbers; //[1, 2, 3, 10]
parent.numbers; //[1, 2, 3, 10]
mydeep.numbers; //[1, 2, 3, 4, 5, 6]

6.9 object

基于在对象之间直接构建继承关系的理念,可以用 object()来接收父对象,并返回一个以该父对象为原型的
新对象。

function object(p) {
  function F() {}
  F.prototype = p;
  return new F();
}

6.12 寄生式继承

var twoD = {
  name: "2d shape",
  dimensions: 2,
};
function triangle(s, h) {
  var that = object(twoD); //把twoD对象全属性拷贝进that对象
  that.name = "Triangle";
  that.getArea = function () {
    return (this.side * this.height) / 2;
  };
  that.side = s;
  that.height = h;
  return that;
}

6.14 本章小结

实现继承的方法大致上分为两类:

  • 基于构造器工作模式
  • 基于对象工作模式

实现继承的方法
实现继承的方法
实现继承的方法

6.15 案例学习:图形绘制

未完成

第七章、浏览器环境

7.3 BOM

7.3.1 Window 对象
window.open("新URL", "新窗口名", "以逗号分割的功能性列表");
window.close();
window.moveTo(x, y);
window.moveBy(x, y);
window.resizeTo(x, y);
window.resizeBy(x, y);
window.alert();
window.prompt(); //点击确认返回相应文本,点击取消返回null
window.confirm(); //点击确认返回true,点击取消返回false
window.setTimeout(); //指定多长时间后执行代码
window.setInterval(); //指定每隔多长时间执行代码
7.3.2 navigation 对象

navigation.userAgent 是一个用户浏览器识别的长字符串,但不要过分依赖这种用户代理字符串,
浏览器能力检测是更好地选择

  • 这种字符串很难追踪到所有的浏览器以及其各种版本
  • 这种字符串可以被修改
7.3.3 location 对象

localtion 对象的完整属性:

  • href
  • hash
  • host
  • hostname
  • port
  • protocol
  • search

location 对象的方法:

  • reload()重载某页面
  • assign()打开新 URL,并在历史记录中生成新纪录
  • replace()与 assign()相同,但不会生成新纪录
7.3.4 history 对象

history.forward();history.back();

7.3.5 screen 对象
screen.width();
screen.availwidth();

7.4 DOM

7.4.2 DOM 节点的访问
hasChildNodes()方法用于判断一个节点是否存在子节点
hasAttributes()方法用于检查该元素中书否存在属性
document.documentElement.childNodes.length; //2
//任何节点都可以通过自身的parentNode来访问它的父节点
document.documentElement.parentNode; //<html>
document.getElementsByTagName();
document.getElementsByName();
document.getElementById();
nextSibling/previousSibling;
firstChild/lastChild
7.4.4 新建节点
createElement();
var myp = document.createElement("p");
createTextNode(); //新建文本节点
appendChild();
document.body.appendChild(myp);
cloneNode(true); //true深拷贝 false浅拷贝
insertBefore(要插入的节点, 参照节点);
replaceChild(要插入的节点, 要替换的节点);
removeChild(要移除的节点);

7.5 事件

7.5.3 DOM 的事件监听器
addEventListener('事件类型',函数指针[,false]);
removeEventListener('事件类型',函数指针[,false]);
//匿名函数所定义的监听器是不能被移除的

该方法基于某一节点对象来调用,第三个参数决定代码是否采用事件捕捉,可选的,为了适应更多的浏览器,我们一般将其设置为 false,即采用事件冒泡。

7.6 XMLHttpRequest 对象

//创建xhr对象
var xhr;
if (window.XMLHttpRequest) {
  xhr = new XMLHttpRequest();
} else {
  xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//设置一个能触发readystatechange事件的事件监听器,及处理响应程序
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    console.log(xhr.responseText);
  }
};
//open(请求类型,请求目标URL,是否异步请求)
xhr.open("GET", "somefile.txt", true);
//发送请求
xhr.send("");

7.8 练习题

2.3;
function include(js) {
  var script = document.createElement("script");
  script.src = js;
  document.body.appendChild(script);
}
include("somescript.js");
3.1;
var myevent = {
  addListener: function (el, type, fn) {
    if (typeof window.addEventListener === "function") {
      myevent.addListener = function (el, type, fn) {
        el.addEventListener(type, fn, false);
      };
    } else if (typeof window.attachEvent === "function") {
      //code for IE
      myevent.addListener = function (el, type, fn) {
        el.attachEvent("on" + type, fn);
      };
    } else {
      // code for older browsers
      myevent.addListener = function (el, type, fn) {
        el["on" + type] = fn;
      };
    }
    myevent.addListener(el, type, fn);
  },
  removeListener: function (el, type, fn) {
    if (typeof window.removeEventListener === "function") {
      myevent.removeListener = function (el, type, fn) {
        el.removeEventEventListener(type, fn, false);
      };
    } else if (typeof window.detachEvent === "function") {
      //code for IE
      myevent.removeListener = function (el, type, fn) {
        el.detachEvent("on" + type, fn);
      };
    } else {
      // code for older browsers
      myevent.removeListener = function (el, type, fn) {
        el["on" + type] = null;
      };
    }
    myevent.removeListener(el, type, fn);
  },
  getEvent: function (event) {},
  getTarget: function (event) {},
  stopPropagation: function (event) {},
  preventDefault: function (event) {},
};
4.1;
var ajax = {
  request: function (url, requestType, queryString) {
    var xhr;
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
    } else {
      xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
      }
    };
    xhr.open(requestType, url, true);
    xhr.send("");
  },
};
ajax.request("some.txt", "get");

第八章、编程模式与设计模式

8.1 编程模式

8.1.2 命名空间与初始化分支模式

为了减少命名冲突,最好的办法是将变量和方法定义在不同的命名空间中,这种方法的实质是只定义一个全局变量,
并将其他的方法和属性定义为该变量的属性。

var mySpace = {};
mySpace.event = {
    addListener:null,
    removeListener:null
    ……
}
if(typeof window.addEventListener === 'function'){
    mySpace.event.addListener = function(el,type,fn){
        el.addEventListener(type,fn,false);
    };
    mySpace.event.removeListener = function(el,type,fn){
        el.removeEventListener(type,fn,false);
    };
}else if(typeof window.attachEvent === 'function'){ //code for IE
    mySpace.event.addListener = function(el,type,fn){
        el.attachEvent('on'+type,fn);
    };
    mySpace.event.removeListener = function(el,type,fn){
        el.detachEvent('on'+type,fn);
    };
}else{  // code for older browsers
    mySpace.event.addListener = function(el,type,fn){
        el['on' + type] = fn;
    };
    mySpace.event.removeListener = function(el,type,fn){
        el['on' + type] = null;
    };
}
8.1.4 延迟定义模式
var mySpace = {};
mySpace.event = {
  addListener: function (el, type, fn) {
    if (typeof window.addEventListener === "function") {
      mySpace.event.addListener = function (el, type, fn) {
        el.addEventListener(type, fn, false);
      };
    } else if (typeof window.attachEvent === "function") {
      //code for IE
      mySpace.event.addListener = function (el, type, fn) {
        el.attachEvent("on" + type, fn);
      };
    } else {
      // code for older browsers
      mySpace.event.addListener = function (el, type, fn) {
        el["on" + type] = fn;
      };
    }
    mySpace.event.addListener(el, type, fn);
  },
};
8.1.5 配置对象

该模式适用于有很多参数的函数或方法

用单个对象来替代多个参数有以下几点优势:

  • 不用考虑参数的顺序
  • 可以跳过某些参数的设置
  • 函数的扩展性强
  • 代码可读性好
var myapp = {};
myapp.dom = {};
myapp.dom.Button = function (text, conf) {
  var type = conf.type || "submit";
  var font = conf.font || "microsoftyahei";
  //……
};
//使用方法如下:
var config = {
  font: "Arial,Verdana,microsoftyahei",
  color: "#fff",
};
new myapp.dom.Button("lalala", config);
8.1.6 私有属性和方法
8.1.7 特权函数
8.1.8 私有函数的公有化
8.1.9 自执行函数
(function () {
  // code in here
})();
//该模式特写适用于某些脚本加载时所执行的一次性初始化工作
8.1.10 链式调用

构造器返回的是新建对象的 this 指针,我们可以使用这些方法所返回的实例来调用其他方法

document.body.appendChild(
  new mySpace.dom.Element("span").setText("hello").setStyle("color", "red")
);
8.1.11 JSON

var obj = JSON.parse(xhr.responseText);

8.2 设计模式

8.2.2 单件模式
8.2.3 工厂模式
8.2.4 装饰器模式
8.2.5 观察者模式

文章目录

  1. 第一章、引言
    1. 1.5 面向对象的程序设计常用概念
  2. 第二章、基本数据类型、数组、循环及条件表达式
    1. 2.3 基本数据类型
      1. 2.3.2 指数表示法
      2. 2.3.4 惰性求值
    2. 2.9 练习题
  3. 第三章、函数
    1. 3.1 函数
      1. 3.1.2 函数参数
    2. 3.3 函数的作用域
      1. 3.4.2 回调函数
      2. 3.4.4 自调函数
      3. 3.4.5 私有函数
      4. 3.4.7 能重写自己的函数
    3. 3.5 闭包
      1. 3.5.1 作用域链
      2. 3.5.2 词法作用域
      3. 3.5.3 利用闭包突破作用域链
        1. 3.5.3.1 闭包#1
        2. 3.5.3.3 相关定义与闭包#3
        3. 3.5.3.4 循环中的闭包
    4. 3.7 练习题
  4. 第四章、对象
    1. 4.1 从数组到对象
      1. 4.1.2 哈希表、关联型数组
      2. 4.1.3 访问对象属性
      3. 4.1.7 构造器函数
      4. 4.1.8 全局对象
      5. 4.1.9 构造器属性
      6. 4.1.12 传递对象
    2. 4.2 内建对象
      1. 4.2.1 Object
      2. 4.2.2 Array
      3. 4.2.3 Function
        1. 4.2.3.1 Function 对象的属性:
        2. 4.2.3.2 Function 对象的方法
        3. 4.2.3.3 重新认识 arguments 对象
      4. 4.2.4 Boolean
      5. 4.2.5 Number
      6. 4.2.6 String
      7. 4.2.7 Math
      8. 4.2.8 Date
      9. 4.2.9 RegExp
        1. 4.2.9.1 RegExp 对象的属性
        2. 4.2.9.2 RegExp 对象的方法
        3. 4.2.9.3 以正则表达式为参数的字符串方法
      10. 4.2.10 Error 对象
    3. 4.4 练习题
  5. 第五章、原型
    1. 5.1 原型属性
      1. 5.1.4 利用自身属性重写原型属性
    2. 5.2 扩展内建对象
      1. 5.2.2 原型陷阱
    3. 5.4 练习题
  6. 第六章、继承
    1. 6.1 原型链
      1. 6.1.1 原型链示例
      2. 6.1.2 将共享属性迁移到原型中
    2. 6.2 只继承于原型
    3. 6.3 uber–子对象访问父对象的方式
    4. 6.8 深拷贝
    5. 6.9 object
    6. 6.12 寄生式继承
    7. 6.14 本章小结
    8. 6.15 案例学习:图形绘制
  7. 第七章、浏览器环境
    1. 7.3 BOM
      1. 7.3.1 Window 对象
      2. 7.3.2 navigation 对象
      3. 7.3.3 location 对象
      4. 7.3.4 history 对象
      5. 7.3.5 screen 对象
    2. 7.4 DOM
      1. 7.4.2 DOM 节点的访问
      2. 7.4.4 新建节点
    3. 7.5 事件
      1. 7.5.3 DOM 的事件监听器
    4. 7.6 XMLHttpRequest 对象
    5. 7.8 练习题
  8. 第八章、编程模式与设计模式
    1. 8.1 编程模式
      1. 8.1.2 命名空间与初始化分支模式
      2. 8.1.4 延迟定义模式
      3. 8.1.5 配置对象
      4. 8.1.6 私有属性和方法
      5. 8.1.7 特权函数
      6. 8.1.8 私有函数的公有化
      7. 8.1.9 自执行函数
      8. 8.1.10 链式调用
      9. 8.1.11 JSON
    2. 8.2 设计模式
      1. 8.2.2 单件模式
      2. 8.2.3 工厂模式
      3. 8.2.4 装饰器模式
      4. 8.2.5 观察者模式