JS学习之路系列总结二阴阳阵(此文犹如武林之中的易筋经,是你驰骋IT界的武功心法,学会JS五大阵法就学会了JS,博主建议先学三才阵)

<script>
 
/*
阴阳阵法: 对象   函数  【为了便于记忆,减少占用大脑内存,我命名为JS心法为:道阵法,两仪阵法,三才阵法,四象阵法,五行阵法,只需记住阵法的关键字,即可搜索大脑中相应的内容,学会JS五大阵法即可学会JS】
             类:具有相同和相似性质的对象的抽象就是类,对象的抽象就是类,对象就是类的实例化
           类的本质是一种数据类型,类似于int,string等基本类型,不同的是它是一种复杂的数据类型,
            因为它的本质是类型,而不是数据,所以不存在于内存中,不能被直接操作,只有被实例化为对象时,才会变得可操作。
           类就是对现实生活一类具有共同特征的事物的抽象(抽象就是具有本质内在的属性)
           类的内部封装了方法,用于操作自身的成员。类是对某种对象的定义,具有特征和行为,
           它描述了一个对象能够做什么以及做的方法(method),包含对象的名称,属性,方法,事件。
           类的构成包括数据成员和成员函数,数据成员对象类的属性,类的数据成员也是一种数据结构,并不需要分配内存,
           成员函数用于操作类的各项属性,是          这个类特有的操作,比如学生可以上课,水果则不能,类和外界发生交互的操作称为接口
           类的三大特性:
           1:封装性,将数据和操作封装为一个有机的整体,由于类中私有成语都是隐藏的,只向外部提供有限的接口,
           所以能够保证内部的高内聚性和外部的低耦 合性。使用者不必了解具体的实现细节,而是通过外部接口,
           以特定的访问权限来使用累的成员,能增强数据安全性和简化编程
           2:继承性,子类可以继承父类的属性和方法,使程序便于理解,节省不必要的重复代码
           3:多态性,同一操作作用于不同对象,可以产生不同的执行结果
           类具有属性:它是对象状态的抽象描述,用数据结构来描述
           类具有操作:它是对象行为的抽象描述,用操作名()函数名和实现该操作的方法(函数)来描述
           对象具有状态:用数据值来描述
           对象具有行为:用对象状态的改变来描述
           对象特征:
           1:对象唯一性,每个对象都有自身唯一的标识,通过标识可找到相应的对象(即变量名,函数名,对象名等名称)
           2:对象分类型,把相同或相似的数据结构(属性)和操作和(方法)的对象抽象成类
           3:对象继承性,子类自动继承父类属性和方法的机制,这是类之间的一种关系
           在定义和实现一个类时,可以把已存在类所定义属性和方法作为自己的属性和方法,并加入新的属性和方法。
           继承性时面向对象程序设计语言不同于其他语言最重要的特点,是其他语言没有的,
           在类层次中,子类只继承一个父类的属性(数据结构)和方法,称为单重继承。
           在类层次中,子类继承多个父类的属性(数据结构)和方法,  称为多重继承
           在软件开发中,类的继承性使代码具有开放性,可扩充性,简化了类,对象的创建工作量,增加了代码的可重用性
           4:多态性(多形性)是指相同的函数方法,操作可作用于多种类型的对象并获得不同的结果,不同的对象,
            受到同一个消息(对象之间进行通信的结构,即是参数),可以产生不同的结果, 这种现象称为多态性,多态性增加代码的灵活性和重重用性。
 
          (一)面向对象设计的准则
⒈模块化
面向对象开发方法很自然地支持了把系统分解成模块的设计原则:对象就是模块。它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。分解系统为一组具有高内聚和松耦合的模块是模块化的属性。
⒉抽象
面向对象方法不仅支持过程抽象,而且支持数据抽象。
⒊信息隐藏
在面向对象方法中,信息隐藏通过对象的封装性来实现。
⒋低耦合
在面向对象方法中,对象是最基本的模块,因此,耦合主要指不同对象之间相互关联的紧密程度。低耦合是设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其它部分的影响降到最低程度。[2] 
⒌高内聚
⑴操作内聚。
⑵类内聚。
 
面向对象思想对于计算机犹如心脏对于人体的重要性,犹如人体奇经八脉中任督二脉,理解了面向对象就如同打通了任督二脉,JS武林任你闯荡。
对象:自然界一切的人,物,事等客观存在的实体皆可称为对象【万物皆对象】
比如一个人,一本书,一把剑
对象:分状态(属性)和行为(方法)
对象                        状态                              行为
人                年龄,身高,性别          旅行   运动   看书
医生            外科,耳科,级别          望   闻   问   切
对象的状态在JS中叫属性
对象的行为在JS中叫方法,函数,功能
 
  <script>
        window.onload = function () {
            /*
            //对象的关键词:  
           1:创建对象,添加属性和方法     2:工厂模式   3:constructor,instanceof   prototype, __proto__     thtis,new    call,apply
            JavaScript中的所有事物都是对象:对象,函数,数组,字符串,数值等,JS中没有类的概念
            但我们可以利用JS的语法特征,以类的思想来创建对象
            */
            //【1:创建对象,添加属性和方法】【对象字面量】
            var obj1 = {};//创建对象
            console.log(obj1);
            obj1.name = "刘洋1"; //添加属性
            obj1.showName1 = function () {//添加方法
                return this.name;
            }
            console.log(obj1.showName1());
            var obj2 = {
                name: "刘洋2",
                showName2: function () {
                    return this.name;
                }
            }
            console.log(obj2.showName2());
            //第二种创建方式
            var obj3 = new Object();//通过new关键字生成一个对象,添加属性和方法
            obj3.name = "刘洋3";
            obj3.showName3 = function () {
                return this.name;
            }
            console.log(obj3.showName3());
            var obj4 = new Object();//通过new关键字生成一个对象,添加属性和方法
            obj4.name = "刘洋4";
            obj4.showName4 = function () {
                return this.name;
            }
            console.log(obj4.showName4());
            /*
            第二种创建对象的问题:
            如果需要创建多个对象,则需要重复代码多次,不利于代码的重用
            改进如下:
            */
            //【2:工厂模式】
            function Factory(name) {
                var obj = new Object();//在this改造工厂模式时可以去掉
                obj.name = name;
                obj.showName = function () {
                    return obj.name;
                }
                return obj;//在this改造工厂模式时可以去掉,创建实例对象时系统默认会生成return this;
            }
            var factory1 = Factory("张三1");
            var factory2 = Factory("李四1");
            console.log(factory1.showName() + "," + factory2.showName());
            //自定义构造对象【用new和this改造工厂模式,改进如下:】
            function CreateObj(age) {
                this.age = age;//this表示调用该属性的对象
                this.name = "刘洋";
                this.showAge = function () {
                    return this;
                }
                //return this//创建实例对象时系统默认会生成return this;
            }
            /*
            那么,在使用new操作符来调用一个构造函数的时候,发生了四件事:
            var obj  ={};创建一个空对象obj。
            obj.__proto__ = CreateObj.prototype;将这个空对象的__proto__成员指向了构造函数对象的prototype成员对象
            CreateObj.call(obj);
            return obj;
 
            当任意一个普通函数用于创建一类对象时,它就被称作构造函数,或构造器。
            一个函数要作为一个真正意义上的构造函数,需要满足下列条件:
            1、 在函数内部对新对象(this)的属性进行设置,通常是添加属性和方法。
            2、 构造函数可以包含返回语句(不推荐),但返回值必须是this,或者其它非对象类型的值。
            */
 
            var create1 = new CreateObj("25");//在内存中创建一个对象create1,复制一份构造函数CreateObj中的属性age,和方法showAge
            var create2 = new CreateObj("26");//在内存中创建一个对象create2,复制一份构造函数CreateObj中的属性age,和方法showAge
            console.log(create1.showAge())
            console.log(create2.showAge())
            /*
            工厂模式创建对象问题:
            工厂模式虽然提高了代码的重用性,但和面向对象中的类相比,还有很大的缺陷,
            面向对象强调对象的属性私有,而对象的方法公有共享的,而工厂模式创建对象时,
            给每个对象都创建代码逻辑相同的方法,浪费内存,影响软件性能。
            改进如下:
            */
           //【3:constructor,instanceof     constructor构造器属性      instance实例     】
            function CreateObj2(name) {
                this.userNme = name;
                this.showName = function () {
                    return this.userNme;
                }
            }
            var create = new CreateObj2("李四");
            console.log(create.constructor);//constructor构造器属性
            /*返回以下代码:
            CreateObj(name) {
                this.userNme = name;
                this.shhowName = function () {
                    return this.userNme;
                }
            }
            */
            console.log("创建构造函数时,构造函数的原型对象上有个属性(constructor)指向构造函数本身");
            console.log(create.constructor === CreateObj2);//true
            //默认情况下,对象的constructor等于实例对象的构造函数,
            //constructor最初的作用是用来标识对象的,但是不是特别准确,因为constructor能被修改
 
            /*
            假设instanceof运算符左边是L,右边是R
            L instanceof R
            instanceof运算时,判断L的原型链上是否存在R.prototype
            L._proto_._proto_......=R.prototype?
            如果存在返回true,否则返回false
            */
            //识别对象一般用instanceof关键字【instance实例】
            console.log(obj1 instanceof CreateObj);//true
            console.log(obj2 instanceof CreateObj);//true
            //所有对象继承自Object,所以obj1,obj2是Object的实例
            console.log(obj1 instanceof Object);//true
            console.log(obj2 instanceof Object);//true
            //优点就是能够通过instanceof识别对象,缺点是每次实例化一个对象,都会把属性和方法复制一遍,浪费内存
            //【3:prototype,__proto          prototype原型    __porto__隐式原型】
         
