JavaScript学习笔记

JavaScript学习笔记

1.六种数据类型
    原始类型:
        number
        string
        boolean
        null
        undefined
    对象类型:
        object

2.隐式转换
    "37" - 7 // 30
    "37" + 7 // 377

3.包装对象
    var str = "string"; // 基本类型
    // 为什么基本类型变量,可以使用length方法呢?
    // 这里js会把str包装成对象变量,调用完length方法后,把临时对象销毁掉。
    a.length; 

4.类型检测
    typeof:适合基本类型及function检测,遇到null失效。可以使用obj === null 来判断。
    instanceof:适合自定义对象,也可以用来检测原生对象,在不同iframewindow间检测时失效。
    Object.prototype.toString
    constructor
    duck type

5.表达式

6.运算符
    一元运算符: +num
    二元运算符: a + b
    三元运算符: c ? a : b

    特殊运算符:
        条件运算符: c ? a : b
        逗号运算符: a,b
        delete: delete obj.x
        in: "document" in window
        instanceof: obj instanceof Func
        new: new ClassName()
        this: return this;
        typeof: typeof 100;
        void: void(0)

7.语句,严格模式

    7.1 block块语句: {} 
    注意:没有块级作用域 eg:for循环中的i变量在外部也可以访问。

    7.2 声明语句: var a = 1;
    注意:var a = b = 1;会隐式把b变成全局变量,最好写成var a = 1, b = 1; 

    7.3 try catch语句: 
        try{

        }catch(ex){

        }

    7.4 function语句:
        // 函数声明,会预先声明,可以在函数定义前调用都可以的。
        function fd() {
            return true;
        }
        // 函数表达式
        var fe = function(){

        }

    7.5 switch语句
        switch(val){
            case 1:
                // do sth
                break;
            default:
                // do sth
                break;
        }

    7.6 严格模式:是一种特殊的运行模式,它修复了部分语言上的不足,提供更强的错误检查,并增强安全性。
        function func() {
            'use strict'; // 关键字,进行严格模式
        }

8.对象
    对象的属性是无序的
    对象的属性的key值是字符串

    8.1创建对象,原型链
        // 第一种方法
        var obj1 = {x:1,y:2}; 

        // 第二种方法
        function foo(){}
        foo.prototype.z = 3;

        var obj = new foo();
        obj.x = 1;
        obj.y = 2;

        obj.x; // 1
        obj.y; // 2
        obj.z; // 3
        typeof obj.toString; // 'function'
        'z' in obj; // true
        obj.hasOwnProperty('z'); // false

        // 第三种方法
        var obj = Object.create({x:1});

    8.2读写对象属性

        8.2.1属性读写
            var obj = {x:1,y:2};
            // 第一种方法
            obj.x;
            // 第二种方法
            obj["y"];
            // 第三种方法,注意:使用in关键字,可能会把原型链上的属性也获取出来,而且顺序是不确定的。
            var p;
            for(p in obj){
                console.log(obj[p]);
            }

        8.2.2getter/setter方法
            var man = {
                name : 'Bosn',
                weibo : '@Bosn',
                get age() {
                    return new Date().getFullYear() - 1988;
                },
                set age(val) {
                    console.log('Age can\'t be set to ' + val);
                }
            }
            console.log(man.age); // 27
            man.age = 100; // Age can't be set to 100
            console.log(man.age); // still 27

    8.3属性标签
        // 1.获取属性标签
        Object.getOwnPropertyDescriptor({pro:true},"pro");

        // 2.定义单个属性标签
        var person = {};
        Object.defineProperty(person,'name',{
            configurable:false, // 表示是否可以修改
            writable:false, // 表示是否可以重写
            enumerable:true, // 表示是否可以枚举
            value:"mike"
        });
        person.name; // mike
        person.name = "Tim";
        person.name; // still mike
        delete person.name; // false

        // 3.定义多个属性标签
        Object.defineProperties(person,{
            title: {value: "test", enumerable:true},
            salary: {value: 50000, enumerable:true, writable:true}
        });

    8.4对象标签

        8.4.1.__proto__原型标签

        8.4.2.class标签
            var toString = Object.prototype.toString;
            function getType(o){return toString.call(o).slice(8,-1);};

            toString.call(null); // "[object Null]"
            getType(null); // "Null"
            getType(undefined); // "Undefined"
            getType(1); // "Number"
            getType(new Number(1)); // "Number"
            typeof new Number(1); // "object"
            getType(true); // "Boolean"
            getType(new Boolean(true)); // "Boolean"

        8.4.3.extensible标签
            var obj = {x : 1, y : 2};
            Object.isExtensible(obj); // true
            Object.preventExtensions(obj);
            Object.isExtensible(obj); // false
            obj.z = 1;
            obj.z; // undefined, add new property failed
            Object.getOwnPropertyDescriptor(obj, 'x');
            // Object {value: 1, writable: true, enumerable: true, configurable: true}

            Object.seal(obj);
            Object.getOwnPropertyDescriptor(obj, 'x');
            // Object {value: 1, writable: true, enumerable: true, configurable: false}
            Object.isSealed(obj); // true

            Object.freeze(obj);
            Object.getOwnPropertyDescriptor(obj, 'x');
            // Object {value: 1, writable: false, enumerable: true, configurable: false}
            Object.isFrozen(obj); // true

            // [caution] not affects prototype chain!!!

    8.5序列化,其他对象方法

        8.5.1自定义序列化
            var obj = {
                x : 1,
                y : 2,
                o : {
                    o1 : 1,
                    o2 : 2,
                    // key值必须为toJSON
                    toJSON : function () {
                        return this.o1 + this.o2;
                    }
                }
            };
            JSON.stringify(obj); // "{"x":1,"y":2,"o":3}"

        8.5.2其他对象方法
            var obj = {x : 1, y : 2};
            obj.toString(); // "[object Object]"
            obj.toString = function() {return this.x + this.y};
            "Result " + obj; // "Result 3", by toString

            +obj; // 3, from toString

            obj.valueOf = function() {return this.x + this.y + 100;};
            +obj; // 103, from valueOf

            "Result " + obj; // still "Result 3"

