当你使用一个全局变量时,就要考虑污染问题,因为一旦你占用了这个名称,其他人在想使用这个名称就会和你发生冲突,这就是污染。
// 将变量封装在函数内 function f() { var dt = new Date() console.log(+dt); // 1552634315865 } f()
// 将变量作为对象的属性封装 var Module = function () { this.dt = new Date() } console.log(new Module().dt);
(function () { var name = 'maoamo' console.log(name); })(); // 写立即函数一定不能少了最后的; // =================================================================== // 为什么不能少了最后的分号?如果不写呢? (function () { console.log(123); }) (function(){ console.log(456); }) // 上面两个立即函数在js编译的时候会变成下面这个样子: (function() { console.log(123); })(function(){console.log(456);}) // 也就是说第二个立即函数变成了第一个函数的参数 // 在看一个例子:============================================== <button id="btn">点击我</button> <script> var btn = document.getElementById('btn'); btn.onclick = function() { console.log(123); } (function () { console.log(456); })() </script> // 上面的代码直接打印出123然后报错:Uncaught TypeError: (intermediate value)(...) is not a function // 原因就是因为上面的代码最后少了;程序变成了类似下面这样: var btn = document.getElementById('btn'); btn.onclick = function() { console.log(123); }(function () {console.log(456);}) // 立即函数变成了上一个函数的参数,导致上一个函数变成了立即函数 () // 你看上面这个函数 function(){}() // 这个立即函数单独写是不可以的,但是经过赋值操作后这个表达式变得可运行了 // 原因就是赋值操作,先将函数表达式赋给变量,然后在执行变量
使用闭包传参(全局变量),使用全局变量封装属性,会提升效率,因为少了变量提升。
(function (w) { var name = '毛毛'; var getName = function () { return name; }; var setName = function (name_) { name = name_ }; // 一般使用json,将所有内部东西封装起来,赋值给全局变量 w.json = { name:name, getName:getName, setName:setName, }; })(window); // 写立即函数一定不能少了最后的;
对比从外部直接使用全局变量封装:考虑一丁点效率问题,会出现变量提升。
(function () { var name = '毛毛'; var getName = function () { return name; }; var setName = function (name_) { name = name_ }; // 一般使用json,将所有内部东西封装起来,赋值给全局变量 window.json = { name:name, getName:getName, setName:setName, }; })(); // 写立即函数一定不能少了最后的;
var f = (function () { var name = '毛毛'; var getName = function () { return name; }; var setName = function (name_) { name = name_ }; return { name:name, sex:sex, getName:getName, setName:setName, }; })(); // 写立即函数一定不能少了最后的; console.log(f);
演变:全局函数的方式->封装对象的方式->私有空间的划分->模块的扩展和维护
//1.全局函数的形式 <input type="text" id="x"> <select name="" id="fa"> <option value="+">+</option> <option value="-">-</option> </select> <input type="text" id="y"> <button id="equal">=</button> <input type="text" id="result"> <body> <script> var equal = document.querySelector('#equal'); var add = function (x, y) { return x + y; } var subtract = function (x, y) { return x - y; } equal.onclick = function () { var x = parseInt(document.querySelector('#x').value); var y = parseInt(document.querySelector('#y').value); var result = document.querySelector('#result'); var option = document.querySelector('#fa option:checked'); switch (option.value) { case '+': result.value = add(x, y) break; case '-': result.value = subtract(x, y) break; } } </script>
// 2.封装对象的方式 <script> var calc = function () { } calc.prototype = { add: function (x, y) { return x + y; }, subtract: function (x, y) { return x - y; } } /*==============上面是封装===============*/ /*业务...*/ </script>
//3.私有空间划分 <script> var cc = (function () { var add = function (x, y) { return x + y; } var subtract = function (x, y) { return x - y; } var ceilAdd = function (x, y) { return ceil(x) + ceil(y) } var ceil = function (x) { // ceil仅供内部使用,是私有的 return Math.ceil(x); } return { add: add, subtract: subtract, ceilAdd: ceilAdd } })(); /*==============上面是封装===============*/ /*业务...*/ </script>
// 4.模块的扩展和维护 <script> (function (calc) { calc.add = function (x, y) { return x + y; } calc.subtract = function (x, y) { return x - y; } calc.ceilAdd = function (x, y) { return ceil(x) + ceil(y) } var ceil = function (x) { // 内部方法,并未封装在对象中 return Math.ceil(x); } window.calc = calc; // 必须在重新赋给全局({}情况) })(window.calc || {}); /*==============上面是封装===============*/ // 外界可直接扩展[只支持扩展,外界不能更改内部方法] window.calc.remander = function (x, y) { return x % y; } </script>
// 定义一个动物类 function Animal(name) { // 属性 this.name = name || 'Animal'; // 实例方法 this.sleep = function () { console.log(this.name + '正在睡觉') } } // 原型方法 Animal.prototype.eat = function (food) { console.log(this.name + '正在吃:' + food); }
// 1.原型链继承[核心:将父类的实例作为子类的原型] function Cat() { } Cat.prototype = new Animal(); Cat.prototype.name = 'cat'; // Test Code var cat = new Cat(); console.log(cat.name); cat.eat('fish') cat.sleep() console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true
1、要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放在构造中。
// 核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型) function Cat(name) { Animal.call(this); this.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); // cat.eat('fish') 报错 cat.sleep() console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true
1、解决了原型链继承中,子类实例共享父类引用属性(指定是Animal.prototype.eat)的问题。
3、无法实现函数复用,每个子类都有父类实例函数的副本,影像性能。
function Cat(name) { var instance = new Animal(); instance.name = name || 'Tom'; return instance; } // Test Code var cat = new Cat(); console.log(cat.name); cat.eat('fish') cat.sleep() console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // flase
1、不限制调用方式,不管是new子类()还是子类(),返回的对象具有相同的效果。
function Cat(name) { var instance = new Animal(); for (var p in instance) { Cat.prototype[p] = instance[p] } Cat.prototype.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); cat.eat('fish') cat.sleep() console.log(cat instanceof Animal); // flase console.log(cat instanceof Cat); // true
2、无法读取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
// 通过调用父类构造,继承父类属性并保留传参的优点,然后通过将 // 父类实例作为子类原型,实现函数复用 function Cat(name) { Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal(); // Test Code var cat = new Cat(); console.log(cat.name); cat.eat('fish') cat.sleep() console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true
1、弥补了构造继承的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法。
1、调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
// 通过寄生方式,砍掉父类的实例属性,这样在调用两次父类的构造的时候, // 就不会初始化两次实例方法/属性,避免组合继承的缺点 function Cat(name) { Animal.call(this); this.name = name || 'Tom'; } (function () { // 创建一个没有实例方法的类 var Super = function () { }; Super.prototype = Animal.prototype; // 将实例作为子类的原型 Cat.prototype = new Super(); })(); // Test Code var cat = new Cat(); console.log(cat.name); cat.eat('fish') cat.sleep() console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true