<script>
alert("10");//10;
//给window对象添加一个方法 相当于
Window.prototype.add = function (a) {
alert("使用prototype重写数组的lenth方法" + a);
}
add("20");//使用prototype重写数组的lenth方法20
var arr = [10, 10, 20, 20, 30];
//给数组对象添加一个方法,作用:去除数组内重复的元素只保留一个【也可以修改Array的方法indexOf()】
Array.prototype.unRename = function () {
var unR = [];//存放已经过滤好的不重复的数据
for (var i = 0, len = this.length; i < len; i++) {
//this指向调用unRename方法的对象,此时就是arr
if (unR.indexOf(this[i]) == -1)
unR.push(this[i]);
}
return unR;
}
console.log(arr.unRename());//10,20,39
console.log(Array.prototype.__porto__ === Object.__porto__)//true
var arr = [10, 20, 30];
var obj = {
a: 10,
b: 20,
c: 30
}
//alert(arr);//10,20,30
//alert(obj);//object Object
console.log(arr);
console.log(obj);
//重写Object的toString方法【系统内置的方法】
Object.prototype.toString = function () {
str = "";
for (var key in this) {
str += this[key] + ",";
}
return str.slice(0, -1);
}
//重写Array的toString方法【系统内置的方法】
Array.prototype.toString = function () {
str = "";
for (var key in this) {
str += this[key] + "/";
}
return str.slice(0, -1);
}
alert(arr);//10,20,30
alert(obj);//10/20/30