9.数组
    JS的数组是弱类型的,数组中可以含有不同类型的元素。

    9.1 创建数组
        // 1.创建数组第一种方式
        var arr = [1,true,null,undefined,{x:1},[1,2,3]];
        // 2.创建数组第二种方式
        var arr = new Array(true,false,null,1,2,"hi");

    9.2 数组迭代
        Array.prototype.x = 'inherited';

        for(i in arr) {
            console.log(arr[i]); // 1, 2, 3, 4, 5, inherited
        }

        for(i in arr) {
            if (arr.hasOwnProperty(i)) {
                console.log(arr[i]); // 1, 2, 3, 4, 5
            }
        }

    9.3 二维数组,稀疏数组
        // 二维数组
        var arr = [[0,1],[2,3],[4,5]];
        var i = 0, j = 0;
        var row;
        for (; i < arr.length; i++) {
             row = arr[i];
             console.log('row ' + i);
             for (j = 0; j < row.length; j++) {
                  console.log(row[j]);
             }
        }

        // 稀疏数组并不含有从0开始的连续索引。一般length属性值比实际元素个数大
        var arr1 = [undefined];
        var arr2 = new Array(1);
        0 in arr1; // true
        0 in arr2; // false
        arr1.length = 100;
        arr1[99] = 123;
        99 in arr1; // true
        98 in arr1; // false
        var arr = [,,];
        0 in arr; // false

    9.4 数组方法

        9.4.1 Array.prototype.join --> 将数组转换为字符串
            var arr = [1, 2, 3];
            arr.join(); // "1,2,3"
            arr.join("_"); // "1_2_3"

            function repeatString(str, n) {
                 return new Array(n + 1).join(str);
            }
            repeatString("a", 3); // "aaa"
            repeatString("Hi", 5); // "HiHiHiHiHi"

        9.4.2 Array.prototype.reverse --> 将数组逆序
            var arr = [1, 2, 3];
            arr.reverse(); // [3, 2, 1]
            arr; // [3, 2, 1] 原数组会被修改

        9.4.3 Array.prototype.sort  --> 排序
            var arr = ["a", "d", "c", "b"];
            arr.sort(); // ["a", "b", "c", "d"]

            arr = [13, 24, 51, 3]; // 会把数字转换成字符串再进行比较,而不是按照数字排序
            arr.sort(); // [13, 24, 3, 51]
            arr; // [13, 24, 3, 51] 原数组被修改

            arr.sort(function(a, b) {
                 return a - b;
            }); // [3, 13, 24, 51]

            arr = [{age : 25}, {age : 39}, {age : 99}];
            arr.sort(function(a, b) {
                 return a.age - b.age;
            });
            arr.forEach(function(item) {
                 console.log('age', item.age);
            });
            // result:
            // age 25
            // age 39
            // age 99

        9.4.4 Array.prototype.concat --> 数组合并
            var arr = [1, 2, 3];
            arr.concat(4, 5); // [1, 2, 3, 4, 5]
            arr; // [1, 2, 3] 原数组未被修改

            arr.concat([10, 11], 13); // [1, 2, 3, 10, 11, 13]

            arr.concat([1, [2, 3]]); // [1, 2, 3, 1, [2, 3]]

        9.4.5 Array.prototype.slice --> 返回部分数组
            var arr = [1, 2, 3, 4, 5];
            arr.slice(1, 3); // [2, 3] 原数组未被修改
            arr.slice(1); // [2, 3, 4, 5]
            arr.slice(1, -1); // [2, 3, 4]
            arr.slice(-4, -3); // [2]

        9.4.6 Array.prototype.splice --> 数组拼接
            var arr = [1, 2, 3, 4, 5];
            arr.splice(2); // returns [3, 4, 5]
            arr; // [1, 2]; 原数组被修改

            arr = [1, 2, 3, 4, 5];
            arr.splice(2, 2); // returns [3, 4]
            arr; // [1, 2, 5];

            arr = [1, 2, 3, 4, 5];
            arr.splice(1, 1, 'a', 'b'); // returns [2]
            arr; // [1, "a", "b", 3, 4, 5]

        9.4.7 Array.prototype.forEach --> 数组遍历
            var arr = [1, 2, 3, 4, 5];
            arr.forEach(function(x, index, a){
                console.log(x + '|' + index + '|' + (a === arr));
            });
            // 1|0|true
            // 2|1|true
            // 3|2|true
            // 4|3|true
            // 5|4|true

        9.4.8 Array.prototype.map --> 数组映射
            var arr = [1, 2, 3];
            arr.map(function(x) {
                 return x + 10;
            }); // [11, 12, 13]
            arr; // [1, 2, 3] 数组未被修改

        9.4.9 Array.prototype.filter --> 数组过滤
            var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            arr.filter(function(x, index) {
                 return index % 3 === 0 || x >= 8;
            }); // returns [1, 4, 7, 8, 9, 10]
            arr; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 原数组未被修改

        9.4.10 Array.prototype.every & some --> 数组判断
            var arr = [1, 2, 3, 4, 5];
            // 每个元素都要满足
            arr.every(function(x) {
                 return x < 10;
            }); // true

            arr.every(function(x) {
                 return x < 3;
            }); // false

            var arr = [1, 2, 3, 4, 5];
            // 有一个元素满足即可
            arr.some(function(x) {
                 return x === 3;
            }); // true

            arr.some(function(x) {
                 return x === 100;
            }); // false

        9.4.11 Array.prototype.reduce&reduceRight --> 把数组元素聚合成一个结果
            var arr = [1, 2, 3];
            var sum = arr.reduce(function(x, y) {
                 return x + y
            }, 0); // 6
            arr; //[1, 2, 3] 原数组未被修改

            arr = [3, 9, 6];
            var max = arr.reduce(function(x, y) {
                 console.log(x + "|" + y);
                 return x > y ? x : y;
            });
            // 3|9
            // 9|6
            max; // 9

            // 从右边可以
            max = arr.reduceRight(function(x, y) {
                 console.log(x + "|" + y);
                 return x > y ? x : y;
            });
            // 6|9
            // 9|3
            max; // 9

        9.4.12 Array.prototype.indexOf&lastIndexOf --> 数组检索
            var arr = [1, 2, 3, 2, 1];
            arr.indexOf(2); // 1
            arr.indexOf(99); // -1
            arr.indexOf(1, 1); // 4
            arr.indexOf(1, -3); // 4
            arr.indexOf(2, -1); // -1
            arr.lastIndexOf(2); // 3
            arr.lastIndexOf(2, -2); // 3
            arr.lastIndexOf(2, -3); // 1

        9.4.13 Array.isArray --> 判断是否有数组
            Array.isArray([]); // true
            [] instanceof Array; // true
            ({}).toString.apply([]) === '[object Array]'; // true
            [].constructor === Array; // true

    小结: 
        1.数组 VS 一般对象
            相同点:
                都可以继承
                数组是对象,对象不一定是数组
                都可以当做对象添加删除属性

            不同点:
                数组自动更新length
                按索引访问数组常常比访问一般对象属性明显迅速。
                数组对象继承Array.prototype上的大量数组操作方法

        2.数组 VS 字符串
                var str = "hello world";
                str.charAt(0); // "h"
                str[1]; // e

                Array.prototype.join.call(str, "_");
                // "h_e_l_l_o_ _w_o_r_l_d"

