Javascript 高级程序设计--总结【二】

 **********************  Chapter 6  **********************

 属性:

         数据属性:

                   Configurable: 能否通过delete 删除属性,默认true

                   Enumerable: 能否通过 for-in 循环返回属性,默认true

                   Writeble: 能否修改属性的值

                   Value:属性的数据值

 

                   使用 Object.defineProperty(obj,'prop',{}) 来定义属性,这种方式的默认值都是 false ,不建议 IE8 中使用

 

                   var person={};

                   Object.defineProperty(person,'name',{

                            writable:false,

                            value:"test"

 

                   });

                   如果设置了configurable:false, 那么就不能再设置更改其他属性,否则会抛出错误

        

         访问器属性:

                   getter\setter  configurable enumerable

                            var book={

                                     _year:2010,

                                     edition:1

                            };

                            Object.defineProperty(book,'year',{

                                     get:function(){

                                               return this._year;

                                     },

                                     set:function(value){

                                               if(value>2010){

                                                        this._year=value;

                                                        this.edition+=value-2010;

                                               }

                                     }

                            });

                            book.year=2011;

                            console.log(book.edition);

 

                            //另外一种方式

                            book.__defineGetter__('year',function(){

                                     return this._year;

                            });

                            book.__defineSetter__('year',function(value){

                                     if(value>2010){

                                                        this._year=value;

                                                        this.edition+=value-2010;

                                               }

                            });

                   defineProperties() 定义多个属性

                            Object.defineProperties(book,{

                                     _year:{

                                               value:2010

                                     },

                                     edition:{

                                               value:1

                                     }

                            })

         读取属性的特性 getOwnPropertyDescriptor() :IE9+       

                   var desc = Object.getOwnPropertyDescriptor(book,'_year')        

                   console.log(desc.configurable);