</script>
            //解决方法第一种:把对象的函数定为全局函数showName,虽然解决了多次复制的问题,
            //但全部函数非常容易被覆盖,也就是大家经常说的污染全局变量。
            //解决方法第二种,使用prototype对象,把方法写在构造函数的原型对象上,节省内存,提高性能
            CreateObj2.prototype.showName1 = function () {
                return this.userNme;
            }
            var obj3 = new CreateObj2();
            var obj4 = new CreateObj2();
            console.log(obj3.shhowName1 === obj4.shhowName1);//true;
            console.log(obj3 instanceof CreateObj2);//true;
            // CreateObj("aa").showName();
            //构造函数(创建对象的函数叫构造函数)
            //每个函数上都有个原型属性[[prototype]],原型属性指向原型对象prototype。
            function Obj(age) {//作用:初始化实例对象的属性,相当于一个人出生时,带着眼睛鼻子耳朵等属性
                this.age = age;//私有属性
            }
            //在创建构造函数时,原型对象上就生成一个constructor构造器属性,它指向构造函数Obj
            //原型上有隐式原型__proto__,指向Object对象的原型prototy;
            Obj.prototype.showAge = function () {//公用方法
                return this.age;
            }
            var obj1 = new Obj("30");//实例对象obj1上有隐式原型__proto__
            var obj2 = new Obj("40");//作用:指向实例对象的构造函数的原型对象,调用公用方法
            console.log(obj1.showAge());
            /*
            就近原则:
            1:当实例对象调用属性和方法时,先查看实例是否有该属性和方法,有就调用,
            2:如果没有就根据实例上的隐式原型__proto__指向构造函数的原型对象,查看是否有该属性和方法,有就调用,
            3:如果没有继续根据隐式原型__proto__指向查看是否有该方法,有就调用,
            4:直到查找到Object的原型上没有该属性和方法没有就返回undefined。
            通过隐式原型__proto__指向原型对象这个特性,一直向上级查找属性和方法的过程就是原型链。
            */
            function Construct(name, age) {
                this.name = name;
                this.age = age;
            }
            Construct.prototype.showName = function () {
                return this.name;
            }
            Construct.prototype.showAge = function () {
                return this.age;
            }
            var obj1 = new Construct("刘洋", "25");
            console.log(obj1.showName() + "," + obj1.showAge());
            console.log(obj1.constructor);
            /*返回的构造器constructor代码如下
             function Construct(name, age) {//指向构造函数Construct
                this.name = name;
                this.age = age;
            }
            */
            //上边重复代码,浪费内存,影响性能,改进如下:
            Construct.prototype = {
                constructor: "Construct",//必不可少,否则obj.constructor指向Object对象
                showName: function () {
                    return this.name;
                },
                showAge: function () {
                    return this.age;
                }
            }
            console.log(obj1.constructor);
            /*没有设置  constructor: "Construct"时返回代码如下
            Object() { [native code] } 指向Obect对象
            */
        }
    </script>
   //【3:this,new    this指向   new新建】
