笔记整理(四)

创建对象

  • 工厂模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.say = function(){
    console.log(this.name + ' is a ' + this.age + ' years old ' + this.job);
    };
    return o;
    }
    var person1 = createPerson('lily', 32, 'teacher');
    person1.say(); // "lily is a 32 years old teacher"
  • 构造函数模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.say = function(){
    console.log(this.name + ' is a ' + this.age + ' years old ' + this.job);
    };
    }
    // 当作构造函数调用
    var person1 = new Person('lily', 32, 'teacher');
    person1.say(); // "lily is a 32 years old teacher"
    // 作为普通函数调用(全局作用下调用函数,this指向Global对象,浏览器中就是window)
    Person('mu', 35, 'doctor');
    window.say();
    // 在另一个对象的作用域中调用
    var o = new Object();
    Person.call(o, 'chen', 20, 'student');
    o.say();
  • 原型模式

    • 新建函数时会创建一个prototype属性,该属性指向函数的原型;所有原型对象都会获得一个constructor属性,该属性包含一个指向prototype属性所在函数的指针
    • __proto__这个链接存在于实例person1与构造函数的原型对象Person Prototype之间,而不是存在于实例person1与构造函数Person之间
    • 原型中所有属性是被很多实例共享的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Person(){}
Person.prototype = {
// 原生的constructor属性是不可枚举的,重设后[[Enumerable]]值为true
constructor: Person,
name: "whiskey",
age: 20,
job: "student",
friends: ["chen", "lily"],
sayFriends: function(){
console.log(this.friends);
}
};
var person1 = new Person();
var person2 = new Person();
person2.friends.push("mu");
// 我们的初衷是只修改person2的friends属性
person1.sayFriends(); // ["chen", "lily", "mu"]
person2.sayFriends(); // ["chen", "lily", "mu"]
  • 组合使用构造函数模式和原型模式★★
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["lily", "chen"];
    }
    Person.prototype.say = function(){
    console.log(this.friends);
    };
    var person1 = new Person("whiskey", 20, "student");
    var person2 = new Person("tiny", 10, "dotaer");
    person2.friends.push("COCO");
    person1.say(); // ["lily", "chen"]
    person2.say(); // ["lily", "chen", "COCO"]

继承

  • 原型式继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    var person = {
    name: 'whiskey',
    friends: ['lily', 'mu'],
    say: function(){
    console.log(this.friends);
    }
    };
    var person1 = Object.create(person, {
    name: {
    value: 'fancypy'
    }
    });
    // 也可以通过person2.name的方式添加姓名
    // var person2 = Object.create(person);
    // person1.name = 'SNK';
    person1.say(); // ["lily", "mu"]
    console.log(person1.name); // "fancypy"
    person1.friends.push('coco');
    person1.say(); // ["lily", "mu", "coco"]
    // 对于不支持Object.create()的浏览器,可以使用自定义函数
    function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
    }
  • 组合继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // 组合继承
    function Parent(name) {
    this.name = name;
    }
    Parent.prototype.sayName = function() {
    console.log('hi, ' + this.name);
    };
    function Child(name, age) {
    Parent.call(this, name); // 继承属性
    this.age = age;
    }
    // 继承方法
    // Child.prototype = new Parent();
    Child.prototype = Object.create(Parent.prototype); //优于上面的
    Child.prototype.constructor = Child;
    // 定义自己的方法
    Child.prototype.sayAge = function() {
    console.log('I\'m ' + this.age + ' years old');
    };
    var lily = new Child('Lily', 20);
    console.log(lily.sayName()); // "hi, Lily"
    console.log(lily.sayAge()); // "I'm 20 years old"
    var whiskey = new Child('whiskey', 30);
    console.log(whiskey.sayName()); // "hi, whiskey"
    console.log(whiskey.sayAge()); // "I'm 30 years old"

事件委托

  • 事件委托允许我们不必为某些特定的节点添加事件监听器,而是将事件监听器添加到这些节点的某个父节点上。事件监听器分析冒泡事件,去找到匹配的子节点元素,然后做出相应的事件响应。比较常见的情况是用ul元素来处理子元素li的事件
  • 优点
    • 减少事件注册,节省内存
    • 对于新增的子节点无需重新绑定事件
  • 缺点
    • 仅限于支持事件冒泡的事件
1
2
3
4
5
6
7
8
<!-- 为了测试效果,忽略不规范的HTML嵌套 -->
<ul id='list'>
<li>111</li>
<p>222</p>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
1
2
3
4
5
6
7
8
9
10
window.onload = function() {
var list = document.querySelector('#list');
list.addEventListener('click', fn);
// 监听ul节点,通过if判断,当目标元素是li时弹出,点击p元素无效
function fn(e) {
if (e.target.nodeName == 'LI') {
alert(e.target.innerHTML);
}
}
};

在线demo

正则表达式

  • \b:代表单词的开头或结尾,也就是单词的分界处。只匹配一个位置

    1
    2
    /\bis\b/.test('this') // false
    /\bis\b/.test('that is tom') // true
  • .:匹配除了换行符\n以外的任意字符

  • \d:匹配一位数字
  • \s:匹配任意空白符,包括空格、制表符、换行符、中文全角空格
  • \w:匹配字母或者数字或者下划线或汉字
  • ^:匹配字符串的开始
  • $:匹配字符串的结束
  • \:字符转义 \.匹配.本身
  • *:重复0次或更多次
  • +:重复1次或更多次
  • ?:重复0次或1次
  • {n}:重复n次
  • {n,}:重复n次或更多次
  • {n,m}:重复n到m次,逗号前后不能有空格
  • []:匹配没有预定义的元字符的字符集合

    1
    2
    [aeiou]匹配aeiou中任何一个字母
    [0-9]等价于\d
  • |:分支条件,从左到右满足条件就不管其他了

    1
    "into".match(/in|int/) // 匹配in,不会匹配int
  • g:执行一个全局匹配,即找到所有匹配,而不是找到第一个之后就停止

  • i:忽略大小写
  • m^$能匹配行结束符
  • \W:大写W,匹配任意不是字母、数字、下划线、汉字的字符
  • \S:大写S,匹配任意不是空白符的字符
  • \D:大写D,匹配任意非数字的字符
  • \B:大写B,匹配不是单词开头或结束的位置
  • [^aeiou]:匹配除了aeiou外的任意字符
  • 元字符:(,[,{,^,$,|,),?,*,+,.,],},匹配本身的时候需要转义
  • ():捕获组,用$1表示第一组捕获
  • (?:):表示非捕获组
  • regexp.exp:执行正则表达式,返回一个数组,数组中的第一项是匹配的整个字符串,之后每一项对应捕获组(匹配+捕获)
  • regexp.test:测试正则表达式,返回布尔值
  • String.match:返回包含结果的数组,数组中的第一项是匹配的整个字符串,之后每一项对应捕获组,没有匹配项返回null
  • String.replace:搜索+替换
  • String.search:匹配返回该str首次出现的index,不匹配返回-1