创建对象:

         工厂模式:

                   function createPerson(name,age){

                            var obj = new Object();

                            obj.name=name;

                            obj.age=age;

                            obj.sayName = function(){

                                     console.log(this.name);

                            }

                            return obj;

                   }

                   var p1 = createPerson('test',15);

                   var p2 = createPerson('test2',18);          

                   这种模式的缺点就是:不能检测对象的所属类型

        

         构造函数模式:

                   function Person(name.age){

                            this.name=name;

                            this.age=age;

                            this.sayName=function(){

                                     console.log(this.name);

                            }

                   }

                   var p1 = new Person('jj',20);

                   var p2 = new Person('ee',22);

                   console.log(p1.constructor==Person);//true

                   console.log(p2.constructor==Person);//true

                   console.log(p1 instanceof Person);//true

 

                   构造函数本质也是函数,区别只是在于如何调用,构造函数使用 new 操作符地哦啊用,

                   如果看做普通函数调用,本质也没什么区别,this 关键字可指向window

                            //普通函数调用

                            Person('gl',22);

                            window.sayName();

 

                            var o = new Object();

                            Person.call(o,'cl',19);

                            o.sayName();

 

                   问题:每个对象里面的方法都会创建一个Function的新实例,但是如果方法体定义在全局中,那么将会声明太多的全局函数    

        

         原型模式:

                   function Person(){

                   }

 

                   Person.prototype.name='aa';

                   Person.prototype.age=18;

                   Person.prototype.sayName=function(){

                            console.log(this.name);

                   }

 

                   Person.prototype.isPrototypeOf(p1);//true

                   Object.getPrototypeOf(p1)==Person.prototype;//true

 

                   var p1 = new Person();

                   console.log(p1.name);

                   p1.sayName();

                  

                   p1.hasOwnProperty('name');//false

 

                   原型链的属性搜索:从实例本身开始找,如果没有就会去原型对象中寻找

                   同样,实例对象里面的同名属性会覆盖掉原型对象中的同名属性  delete

                   ES5中,Object.getOwnPropertyDescriptor() 只能获取实例对象中属性,要获取原型对象必须在原型对象上调用此方法

 

                   in操作符:

                            只要是能访问到,不管实例还是原型上都为true, 如果

                            'name' in p1;//true

 

                            Object.keys(p1);// for-in

                            Object.keys(Person.prototype);//["name", "age", "sayName"]0: "name"1: "age"2: "sayName"length: 3__proto__: Array[0]

                            Object.getOwnPropertyNames(Person.prototype);//["constructor", "name", "age", "sayName"]

                   字面量的原型对象声明        

                                function Person() {

                                     }

                                     //这里使用了字面量的方式创建原型对象,但是这个原型的constructor 就不是指向Person,而是Object

                                     Person.prototype = {

                                               //constructor: Person,//constructor 的enumerable 会设置为true,可迭代出去

                                               name: "test",

                                               age: 18,

                                               sayName: function () {

                                                        console.log(this.name);

                                               }

                                     }

                                     var p = new Person();

                                     console.log(p.constructor);//Object

                                     //手动定义的方式  ES5 兼容

                                     Object.defineProperty(Person.prototype, 'constructor', {

                                               enumerable: false,

                                               value: Person

                                     });

                   原型的动态性:

                            声明变量之后,再更改原型对象,也是可以再对象中使用的

                            var p = new Person();

                            Person.prototype.run = function () {

            }

            p.run();

                           

                            //注意: 以下是重写了原型的方式

                            function Person() {

                            }

                            var p = new Person();

                            //重写了原型对象, p 对象还是指向原来的原型对象

                            Person.prototype = {

                                constructor: Person,

                                name: "test",

                                sayName: function () {

                                    console.log(this.name);

                                }

                            }

                            //原来的原型对象中没有此方法

                            p.sayName();//error: p.sayName is not a function

                           

                   扩展原生对象的原型:

                            String.prototype.startWith=function(){

                                     //......

                            }

                   原型对象的问题:

                            属性的引用类型问题:

                            function Person() {

                            }

                            //重写了原型对象, p 对象还是指向原来的原型对象

                            Person.prototype = {

                                     constructor: Person,

                                     name: "test",

                                     hobbies:['basketball','football'],

                                     sayName: function () {

                                               console.log(this.name);

                                     }

                            }

                            var p = new Person();

                            p.hobbies.push('a');

                            console.log(p.hobbies);//["basketball", "football", "a"]

                           

                            var p1 = new Person();

                            console.log(p1.hobbies);//["basketball", "football", "a"]      

         组合使用构造函数模式和原型模式【推荐】:

                   function Person(name, age) {

            this.name = name;

            this.age = age;

            this.hobbies = [];

        }

 

        Person.prototype = {

            constructor: Person,

            sayName: function () {

                console.log(this.name);

            }

        };

         动态原型模式:

                   function Person(name, age) {

            this.name = name;

            this.age = age;

            this.hobbies = [];

            //这样子相当于只会执行一次的定义

            if (typeof this.sayName != 'function') {

                Person.prototype.sayName = function () {

                    console.log(this.name);

                }

            }

        }

         寄生构造函数模式【基本不用】:

                   function Person(name,age) {

            var o = new Object();

            o.name = name;

            o.age = age;

            o.sayName = function () {

                console.log(this.name);

            }

            return o;

        }

        var p = new Person('kk', 19);

                           

         稳妥构造函数模式【基本不用】:

                   不使用new 和 this 关键字

                   function Person(name,age) {

            var o = new Object();

            o.sayName = function () {

                console.log(name);//这里的name 只有方法内部才能访问的到

            }

            return o;

        }

                           