<script>
//第一种:单独的this,指向的是window对象
// 注:当前的执行环境是window,所以指向了window
console.log(this);
/*
第二种:全局函数中的this
*/
function show() {
console.log("第二种:" + this);
}
show();//这样调用时指向window
new show()//构造函数的调用指向Object
/*
第三种:用call和apply调用函数
一般情况下,this指向call和apply后面的第一个参数,
当call和apply后面的第一个参数是undefined和null时this指向window
*/
function show1() {
console.log("第三种" + this);//this==刘洋
}
show1.call("刘洋");
show1.apply("刘洋");
show1.call(undefined);//函数中this指向window
show1.call(null);//函数中this指向window
show1.apply(undefined);//函数中this指向window
show1.apply(null);//函数中this指向window
function show2() {
console.log("第四种" + this + arguments[0]);//第三种刘洋25
}
show2.call("刘洋", "25", "男");//arguments[0]==25,不是刘洋【参数是一个一个传】
show2.apply("刘洋", ["25", "男"]);//arguments[0]==25,不是刘洋【参数以数组方式传】
/*
第四种:定时器的this,指向的是window
*/
// setInterval(function(){
// console.log(this);//window
// },1000)
/*
第五种:元素绑定事件,事件触发后执行的函数中this指向事件对象(即当前元素)
*/
window.onload = function () {
console.log("第五种" + this);//指向window
document.body.onclick = function () {
console.log("第五种" + this);//指向body元素
}
document.body.addEventListener("click", function () {
console.log("第五种" + this);//此时指向window
}.bind(window));//如果没有bind则指向body
}
/*
第六种:对象中的方法,该方法被哪个对象调用,方法中的this就指向哪个对象
*/
var obj = {
name: "刘洋",
show: function () {
return "第六种" + this + "/" + this.name;
}
}
console.log(obj.show());//this指向Object
//如果放对象的方法,赋给一个全局变量,然后再调用,那么this指向window
var fn = obj.show;
var name = "全局变量刘洋";
console.log(fn());//指向window
//腾讯面试题
var x = 20;
var a = {
x: 10,
fn: function () {
var x = 30;
return function () {
return this.x;
};
}
};
console.log(a.fn())//function(){return this.x};
console.log((a.fn())())//20 this指向对象window
console.log(a.fn()())//20 this指向对象window
console.log(a.fn()() == (a.fn())())//true;
console.log(a.fn()() === (a.fn())())//true;
console.log(a.fn().call(this));//20 this指向对象window
console.log(a.fn().apply(a));//10 this指向对象a
</script>
/*
   //【3:call,apply           call  呼叫,访问    apply  请求,申请】
call,apply共同之处,改变this指向,
call,apply不同之处,参数不同
call:fn.call(alterThis, args1,args2);传入多个参数
apply:fn.apply(alterThis, arguments);传入参数数组
*/
//基本用法
function add(a, b) {
return a + b;
}
function sub(a, b) {
return a - b;
}
var a1 = add.apply(sub, [4, 2]);///sub调用add的方法
var a2 = sub.call(add, 4, 2);
// console.log(a1);//4+2=6
/// console.log(a2);//4-2=2
function show1() {
return this;
}
function show2() {

}
//call,apply相同原理,call,apply之后的第一个参数改变this的指向对象,
console.log(show1.call(undefined));//this指向window
console.log(show1.call(null));//this指向window
console.log(show1.call());//this指向window
alert(show1.call(""));//空字符串
alert(show1.call(" "));//空字符串
alert(show1.call("abc"));//abc
//实现继承
function Animal(AnimalName) {
this.name = AnimalName;
this.showName = function () {
alert(this.name);
}
}
function Cat(catName) {
// Animal.apply(this,[catName]);
Animal.call(this, catName);
console.log("22");
console.log(this);
}
var cat = new Cat("加菲猫");
// cat.showName();//加菲猫
//实现多重继承
function fn1() {
this.add = function (a, b) { alert(a + b) };
}
function fn2() {
this.sub = function (a, b) { alert(a - b) };
}
function fn3() {
console.log(this);
fn1.call(this);
fn2.apply(this);
}
var fn = new fn3();
///fn.add(4, 2);//6
//fn.sub(4, 2);//2