10.函数

    10.1 创建函数

        // 1.函数声明:会被前置
        function add (a, b) {
            a = +a;
            b = +b;
            if (isNaN(a) || isNaN(b)) {
            return;
            }
            return a + b;
        }

        // 2.函数表达式
        // function variable
        var add = function (a, b) {
            // do sth
        };
        // IEF(Immediately Executed Function) 匿名函数表达式
        (function() {
            // do sth
        })();
        // first-class function 把函数对象作为返回值
        return function() {
            // do sth
        };
        // NFE (Named Function Expression) 命名式函数表达式
        var add = function foo (a, b) {
            // do sth
        };

    10.2 命名函数表达式(NFE)
        var func = function nfe() {};
        alert(func === nfe); // IE6~8为false,IE9报错,nfe为undefined
        // 递归调用
        var func = function nfe() {/** do sth.**/ nfe();}

    10.3 Function构造器
        var func = new Function('a', 'b', 'console.log(a + b);');
        func(1, 2); // 3
        var func = Function('a', 'b', 'console.log(a + b);');
        func(1, 2); // 3

        // 案例1: localVal仍为局部变量
        Function('var localVal = "local"; console.log(localVal);')();
        console.log(typeof localVal);
        // result: local, undefined

        // 案例2: localVal不可访问,全局变量global可以访问
        var globalVal = 'global';
        (function() {
        var localVal = 'local';
        Function('console.log(typeof localVal, typeof globalVal);')();
        })();
        // result: undefined, string

    10.4 this
        10.4.1 全局this
            console.log(this.document === document); // true
            console.log(this === window); // true
            this.a = 37;
            console.log(window.a); // 37

        10.4.2 一般函数的this
            function f1(){
                return this;
            }
            f1() === window; // true, global object

            function f2(){
                "use strict"; // see strict mode
                return this;
            }
            f2() === undefined; // true

        10.4.3 作为对象方法的函数的this
            var o = {
                prop: 37,
                f: function() {
                return this.prop;
                }
            };
            console.log(o.f()); // logs 37

            var o = {prop: 37};
            function independent() {
                return this.prop;
            }
            o.f = independent;
            console.log(o.f()); // logs 37

        10.4.4 对象原型链上的this
            var o = {f:function(){ return this.a + this.b; }};
            var p = Object.create(o);
            p.a = 1;
            p.b = 4;
            console.log(p.f()); // 5

        10.4.5 get/set方法与this
            function modulus(){
                return Math.sqrt(this.re * this.re + this.im * this.im);
            }
            var o = {
            re: 1,
            im: -1,
            get phase(){
                return Math.atan2(this.im, this.re);
            }
            };
            Object.defineProperty(o, 'modulus', {
            get: modulus, enumerable:true, configurable:true});
            console.log(o.phase, o.modulus); // logs -0.78 1.4142

        10.4.6 构造器中的this
            function MyClass(){
                this.a = 37;
            }
            var o = new MyClass();
            console.log(o.a); // 37
            function C2(){
                this.a = 37;
                return {a : 38};
            }
            o = new C2();
            console.log(o.a); // 38

        10.4.7 call/apply方法与this
            function add(c, d){
                return this.a + this.b + c + d;
            }
            var o = {a:1, b:3};
            add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
            add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
            function bar() {
                console.log(Object.prototype.toString.call(this));
            }
            bar.call(7); // "[object Number]"

        10.4.8 bind方法与this
            function f(){
                return this.a;
            }
            var g = f.bind({a : "test"});
            console.log(g()); // test
            var o = {a : 37, f : f, g : g};
            console.log(o.f(), o.g()); // 37, test

    10.5 函数属性 & arguments

        10.5.1 arguments
            function foo(x, y, z) {
                arguments.length; // 2 实参个数
                arguments[0]; // 1
                arguments[0] = 10;
                x; // change to 10;
                arguments[2] = 100;
                z; // still undefined !!!
                arguments.callee === foo; // true
            }
            foo(1, 2);
            foo.length; // 3 形参个数
            foo.name; // "foo" 函数名

        10.5.2 apply/call方法
            function foo(x, y) {
                'use strict';
                console.log(x, y, this);
            }
            foo.apply(null); // undefined, undefined, null
            foo.apply(undefined); // undefined, undefined, undefined

        10.5.3 bind方法
            this.x = 9;
            var module = {
                x: 81,
                getX: function() { return this.x; }
            };
            module.getX(); // 81
            var getX = module.getX;
            getX(); // 9
            var boundGetX = getX.bind(module);
            boundGetX(); // 81

        10.5.4 bind与currying
            function add(a, b, c) {
                return a + b + c;
            }
            var func = add.bind(undefined, 100); // 定义a为100
            func(1, 2); // 103
            var func2 = func.bind(undefined, 200); // 定义b为200
            func2(10); // 310

        10.5.5 bind与new
            function foo() {
                this.b = 100;
                return this.a;
            }
            var func = foo.bind({a:1});
            func(); // 1
            new func(); // {b : 100}