继承:

         原型链【很少单独使用】:

                   prototype属性实现继承,每一个实例对象都有一个prototype 的属性

                   所有的函数的默认原型都是Object的实例,默认的原型实例都包含一个指针指向 Object.prototype

                  

                            instanceof()\isPrototypeof() 确定实例和原型的关系,只要出现在原型链中的对象就会返回true

                            Person.prototype.isPrototyprOf(obj);

                   原型链继承一定不要使用字面量的方式,因为这样会导致重写原型,之前的继承会失效

                   继承添加的方法一定要在继承了原型链之后    

                  

                   原型链问题:

                            引用对象共享实例问题

                            function Person(){

                                     this.colors=['red','blue'];

                            }

                            function Man(){

                            }

                            Man.prototype=new Person();

 

                            var m  =new Man();

                            m.colors.push('blink');

 

                            var m1 = new Man();

                            console.log(m.colors);//['red','blue','blink']

                            console.log(m1.colors);//['red','blue','blink'] 

         借用构造函数【很少单独使用】:

                            function Base(name){

                                     this.name=name;

                            }

 

                            function Sub(){

                                     Base.call(this,'test');

                                     this.age=age;

                            }

 

                            var s = new Sub();

                   问题:方法都只能在构造函数中定义,函数不能复用,并且父类的原型方法不可见

         组合继承:

                            function Base(name){

                                     this.name=name;

                            }

 

                            Base.prototype.sayName=function(){

                                     console.log(this.name);

                            }

 

                            function Sub(name,age){

                                     Base.call(this,name);

                                     this.age=age;

                            }

 

                            Sub.prototype=new Base();

                            Sub.prototype.sayAge=function(){

                                     console.log(this.age);

                            }

 

                            var s1 = new Sub('kk',18);

                            s1.sayName();

                            s1.sayAge();

         原型式继承:

                            function object(o){

                                     function F(){}

                                     F.prototype=o;

                                     return new F();

                            }

 

                            var p = {name:'qq',hobbies:['a','b']};

 

                            var p1 = object(p);

                            p1.hobbies.push('c');

                            console.log(p1.hobbies);//["a", "b", "c"]

                            var p2 = object(p);

                            console.log(p2.hobbies);//["a", "b", "c"]        

                   ES5 的 Object.create() 就是使用的这个方法

                            //类似 defineProperties 的参数使用方式

                            var p3 = Object.create(p,{

                                     name:{

                                               value:'newP'

                                     }

                            });

                            console.log(p3.name);//newP

         寄生式继承:

                            function createObj(obj){

                                     var clone = object(obj);

                                     clone.run=function(){

                                               console.log('running');

                                     }

                                     return clone;

                            }

                            var p4 =  createObj(p);

                            p4.run();

         寄生组合式继承【最理想的继承范式】:

                   function object(o){

                            function F(){}

                            F.prototype=o;

                            return new F();

                   }

                   function inherit(sub,base){

                            var proto = object(base.prototype);

                            proto.constructor = sub;

                            sub.prototype=proto;

                   }

 

                   function Base(name){

                            this.name=name;

                            this.colors=['red'];

                   }

                   Base.prototype.sayName=function(){

                            console.log(this.name);

                   }

 

                   function Sub(name,age){

                            Base.call(this,name);

                            this.age=age;

                   }

 

                   inherit(Sub,Base)

 

                   Sub.prototype.sayAge=function(){

                            console.log(this.age);

                   }

 

 

                   var sub = new Sub('kk',18);

                   sub.sayName();

                   sub.sayAge();

 

                   console.log(sub.__proto__.constructor);// Sub()

                           

************************  Chapter 7 函数表达式       ************************                  

func.name;//输出函数名称

             //递归方式  arguments.callee() 或 以下方式

        var factorial = (function f(num) {

            if (num <= 1) {

                return 1;

            } else {

                return num * f(num - 1);

            }

        });

闭包:

         作用域链本质上是一个指向变量对象的指针列表

         闭包会携带包含它函数的作用域链,更加占用内存资源

             function createF() {

            var arr = new Array();

            for (var i = 0; i < 10; i++) {

                //1. 这种方式的闭包,都会引用到外部函数的 活动对象 i, 最终的值都一样

                //arr[i] = function () {

                //    console.log(i);

                //}

 

                //2. 这种优化的方式,就可以实现每次返回不同的值

                arr[i] = function (num) {

                    return function () {

                        console.log(num);

                    }

                }(i);//这里立即执行了函数,所以传入参数会让num更改

            }

            return arr;

        }

        var res = createF();

        for (var i = 0; i < res.length; i++) {

            res[i]();

        }

         内存泄漏问题:

                   function assignHandler() {

            var ele = document.getElementById("ele")

            ele.onclick = function () {

                console.log(ele.id);//这里相当于一直引用着ele 元素,导致循环引用,无法释放

            }

        }

 

        function assignHandler() {

            var ele = document.getElementById("ele")

            var id = ele.id;

            ele.onclick = function () {

                console.log(id);//正确用法

            }

            ele = null;//释放引用

        }

模仿块级作用域:                           

                   function test() {

            for (var i = 0; i < 10; i++) {

                //alert(i);

            }

            console.log(i);//10

            var i;//声明会被忽视,但是赋值才会覆盖  i=100

            console.log(i);//10

        }

        test();

         模仿块级作用域:

                   var f = function () {

            console.log('f');

        }

        f();

        //块级作用域

        (function () { console.log('f'); })();

                  

                   //里面的都是块级作用域

                   (function () {

            var btn = document.getElementById("btn");

            btn.onclick = function () {

 

                console.log('onclick');

            }

            console.log('f');

        })();  