var arr = [1, -29, 43, 344, 4, -5];
//第一种方法:求数组中的最大值,最小值
var max1 = arr[0];
var min1 = arr[0];
for (var i = 0, len = arr.length; i < len; i++) {
if (max1 < arr[i]) max1 = arr[i];
if (min1 > arr[i]) min1 = arr[i];
}
console.log(max1);
console.log(min1);
//第二种方法:求数组中的最大值,最小值
var max2 = Math.max.apply(null, arr);
var min2 = Math.min.apply(null, arr);
console.log(max2);
console.log(min2);

//合并两个数组并返回新数组的长度
var arr1 = new Array("1", "2");
var arr2 = new Array("3", "4");
console.log(Array.prototype.push.apply(arr1, arr2));
}
</script>
 
如果把函数比作计算机,计算机五大功能如下:
1,函数名             相当于存储器 【函数名是变量,在内存中开辟一块空间,存放函数,函数加小括号时调用执行函数】
2,参数                相当于输入数据
3,函数体            相当于运算器和控制器
4,返回值            相当于输出数据
 
*/
//  函数的关键词     1:函数声明   2:匿名函数     3:函数表达式       4:arguments       5:闭包
 
 
//【  1:函数声明  】
//无参函数
function noPara() {
//函数体
console.log("我是无参函数");
}
noPara();
//有参函数
function hasPara(a) {
console.log("我是有参函数" + a);
}
hasPara(10);
//有返回值的函数
function returnedValue(a) {
return "我是有返回值的函数" + a;
}
console.log(returnedValue(10));