11.闭包
    11.1 闭包的概念
        闭包就是能够读取其他函数内部变量的函数。

        // 1.取不到局部变量n 
        function f1(){
             var n=999;
        }
        alert(n); // error

        // 可以通过闭包获取局部变量n
       function f1(){
           var n=999;
           function f2(){
             alert(n); 
           }
           return f2;
        }
         var result=f1();
         result(); // 999

    11.2 闭包-常见错误之循环闭包

        // addEventListener是一个回调函数,当你点击的时候才会动态去拿i的值,所以都是4
        document.body.innerHTML = "<div id=div1>aaa</div>"
        + "<div id=div2>bbb</div><div id=div3>ccc</div>";
        for (var i = 1; i < 4; i++) {
            document.getElementById('div' + i).
            addEventListener('click', function() {
                alert(i); // all are 4!
            });
        }

        // 绑定一个立即执行的闭包函数
        document.body.innerHTML = "<div id=div1>aaa</div>"
        + "<div id=div2>bbb</div><div id=div3>ccc</div>";
        for (var i = 1; i < 4; i++) {
            !function(i) {
                document.getElementById('div' + i).
                addEventListener('click', function() {
                    alert(i); // 1, 2, 3
                });
            }(i);
        }

    11.3 闭包-封装

        (function() {
            var _userId = 23492;
            var _typeId = 'item';
            var export = {};
            function converter(userId) {
                return +userId;
            }
            export.getUserId = function() {
                return converter(_userId);
            }
            export.getTypeId = function() {
                return _typeId;
            }
            window.export = export;
        }());

        export.getUserId(); // 23492
        export.getTypeId(); // item
        export._userId; // undefined
        export._typeId; // undefined
        export.converter; // undefined