私有变量:

                   function Person() {

                            //特权方法,访问私有变量          

                            this.getName = function () {             

                                     return name;           

                            };               

                            //特权方法,访问私有变量          

                            this.setName = function (val) {                 

                                     name = val;               

                            };               

                   }                

         静态私有变量:

                   function () {

            var privateVal = 10;

 

            function privateF() {

                return false;

            };

            //这里没有使用var ,所以是全局的

            Person = function (val) {

                name = val;

            };

 

            Person.prototype.getName = function () {

                return name;

            }

            Person.prototype.setName = function (val) {

                name = val;

            }

        })();

        var p1 = new Person('t1');//t1

        console.log(p1.getName());

        var p2 = new Person('t2');

        console.log(p1.getName());//t2 由于是静态的,所以都改变了

        console.log(p2.getName());//t2

                           

         模块模式(单例):

                   var singleton = function () {

            var privateVal = 10;

 

            function privateFun() {

                return false;

            }

 

            return {

                pubProp: true,

                pubMethod: function () {

                    privateVal++;

                    return privateFun();

                }

            };

        }();

 

        var application = function () {

            var components = new Array();

            components.push(new BaseComponent());

 

            return {

                getCompCount: function () {

                    return components.length;

                },

                registerComp: function (component) {

                    if (typeof component == 'object') {

                        components.push(component);

                    }

                }

            };

        }();

        

         增强的模块模式:

                   var singleton = function () {

            var privateVal = 10;

 

            function privateFun() {

                return false;

            }

            //所谓的增强就是指定了返回类型

            var object = new CustomType();

            object.pubProp = true;

            object.pubMethod = function () {

                privateVal++;

                return privateFun();

            };

            return object;

        }();

                   var application = function () {

            var components = new Array();

            components.push(new BaseComponent());

            //所谓的增强就是指定了返回类型

            var app = new BaseComponent();

            app.getCompCount = function () {

                return components.length;

            };

            app.registerComp = function (component) {

                if (typeof component == 'object') {

                    components.push(component);

                }

            };

            return app;

        }();   

                  

                           

                           

                           

严格模式:

         eval赋值会导致错误;//eval='a'

         getter\setter, 没有设置就访问会报错

 

 

 

************************  Chapter 9 客户端检测       ************************                  

能力检测:

         浏览器能力检测

                            if(obj.property){

                                     //使用obj.property 方法

                            }

                  

                   尽量使用 typeof 进行检测

                            function hasSort(){

                                     return typeof  obj.sort == 'function';

                            }

                   //IE

                   typof document.createElement == 'function'

                   IE9 之后所有的DOM方法才会返回 'function',因为IE8 之前的所有宿主对象都是COM对象,返回的是'object'

 

                   var xhr = new ActiveXObject("Microsoft.XMLHttp");

        if (xhr.open) {//函数作为属性检测 IE会发生错误,使用typeof 会放回 'unknow'

        }

        function isHostMethod(object, prop) {

            var t = typeof object[prop];

            // IE typeof xhr.open 这里会返回'unknow'

            return t == 'function' || (!!(t == 'object' && object[prop])) || t == 'unknow';

        }

        var res = isHostMethod(xhr, 'open');//true

 

         navigator.vendor;//浏览器的品牌

 

怪癖检测(略):

         var obj = {

                   toString: function () {

                            console.log('string');

                   }

         };

         for (var i in obj) {

                   alert(i);

         }

        

用户代理检测:

         IE7 和 IE8 的兼容模式:

                   IE7  navigator.userAgent 返回的是 MSIE 7.0, 没有trident 标记

                   IE8 的兼容模式 navigator.userAgent 返回的是 MSIE 7.0, 有trident 标记

         IE8:

                   navigator.userAgent 返回的是 MSIE 8.0

        

         Gecko:

                   //默认加密方式U,不会显示

                   "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0"

        

         用户代理字符串检测技术:

                   五大呈现引擎:IE\Gecko\WebKit\KHTML\Opera

                  

                   ?: 表示不捕获分组

posted @ 2018-05-02 14:25  Young汨  阅读(225)  评论(0编辑  收藏  举报