//【2:匿名函数】
//立即式函数,也叫自执行函数
(function () {
console.log("我是匿名函数a");
})();//立即执行
(function () {
console.log("我是匿名函数b");
console.log(arguments[0]);
})//【此处不能少写分号,否则function(){console.log("我是匿名函数c");}在小括号中相当于一个参数传给arguments[0],所以记得写分号】
(function () {
console.log("我是匿名函数c");
});//立即执行
//【3:第三种函数表达式:】
//将匿名函数赋给一个变量
var express = function () {
console.log("我是函数表达式");
}
express();
<script>
//【函数声明和函数表达式的区别】
show("show1");//在函数表达式之前调可以执行
function show() {
console.log("我是函数声明");
}
show();//在函数表达式之后调用可以执行
// express("express1");//在函数表达式之前调用不能执行
var express = function () {
console.log("我是函数表达式");
}
express();//在函数表达式之后调用可以执行

//函数表达式,在后边加小括号,可以立即调用
var show = function () {
console.log("函数表达式,在后边加小括号,可以立即调用");
}();
//函数声明不能被立即调用, 这是错误的写法
// function show(){
// alert( 2 );
// }();

//但是可以把函数声明变成函数表达式
//在函数声明外加个小括号就可以把函数声明变成函数表达式了
(function show() {
console.log("在函数声明外加小括号就变成了函数表达式");
});
//再加个小括号就可以调用执行函数了
(function show() {
console.log("在函数声明外加小括号就变成了函数表达式,再加个小括号就立即执行函数了");
})();

//表达式传参
(function show(a) {
console.log(a);
})(10);//10

//匿名函数:没有函数名的函数
(function (a) {
console.log(a);
})(1000);//1000
//(function(){})() 立即表达式【函数自执行】
(function () {
function show2() {
console.log("我是函数自执行");
}
show2();
})();
// show2()//show2 undefined,调用不到函数里边定义的函数,可以吧它理解成函数内部的局部变量

(function () {
function show() {
console.log("利用window的属性。调用函数内部的函数");
}
window.fn = show;//把函数名(即变量)赋给window对像的属性fn
})();
fn();//fn()相当于show()
// show();//不能调用,因为show是内部函数
//fn.show()//错误,因为fn不是对象,它只是个方法
(function () {
var Obj = {
show: function () {
console.log("把对象名赋给window的属性");
}
}
window.fn = Obj;
})();
//fn();//错误,因为fn是对象,它不是函数名
fn.show();//此时fn相当于对象Obj
</script>
/*
 
</script>
//【4:arguments】
function arg1() {
for (var i = 0, len = arguments.length; i < len; i++) {
console.log(arguments[i]);
}
}
arg1(1, 2, 3);//1,2,3是实参
function arg2(a, b) {//a,b是形参
console.log(a);
for (var i = 0, len = arguments.length; i < len; i++) {
console.log(arguments[i]);//4,5,6 arguments的个数是有实参决定的
}
}
arg2(4, 5, 6);
//【5:闭包】
//污染全局变量的测试 因此尽量不要定义全局变量,一是防止变量污染,二是节省内存,提高性能
/*
闭包:在一个函数(父函数)内部嵌套一些函数(子函数),
这些函数(子函数)可以访问它们所在的外部函数中的所有局部变量,参数和其他函数
当这样的内部函数在外部被调用时,就会形成闭包。
全局变量和局部变量
全局变量:1,用var 声明的变量 2,在函数之外 【global全局 variable】
局部变量:1,用var 声明的变量 2,在函数之内 【local 局部variable】
隐变量: 1,没有用var声明的变量 【hidden隐式 variable】【不推荐使用,严格模式不能使用】
变量生命周期
全局变量:在页面打开时生成,在页面关闭时销毁(释放)
局部变量:在函数执行时生成,在函数执行完毕时销毁(释放)
函数内部可以直接读取全局变量,因此子函数可访问父函数的局部变量,
父函数不能访问子函数的局部变量
 
特点:一般情况下 要把里面的函数返回
作用:1,防止污染全局变量 2,模块化开发
*/
function show() {
var n = 10;
}
//console.log(n); //undefined ,因为局部变量在函数执行完毕后被释放
//怎么在函数之外访问到局部变量 使用闭包
function parent() {
var n = 999;
add = function () { n++ };
function child() {
console.log(n);
}
return child;
}
var result = parent();