12.作用域

    12.1 全局,函数,eval

        var a = 10; // 全局作用域

        (function() {
            var b = 20; // 函数作用域
        })();

        console.log(a); // 10
        console.log(b); // error, b in not defined
        // javascript中没有块级作用域,这里定义的item还是全局作用域
        for (var item in {a : 1, b : 2}) {
            console.log(item);
        }
        console.log(item); // item still in scope

        eval("var a = 1;"); // eval作用域

    12.2 作用域链
        function outer2() {
            var local2 = 2;
            function outer1() {
                var local1 = 1;
                // visit local1, local2 or global3
                console.log(local1 + "," + local2 + "," + global3);
            }
            outer1();
        }
        var global3 = 3;
        outer2();

        // new Function()方式访问不到变量i
        function outer() {
            var i = 1;
            var func = new Function("console.log(typeof i);");
            func(); // undefined
        }
        outer();

    12.3 利用函数作用域封装
        // 通过()或者!来把函数声明变成函数表达式,里面的a,b变量对应也会变成局部变量
        (function() {
        // do sth here
            var a, b;
        })();

        !function() {
        // do sth here
            var a, b;
        }();

13. ES3(ECMAScript3)执行上下文

    13.1 执行上下文(Execution Context)

        console.log('EC0');
        function funcEC1() {
            console.log('EC1');
            var funcEC2 = function() {
            console.log('EC2');
                var funcEC3 = function() {
                    console.log('EC3');
                };
                funcEC3();
            }
            funcEC2();
        }
        funcEC1();
        // EC0 EC1 EC2 EC3

    13.2 变量对象

        变量对象(Variable Object, 缩写为VO)是一个抽象概念中的“对象”,它用于存储执行上下文中的:
            1. 变量
            2. 函数声明
            3. 函数参数

        activeExecutionContext = {
            VO : {
                data_var,
                data_func_declaration,
                data_func_arguments
            }
        };
        GlobalContextVO (VO === this === global)

    13.3 执行上下文和变量对象

        var a = 10; 
        function test(x) { 
            var b = 20;
        }
        test(30);

        // 对应关系如下:
        // 全局上下文环境中有个a变量和test函数
        VO(globalContext) = {
            a : 10,
            test : <ref to function>
        };
        // 函数上下文环境中有个变量b和参数a
        VO(test functionContext) = {
            x : 30,
            b: 20
        };

    13.4 全局执行上下文(浏览器)

        VO(globalContext) === [[global]];
        [[global]] = {
            Math : <...>,
            String : <...>,
            isNaN : function() {[Native Code]}
            ...
            ...
            window : global // applied by browser(host)
        };
        String(10); //[[global]].String(10);
        window.a = 10; // [[global]].window.a = 10
        this.b = 20; // [[global]].b = 20;
        GlobalContextVO (VO === this === global)

    13.5 函数中的激活对象

        VO(functionContext) === AO;
        AO = {
            arguments : <Arg0>
        };
        arguments = {
            callee,
            length,
            properties-indexes
        };

    13.6 变量初始化阶段

        VO按照如下顺序填充:
            1.函数参数
            (若未传⼊入,初始化该参数值为undefined)
            2.函数声明
            (若发生命名冲突,会覆盖)
            3.变量声明
            (初始化变量值为undefined,若发⽣生命名冲突,会忽略。)

        function test(a, b) {
            var c = 10;
            function d() {}
            var e = function _e() {};
            (function x() {});
            b = 20;
        }
        test(10);

        // 对应关系如下:
        AO(test) = {
            a: 10,
            b: undefined,
            c: undefined,
            d: <ref to func "d">
            e: undefined
        };

    13.7 代码执行阶段

        function test(a, b) {
            var c = 10;
            function d() {}
            var e = function _e() {};
            (function x() {});
            b = 20;
        }
        test(10);

        // 对应关系如下:
        AO(test) = {
            a: 10,
            b: 20,
            c: 10,
            d: <reference to FunctionDeclaration "d">
            e: function _e() {};
        };

    13.8 Demo

        alert(x); // function
        alert(a); // undefined
        alert(b); // undefined

        var x = 10;
        alert(x); // 10
        x = 20;
        function x() {}
        alert(x); // 20

        if (true) {
            var a = 1;
        } else {
            var b = true;
        }

        alert(a); // 1
        alert(b); // undefined