result();//999;
add();
result()//1000;
/*
result实际上就是闭包child函数。它一共运行了两次,
第一次的值是999,第二次的值是1000。这证明了,函数parent中的局部变量n一直保存在内存中,并没有在函数parent调用后被自动清除。
为什么会这样呢?原因就在于parent是child的父函数,而函数child被赋给了一个全局变量,这导致f2始终在内存中,
而函数child的存在依赖于函数parent,因此函数parent也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中另一个值得注意的地方,就是"add=function(){n+=1}"这一行,首先在add前面没有使用var关键字,因此nAdd是一个全局变量,
而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,
所以add相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
 
使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,
否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,
把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),
这时一定要小心,不要随便改变父函数内部变量的值。
 
*/


function closure() {
var a = 10;
function closure1(){
console.log("我是闭包close1");
}
closure1();
}
closure();
console.log(a);//a is not defined,因为var a=10,a是局部变量,函数在执行完毕后,变量b被释放。
//典型的闭包是计时器setInterval;setInterval()是一个函数,函数里边有嵌套了一个函数
var count = 1;
// setInterval(function(){
// document.body.innerHTML=++count;
// },500);

//函数声明 闭包
function show2() {
var a = 10;
return function () {
return ++a;
}
}

console.log(show2())//function(){return ++a;}
console.log(show2()());//11
console.log(show2()());//11 为什么是11,因为每次执行show2函数是都会执行var a=10;

var fn1 = show2();
console.log(fn1);//function(){return ++a;}
console.log(fn1());//11; 此时可以访问到变量a了。
console.log(fn1());//12;为什么是12,因为只是执行show2函数内部的函数,不会执行var a=10;


//函数表达式 闭包
var fn2 = function () {
var b = 10;
return function () {
return ++b;
}
}
var fn3 = fn2();
console.log(fn3);//function(){return ++a;}
console.log(fn3());//11; 此时可以访问到变量a了。
console.log(fn3());//12;
</script>
<script>
 
 
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        window.onload = function () {
            // //JS写法
            // var button = document.querySelectorAll("button");
            // var input = document.querySelectorAll("input");
            // button[0].onclick = function () {
            //     checkFormat(true);
            // }
            // button[1].onclick = function () {
            //     checkFormat(false);
            // }
            // button[2].onclick = function () {
            //     checkFormat();
            // }
            // function checkFormat(arg) {
            //     for (var i = 0, len = input.length; i < len; i++) {
            //         if (arg) {
            //             input[i].checked = arg;
            //         } else if (arg == false) {
            //             input[i].checked = arg;
            //         } else {
            //             input[i].checked = !input[i].checked;
            //         }
            //     }
            // }
            // console.log(undefined==false);
            //面向对象写法【属性用:】
            // var Check = {
            //     //属性
            //       button:null,
            //     //方法
            //     init: function (a) {
            //         this.button = document.querySelectorAll(a["button"]);
            //         this.input = document.querySelectorAll(a.input);
            //         console.log(this.button);
            //         this.addEvent();
            //     },
            //     addEvent: function () {
            //         var that = this;
            //         this.button[0].onclick = function () {
            //             that.checkFormat(true);
            //         }
            //         this.button[1].onclick = function () {
            //             that.checkFormat(false);
            //         }
            //         this.button[2].onclick = function () {
            //             that.checkFormat();
            //         }
            //     },
            //     checkFormat: function (arg) {
            //         for (var i = 0, len = this.input.length; i < len; i++) {
            //             if (arg) {
            //                 this.input[i].checked = arg;
            //             } else if (arg == false) {
            //                 this.input[i].checked = arg;
            //             } else {
            //                 this.input[i].checked = !this.input[i].checked;
            //             }
            //         }
            //     }

            // };
            // Check.init({"button":"button","input":"input"});
            //构造函数写法【属性用=】
            //     function construct(a, b) {//私有属性
            //         this.button = document.querySelectorAll(a);
            //         this.input = document.querySelectorAll(b);
            //         this.init();
            //     }
            //     //公有方法
            //     construct.prototype.init = function () {
            //         this.addEvent();
            //     }
            //     construct.prototype.addEvent = function () {
            //         var that = this;
            //         this.button[0].onclick = function () {
            //             that.checkFormat(true);
            //         }
            //         this.button[1].onclick = function () {
            //             that.checkFormat(false);
            //         }
            //         this.button[2].onclick = function () {
            //             that.checkFormat();
            //         }
            //     }
            //     construct.prototype.checkFormat = function (arg) {
            //         for (var i = 0, len = this.input.length; i < len; i++) {
            //             if (arg) {
            //                 this.input[i].checked = arg;
            //                 console.log(this.input[i]);
            //             } else if (arg == false) {
            //                 this.input[i].checked = arg;
            //             } else {
            //                 this.input[i].checked = !this.input[i].checked;
            //             }
            //         }
            //     }
            //    new construct("button", "input");

        }
    </script>
    <script>
            (function () {
                var LiuYang = {};
                LiuYang.FirstObj = {//LiuYang对象的属性是FirstObj,对象可以有很多属性,一个属性又代表着一个对象
                    Check: function (data) {//FristObj对象的方法是Check(data);
                        return new LiuYang.FirstObj.construct(data);//返回实例对象
                    }
                }
                LiuYang.FirstObj.construct = function (data) {
                    this.defaultData = {
                        "button": "button",
                        "input": "input"
                    }
                    for (var key in data) {
                        this.defaultData[key] = data[key];
                    }
                    this.button = document.querySelectorAll(this.defaultData.button);
                    this.input = document.querySelectorAll(this.defaultData.input);
                    this.init();
                }
                LiuYang.FirstObj.construct.prototype.init = function () {
                    this.addEvent();
                }
                LiuYang.FirstObj.construct.prototype.addEvent = function () {
                    var that = this;
                    this.button[0].onclick = function () {
                        that.checkFormat(true);
                    }
                    this.button[1].onclick = function () {
                        that.checkFormat(false);
                    }
                    this.button[2].onclick = function () {
                        that.checkFormat();
                    }
                }
                LiuYang.FirstObj.construct.prototype.checkFormat = function (arg) {
                    for (var i = 0, len = this.input.length; i < len; i++) {
                        if (arg) {
                            this.input[i].checked = arg;
                            console.log(this.input[i]);
                        } else if (arg == false) {
                            this.input[i].checked = arg;
                        } else {
                            this.input[i].checked = !this.input[i].checked;
                        }
                    }
                }
                //使用闭包是为了污染全局变量,只把对象赋给window的属 
                window.Ly=LiuYang;
            })();
        window.onload = function () {
            var ly1 = Ly.FirstObj.Check({
                "button": "button",
                "input": "input"
            })
        }
    </script>
</head>

<body>
    <button>全选</button>
    <button>不选</button>
    <button>反选</button>
    <input type="checkbox">
    <input type="checkbox">
    <input type="checkbox">
    <input type="checkbox">
    <input type="checkbox">
</body>

</html>
 
原文地址:https://www.cnblogs.com/xingkongly/p/7670583.html