14.OOP(面向对象编程) 特性: 继承 封装 多态 抽象

    14.1 继承实例代码
        function Person(name,age){
            this.name = name;
            this.age = age;
        }

        Person.prototype.hi = function(){
            console.log("Hi,my name is " + this.name + ",I'm" + this.age + " years old now");
        };

        Person.prototype.LEGS_NUM = 2;
        Person.prototype.ARMS_NUM = 2;
        Person.prototype.walk = function(){
            console.log(this.name + " is walking");
        };

        function Student(name,age,className){
            Person.call(this,name,age);
            this.className = className;
        }

        Student.prototype = Object.create(Person.prototype);
        Student.prototype.constructor = Student;

        Student.prototype.hi = function(){
            console.log("Hi,my name is " + this.name + ",I'm" + 
            this.age + " years old now,and from " +
            this.className + "." );
        };

        Student.prototype.learn = function(subject){
            console.log(this.name + " is learning" + subject + "at" + 
            this.className + ".");
        }

        // test
        var mike = new Student("Mike",22,"Class 3,Grade 2");
        mike.hi(); // Hi,my name is Mike,I'm22years old now,and fromClass 3,Grade 2.
        mike.LEGS_NUM; // 2
        mike.walk(); // Mikeis walking
        mike.learn("math"); // Mikeis learningmathatClass 3,Grade 2.

    14.2 prototype对象属性

        Student.prototype.x = 101;
        mike.x; // 101

        // 可以看出对于已经实例化的对象,更改student的prototype属性并不会影响该实例所指向的proto原型
        Student.prototype = {y:2};
        mike.y; // undefined
        mike.x; // 101

        // 新创建一个实例则会影响
        var newStu = new Student("test",3,"class 1");
        newStu.x; // undefined
        newStu.y; // 2

        总结:
            1.动态修改prototype的属性的时候,是会影响所有实例的。
            2.动态修改整个prototype的话,是不会影响已经创建的实例,但会影响后续创建的实例。

    14.3 实现继承的方式

        function Person(){}
        function Student(){}

        // 第一种方法,错误,因为改变student的同时会把person的也改变了
        Student.prototype = Person.prototype;

        // 第二种方法,调用了Person的构造函数创建了一个实例
        // 但是假如构造函数需要传参的话,最好不要使用这种方式
        Student.prototype = new Person();

        // 第三种方法,ES5之后才支持,使用Object.create()方法
        Student.prototype = Object.create(Person.prototype);
        Student.prototype.constructor = Student;

        // 但是没关系,我们可以自己模拟create方法
        if(!Object.create){
            Object.create = function(proto){
                function F(){}
                F.prototype = proto;
                return new F;
            };
        }

    14.4 模拟重载
        // 因为JS是弱类型语法,所以对重载的支持需要自己模拟
        function Person() {
            var args = arguments;
            if(typeof args[0] === 'object' && args[0]) {
                if(args[0].name) {
                    this.name = args[0].name;
                }
                if(args[0].age) {
                    this.age = args[0].age;
                }
            } else {
                if(args[0]) {
                    this.name = args[0];
                }
                if(args[1]) {
                    this.age = args[1];
                }
            }
        }

        Person.prototype.toString = function() {
            return "name = " + this.name + ",age = " + this.age; 
        }

        var mike = new Person("Mike",22);
        mike.toString();

        var mike2 = new Person({name: "mike2", age: 22});
        mike2.toString();

    14.5 链式调用(模拟jquery)

        function ClassManager() {}
        ClassManager.prototype.addClass = function(str){
            console.log("Class:" + str + "added.");
            return this;
        };

        var manager = new ClassManager();
        manager.addClass("classA").addClass("classB").addClass("classC");

    14.6 抽象类(自定义模拟)

        function DetectorBase() {
            // 不想直接被调用,可以采取抛出异常的方式
            throw new Error("Abstract class can not be invoked directly!");
        }
        DetectorBase.detect = function(){console.log("Detection starting...");};
        DetectorBase.stop = function(){console.log("Detector stopped.");};
        DetectorBase.init = function(){throw new Error("Error");};

        function LinkDetector(){}
        LinkDetector.prototype = Object.create(Detector.prototype);
        LinkDetector.prototype.constructor = LinkDetector;

    14.7 实践--探测器

        !function(global) {
            function DetectorBase(configs) {
                // 必须使用new创建
                if(!this instanceof DetectorBase) {
                    throw new Error("Do not invoke without new.");
                }
                this.configs = configs;
                this.analyze();
            }


            DetectorBase.prototype.detect = function() {
                throw new Error("Not implemented");
            };

            DetectorBase.prototype.analyze = function() {
                console.log("analyzing...");
                this.data = "###data###";
            }

            function LinkDetector(links) {
                if(!this instanceof LinkDetector) {
                    throw new Error("Do not invoke without new.");
                }
                this.links = links;
                DetectorBase.apply(this,arguments);
            }

            function ContaninerDetector(containers) {
                if(!this instanceof ContaninerDetector) {
                    throw new Error("Do not invoke without new.");
                }
                this.containers = containers;
                DetectorBase.apply(this,arguments);
            }

            // inherit first 先继承
            inherit(LinkDetector,DetectorBase);
            inherit(ContaninerDetector,DetectorBase);

            // expand later 后扩展
            LinkDetector.prototype.detect = function() {
                console.log("Loading data:" + this.data);
                console.log("Link detection started.");
                console.log("Scaning links:" + this.links);
            };

            ContaninerDetector.prototype.detect = function() {
                console.log("Loading data:" + this.data);
                console.log("Container detection started.");
                console.log("Scaning links:" + this.containers);
            }

            // prevent from being altered
            Object.freeze(DetectorBase);
            Object.freeze(DetectorBase.prototype);
            Object.freeze(LinkDetector);
            Object.freeze(LinkDetector.prototype);
            Object.freeze(ContaninerDetector);
            Object.freeze(ContaninerDetector.prototype);

            // export to global object
            Object.defineProperties(global,{
                LinkDetector: {value: LinkDetector},
                ContaninerDetector: {value: ContaninerDetector},
                DetectorBase: {value: DetectorBase}
            });

            function inherit(subClass, superClass) {
                subClass.prototype = Object.create(superClass.prototype);
                subClass.prototype.constructor = subClass;
            }

        }(this);

        // 容器探测器
        var cd = new ContaninerDetector("#abc #def #ghi");
        // 链接探测器
        var ld = new LinkDetector("http://www.baidu.com http://www.taobao.com");

        cd.detect();
        ld.detect();

15.正则表达式

    15.1 正则表达式两种写法

        第一种://隔开
        /\d\d\d/.test("123"); // true
        /\d\d\d/.test("abc"); // false

        第二种:使用RegExp构造器
        new RegExp("Mike").test("Hi,Mike");

    15.2 特殊符转义(使用\)

        /\^abc/.test("^abc"); // true

    15.3 分组

        第一种:只是使用括号括起来,那么\1就表示分组的内容,即abc
        /(abc)\1/.test("abcabc"); // true

        第二种:使用(?:x)的形式,那么就没有\1表示分组内容的快捷方式
        /(?:abc)(def)\1/.test("abcdefdef"); // true

    15.4 三个flag(global,ignoreCase,multiline)

        /abc/gim.test("ABC"); //true

        RegExp("abc","mgi").test("ABC"); // true

    15.5 RegExp对象属性
        /abc/g.global // true
        /abc/g.ignoreCase // false
        /abc/g.multiline // false
        /abc/g.source // "abc"

    15.6 RegExp对象方法
        /abc/.exec("abcdef"); // "abc",正则的一个匹配方法
        /abc/.test("abcde"); // true
        /abc/.toString(); // "/abc/"

        var reg = /abc/;
        reg.compile("def"); // 可以改变正则的属性
        reg.test("def"); // true

    15.7 String类型与正则相关的方法(search/replace/match/split)

        "abcabcdef".search(/(abc)\1/); // 0
        "aabbbbcc".replace(/b+?/,"1"); // aa1bbbcc
        "aabbbbcc".match(/b+/); // ["bbbb"]
        "aabbbbccbbaa".match(/b+/g); // ["bbbb","bb"]
        "aabbbbccbbaa".split(/b+/); //["aa","cc","aa"]

相关原理图:

原型链

prototype属性

这里写图片描述

这里写图片描述

这里写图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值