ECMA基础(三)
原型
原型是什么?
prototype
原型prototye是function对象的一个属性,但打印结果也是对象。
function Handphone() {}console.log(Handphone.prototype); //{constructor: ƒ}
function Handphone(color, brand) {this.color = color;this.brand = brand;this.screen = '18:9';this.system = 'Android';}var hp1 = new Handphone('red', 'xiaomi');var hp2 = new Handphone('black', 'huawei')console.log(hp1); //Handphone {color: "red", brand: "xiaomi", screen: "18:9", system: "Android"}console.log(hp2); //Handphone {color: "black", brand: "huawei", screen: "18:9", system: "Android"}
既然原型prototye是function对象的一个属性,尝试下
function Handphone(color, brand) {this.color = color;this.brand = brand;this.screen = '18:9';this.system = 'Android';}Handphone.prototype.rom = '64G';Handphone.prototype.ram = '6G';var hp1 = new Handphone('red', 'xiaomi');var hp2 = new Handphone('black', 'huawei')console.log(hp1.rom); //64Gconsole.log(hp2.ram); //6G
说明
- 原型
prototype是定义构造函数构造出每个对象的公共祖先 - 所有被该构造函数构造出的对象都可以继承原型上的属性和方法
function Handphone(color, brand) {this.color = color;this.brand = brand;this.screen = '18:9';this.system = 'Android';}Handphone.prototype.rom = '64G';Handphone.prototype.ram = '6G';Handphone.prototype.screen = '16:9';var hp1 = new Handphone('red', 'xiaomi');var hp2 = new Handphone('black', 'huawei')console.log(hp1.screen); //18:9console.log(hp2.screen); //18:9
说明构造函数自身有的属性不会往祖先身上找
作用:
- 减少代码冗余(每次实例化会重复)
function Handphone(color, brand) {//配置项,需要传参取配置的this.color = color;this.brand = brand;}//公共方法Handphone.prototype.rom = '64G';Handphone.prototype.ram = '6G';Handphone.prototype.screen = '16:9';Handphone.prototype.system = 'Android';Handphone.prototype.call = function () {console.log('I am calling somebody');};var hp1 = new Handphone('red', 'xiaomi');var hp2 = new Handphone('black', 'huawei')hp2.call(); //I am calling somebody
实例化出来的对象 对原型prototype的增删改查
查
function Test() {}Test.prototype.name = 'prototype';var test = new Test();console.log(test.name); //prototype
增(不能修改原型属性,可修改实例对象属性)
function Test() {}Test.prototype.name = 'prototype';var test = new Test();test.num = 1;console.log(Test.prototype); //{name: "prototype", constructor: ƒ}console.log(test); //Test {num: 1}/*** 说明test.num = 1; 写在* function Test() {* this.num = 1;* }*/
删(不能删除原型属性,可删除实例对象属性)
function Test() {this.name = 'proto';}Test.prototype.name = 'prototype';var test = new Test();console.log(test); //Test {name: "proto"}delete test.name;console.log(Test.prototype); //{name: "prototype", constructor: ƒ}console.log(test); //Test {}
改(不能更改原型属性,可更改实例对象属性)
function Test() {}Test.prototype.name = 'prototype';var test = new Test();test.name = 'proto';console.log(Test.prototype); //{name: "prototype", constructor: ƒ}console.log(test); //Test {name: "proto"}
实际开发写法:
//公共方法Handphone.prototype = {rom: '64G',ram: '6G',screen: '18:9',system: 'Andriod',call: function () {console.log('I am calling somebody');}}
constructor
- 在
prototype里面 - 指向构造函数本身
function Handphone(color, brand, system) {this.color = color;this.brand = brand;this.system = system;}console.log(Handphone.prototype);/*** 打印:* {constructor: ƒ}constructor: ƒ Handphone(color, brand, system)__proto__: Object*/
说明constructor对应的是构造函数
function Handphone(color, brand, system) {this.color = color;this.brand = brand;this.system = system;}function Telephone() {}Handphone.prototype = {//将constructor指向Telephoneconstructor: Telephone}console.log(Handphone.prototype);/*** 打印:* {constructor: ƒ}constructor: ƒ Telephone()__proto__: Object*/
说明可以通过构造函数本身prototype更改contructor的指向另外的构造函数
__proto__
是实例化以后的结果,是每个实例化对象的原型prototype的容器
function Car() {}Car.prototype.name = 'Benz';var car = new Car();console.log(car); //Car {}/*** 点开打印结果* Car {}* __proto__: Object*/
相当于实例化以后实例对象里面的其中一个属性
function Car() {var this = {__proto__: ?}}
__proto__里面存放一个对象包含构造函数原型上的属性
/*** 点开打印结果* Car {}__proto__:name: "Benz"constructor: ƒ Car()__proto__: Object*/
function Car() {var this = {__proto__: Car.prototype}this.color = ‘red';}
说明原型prototype是属于实例化对象而不属于构造函数
属性访问顺序
function Car() {/*** var this = {__proto__: Car.prototype}*/this.name = 'mazda';}Car.prototype.name = 'Benz';var car = new Car();console.log(car); //Car {name: "mazda"}
找到自身有的属性而不是找原型上的属性
尝试强行修改实例对象的__proto__的值
function Person() {}Person.prototype.name = '张三';var p1 = {name: 'lisi'}var person = new Person();console.log(person.__proto__); //{name: "张三", constructor: ƒ}person.__proto__ = p1;console.log(person.__proto__); //{name: "lisi"}
说明__proto__属性可以更改
对属性的重写
function Car() {}Car.prototype.name = 'Mazda';var car = new Car();Car.prototype.name = 'Benz';console.log(car.name); //Benz
Car.prototype.name = 'Mazda';function Car() {}var car = new Car();Car.prototype.name = 'Benz';console.log(car.name); //Benz
Car.prototype.name = 'Mazda';function Car() {}Car.prototype.name = 'Benz';var car = new Car();console.log(car.name); //Benz
注意:实例化之前的
prototype和实例化的prototype是有区别的
Car.prototype.name = 'Benz';function Car() {}var car = new Car();//还没实例化Car.prototype = {name: 'Mazda'}console.log(car.name); //Benz//实例化以后function Car() {var this = {__proto__: Car.prototype = {name: 'Benz'}}}
Car.prototype.name = 'Benz';function Car() {}Car.prototype = {name: 'Mazda'}var car = new Car();console.log(car.name); //Mazda
Car.prototype.name = 'Benz';function Car() {}var car = new Car();Car.prototype = {name: 'Mazda'}var car2 = new Car();console.log(car.name); //Benzconsole.log(car2.name); //Mazda
时间线
Car.prototype.name = 'Benz';function Car() {};console.log(Car.prototype);var car = new Car();console.log(car);/*** 没实例化:* 打印Car.prototype结果:* {name: "Benz", constructor: ƒ}name: "Benz"constructor: ƒ Car()name: "Car"prototype: {name: "Benz", constructor: ƒ}__proto__: ƒ ()__proto__: Object*//*** 实例化后:* 打印car结果:* Car {}__proto__:name: "Benz"constructor: ƒ Car()name: "Car"prototype: {name: "Benz", constructor: ƒ}__proto__: ƒ ()__proto__: Object*/
原型链
实例对象的__proto__指向构造函数的原型,所有的对象都有自己的原型(包括原型本身)
function Car() {}var car = new Car();console.log(Car.prototype);console.log(car);/*** 打印Car.prototype:* {constructor: ƒ}constructor: ƒ Car()__proto__: Object*//*** 打印car:* Car {}__proto__: Object => 指向Car.prototype*/
概念
沿着__proto__去找原型里的属性一层一层的继承原型的属性的这条链
Professor.prototype.tSkill = 'JAVA';function Professor() {}var professor = new Professor();Teacher.prototype = professor;function Teacher() {this.mSkill = 'JS/JQ';}var teacher = new Teacher();Student.prototype = teacher;function Student() {this.pSkill = 'HTML/CSS'}var student = new Student();console.log(student);/*** 打印student* Student {pSkill: "HTML/CSS"}pSkill: "HTML/CSS"__proto__: ProfessormSkill: "JS/JQ"__proto__: Professor__proto__:tSkill: "JAVA"constructor: ƒ Professor()__proto__: Object*/
原型的顶端是Object.prototype(面试问题)
console.log(Professor.prototype);/*** 打印Professor.prototype:* {tSkill: "JAVA", constructor: ƒ}tSkill: "JAVA"constructor: ƒ Professor()__proto__:constructor: ƒ Object()toString: ƒ toString()*/
注:
Object.prototype.toString()
原型链上的增删改只能是它自己本身增删改(后代不能)
引用值思考:子代赋值是否影响被继承的原型?子代赋值还是父代被赋值?
function Teacher() {this.mSkill = 'JS/JQ';//引用值this.success = {alibaba: '28',tencent: '30'}}var teacher = new Teacher();Student.prototype = teacher;function Student() {this.pSkill = 'HTML/CSS'}var student = new Student();student.success.baidu = '100';console.log(teacher);//Professor {mSkill: "JS/JQ", success: {alibaba: "28", tencent: "30", baidu: "100"}}console.log(student);//Student {pSkill: "HTML/CSS"}
结果看出没有赋值到实例对象里而是赋值到实例对象的原型上
分析:子代实例对象不存在success属性,所以向上找success属性并修改值
引用值思考:
function Teacher() {this.mSkill = 'JS/JQ';this.success = {tencent: '26'}}var teacher = new Teacher();Student.prototype = teacher;function Student() {this.pSkill = 'HTML/CSS'this.success = {alibaba: '26'}}var student = new Student();student.success.baidu = '100';console.log(teacher);//Professor {mSkill: "JS/JQ", success: {tencent: "26"}}console.log(student);//Student {pSkill: "HTML/CSS", uccess: {alibaba: "26", baidu: "100"}}
子代实例对象已经存在success属性只更改自己的属性值
原始值思考:
function Teacher() {this.mSkill = 'JS/JQ';//原始值this.students = 500;}var teacher = new Teacher();Student.prototype = teacher;function Student() {this.pSkill = 'HTML/CSS'}var student = new Student();student.students++;console.log(teacher);//Professor {mSkill: "JS/JQ", students: 500}console.log(student);//Student {pSkill: "HTML/CSS", students: 501}//分析student.students++ => student.students = student.students += 1即student原来没有students属性,但是在赋值的时候被增加了students属性
子代实例对象不能修改父代的原始值属性,隐式的为子代实例对象增加原始值属性
原始值思考:
function Teacher() {this.mSkill = 'JS/JQ';this.students = 500;}var teacher = new Teacher();Student.prototype = teacher;function Student() {this.pSkill = 'HTML/CSS';}var student = new Student();student.students = '800';console.log(teacher);//Professor {mSkill: "JS/JQ", students: 500}console.log(student);//Student {pSkill: "HTML/CSS", students: "800"}
赋值的情况下会帮student实例对象新增属性students并赋值
function Car() {this.brand = 'Benz';}Car.prototype = {brand: 'Mazda',intro: function () {console.log('我是' + this.brand + '车');}}var car = new Car();car.intro(); //我是Benz车 this => 实例对象Car.prototype.intro(); //我是Mazda车 this => Car.prototype
实例化对象已经存在brand,改变调用对象可以改变方法的输出
原型的原型Object.prototype
function Obj() {}var obj = new Obj();console.log(obj.__proto__.__proto__);
Object.create(对象/null)创建对象用的方法
此方法可以自己定义,可以指定原型
function Obj() {}Obj.prototype.num = 1;//两条语句产生的效果是一样的var obj1 = Object.create(Obj.prototype);var obj2 = new Obj();console.log(obj1);/*** 打印obj1 和 打印obj2:* Obj {}__proto__:num: 1constructor: ƒ Obj()__proto__: Object*/
var test = {num: 2}function Obj() {}Obj.prototype.num = 1;var obj1 = Object.create(test);var obj2 = new Obj();console.log(obj1);console.log(obj2);/*** 打印obj1* {}__proto__:num: 2__proto__: Object** 打印obj2:* Obj {}__proto__:num: 1constructor: ƒ Obj()__proto__: Object*/
Object.create()提供了一个自定义原型的功能
通过Object.create(null)创建一个空对象
var obj1 = Object.create(null);console.log(obj1);//{}// No properties
var obj1 = Object.create(null);console.log(obj1);obj1.num = 1;var obj2 = Object.create(obj1);console.log(obj2);console.log(obj2.num); //1/*** 打印obj2:* {}__proto__:num: 1*/
作用:把其他对象作为自己的原型存在
思考:是不是所有的对象都继承Object.prototype?
var obj = Object.create(null);obj.num = 1;obj.toString(); //报错,说明没有该方法console.log(obj); //这个对象并没有原型
说明通过Object.create(null)创建的对象不继承Object.prototype
不是所有的对象都继承于Object.prototype(面试题)
手动添加对象并赋值给Object.create(null)创建的对象
var obj = Object.create(null);obj.num = 1;var obj1 = {count: 2}obj.__proto__ = obj1;console.log(obj);console.log(obj.count); //undefined/*** 打印obj:* {num: 1, __proto__: {…}}num: 1__proto__:count: 2__proto__: Object*/
发现可以继承Object.prototype,但访问不了变量,说明自己定义的__proto__是不行的,必须是系统内置的才能访问(只能更改不能制造__proto__)
思考:undefined和null能否使用Object.prototype.toString()方法?
console.log(undefined.toString()); //报错console.log(null.toString()); //报错
原始值是没有属性的,只有引用值才有
var num = 1;console.log(num.toString()); //1 字符串//包装类的过程//new Number(1) -> toString();var num2 = new Number(num);console.log(num2);/*** 打印num2:* Number {1}__proto__: Numberconstructor: ƒ Number()toString: ƒ toString()**/
undefined和null不能经过包装类,还没有原型
var num = 1;var obj = {};var obj2 = Object.create(null);//document.write() 此处有个隐式转换的操作把要打印的内部转换成string类型document.write(num); //页面显示 1document.write(obj); //页面显示 1[object Object]console.log(Object.prototype.toString(obj)); //[object Object]//obj2没有原型没法继承Object.prototype,没法转换string类型// document.write(obj2); //报错 不能转换对象为原始值 所以没法打印
思考:为什么Number()有自己的toString()方法而不是去继承对象原型的toString()方法?
包装类都有自己系统内置的toString()方法
console.log(Object.prototype);console.log(Number.prototype);console.log(String.prototype);console.log(Boolean.prototype);console.log(Array.prototype);
区别:Object.prototype.toSting()和Number.prototype.toSting()
console.log(Object.prototype.toString.call(1));//"[object Number]" -> [对象类型的Number构造函数]console.log(Object.prototype.toString.call('a'));//"[object String]" -> [对象类型的String构造函数]console.log(Object.prototype.toString.call(true));//"[object Boolean]" -> [对象类型的Boolean构造函数]console.log(Object.prototype.toString.call([1, 2]));//"[object Array]" -> [对象类型的Array构造函数]console.log(Object.prototype.toString.call({name: 1}));// "[object Object]" -> [对象类型的Object构造函数]//说明两个toString()是不一样的,实现的功能不一样的console.log(Number.prototype.toString.call(1)); //'1'console.log(Object.prototype.toString.call(1)); //[object Number]
说明两个toString()是不一样的,实现的功能不一样的,也不是继承Object.prototype, 返回的值也不一样
因为Number.prototype跟Object.prototype的返回值不一样(需求不一样),所以Number.prototype单独重写了toString()方法
继承
Professor.prototype = {name: 'Mr.Zhang',tSkill: 'JAVA'}function Professor() {}var professor = new Professor();Teacher.prototype = professor;//------------------------------------------function Teacher() {this.name = 'Mr.Wang';this.mSkill = 'JS/JQ';}var teacher = new Teacher();//------------------------------------------Student.prototype = teacher;function Student() {this.name = 'Mr.Li';this.pSkill = 'HTML/CSS'}var student = new Student();console.log(student);/*** student:* Student {name: "Mr.Li", pSkill: "HTML/CSS"}name: "Mr.Li"pSkill: "HTML/CSS"__proto__:mSkill: "JS/JQ"name: "Mr.Wang"__proto__:__proto__:name: "Mr.Zhang"tSkill: "JAVA"__proto__: Object*/
思考:学生是否需要继承老师和教授身上的所有的属性?
实际上并不需要
call/appl可以实现”继承”(借用属性方法)但是没办法继承原型
function Teacher(name, mSkill) {this.name = name;this.mSkill = mSkill;}function Student(name, mSkill, age, major) {Teacher.apply(this, [name, mSkill]);this.age = age;this.major = major;}var student = new Student('Mr.Zhang', 'JS/JQ', 18, 'Computer');console.log(student);/*** 打印student:* Student {name: "Mr.Zhang", mSkill: "JS/JQ", age: 18, major: "Computer"}age: 18mSkill: "JS/JQ"major: "Computer"name: "Mr.Zhang"__proto__:constructor: ƒ Student(name, mSkill, age, major)__proto__: Object*/
继承原型的操作
function Teacher() {this.name = 'Mr.Li';this.tSkill = 'JAVA';}Teacher.prototype = {pSkill: 'JS/JQ'}var t = new Teacher();console.log(t);function Student() {this.name = 'Mr.Wang';}//继承原型Student.prototype = Teacher.prototype;var s = new Student();console.log(s);/*** 打印teacher:* Teacher {name: "Mr.Li", tSkill: "JAVA"}name: "Mr.Li"tSkill: "JAVA"__proto__:pSkill: "JS/JQ"__proto__: Object*//*** 打印student:Student {name: "Mr.Wang"}name: "Mr.Wang"__proto__:pSkill: "JS/JQ"__proto__: Object*/
以上基础存在修改子代原型会影响父代的原型的问题
...//继承原型 此时赋值会影响teacher的原型Student.prototype = Teacher.prototype;Student.prototype.age = 18;.../*** 打印teacher:* Teacher {name: "Mr.Li", tSkill: "JAVA"}name: "Mr.Li"tSkill: "JAVA"__proto__:age: 18pSkill: "JS/JQ"__proto__: Object*//*** 打印student:Student {name: "Mr.Wang"}name: "Mr.Wang"__proto__:age: 18pSkill: "JS/JQ"__proto__: Object*/
圣杯模式
Buffer
思考:如何解决上述问题?
企业级方法
function Teacher() {this.name = 'Mr.Li';this.tSkill = 'JAVA';}Teacher.prototype = {pSkill: 'JS/JQ'}var t = new Teacher();function Student() {this.name = 'Mr.Wang';}//企业级方案//中转构造函数--Bufferfunction Buffer() {}Buffer.prototype = Teacher.prototype;var buffer = new Buffer();Student.prototype = buffer;var s = new Student();console.log(s);/*** 打印s:* Student {name: "Mr.Wang"}name: "Mr.Wang"__proto__:__proto__:pSkill: "JS/JQ"__proto__: Object*/
完美解决继承和隔离的问题
封装
//继承方 -> Target//被继承方 -> Originfunction inherit(Target, Origin) {function Buffer() {}Buffer.prototype = Origin.prototype;Target.prototype = new Buffer();//还原构造器Target.prototype.constructor = Target;//设置继承源Target.prototype.super_class = Origin;}/*** 打印s:* Student {}__proto__: Teacherconstructor: ƒ Student()super_class: ƒ Teacher()__proto__: Object*/
立即执行函数
IIFE-immediately invoked function expression
自动执行,执行完成以后立即销毁
作用:
- 初始化函数
写法:
;(function(){})();
;(function(){}()); //W3C建议
传参:
(function (a, b) {var a = 1,b = 2;console.log(a + b);})(1, 2);
返回值:
var num = (function (a, b) {var a = 1,b = 2;return a + b;})(1, 2);console.log(num); //3
注:
()里加上任何东西都为表达式
报错:函数声明写法加执行符号
function test() {console.log('111');}()
正常运行:函数表达式加执行符号
var test = function test() {console.log('111');}()
正常运行:函数声明写法加执行符号且传入参数
function test(a) {console.log(1); //没有打印}(6);
逗号运算符返回逗号后面的数据
console.log((6, 5)); //5var num = (2 - 1, 6 + 5, 24 + 1);console.log(num); //25
- 说明一定是表达式才能被执行符号执行
- 执行符号里面的逗号是一个运算符
var test = function () {console.log(1);}console.log(test); //function(){...}var test1 = function () {console.log(2); //2}();console.log(test1); //undefined 说明销毁了
证明立即执行函数可以立即执行且执行完之后就销毁
(function () {console.log(123); //123})();(function test() {console.log(123); //123})();
证明能够被执行符号执行的都为表达式,表达式会自动忽略函数名称
函数声明转换为表达式的方法:+,-,!, &&, ||
+ function test() { };- function test() { };! function test() { };1 && function test() { };0 || function test() { };
循环点击案例
打印5个函数但没执行
function test() {var arr = [];for (var i = 0; i < 5; i++) {arr[i] = function () {document.write(i + '');}}return arr;}var myArr = test();console.log(myArr); //[f, f, f, f, f]
继续循环执行5个函数
for (var j = 0; j < 5; j++) {myArr[j]();}//5 5 5 5 5
打印结果为5个5,而不是1到5,为什么?
分析:
//1. i < 5 进入循环//2. 第i项为一个声明函数但没执行函数//3. i++//4. 直到i=5无法进入循环//5. 此时return arr形成5个闭包且这时i = 5//6. 当循环j执行函数调用的时候拿到的是最后一项i的值为5//所以test函数里面arr[i]永远都为arr[5]
function test() {var arr = [];var i = 0 //当i = 5 时 return arrfor (; i < 5;) {arr[i] = function () {document.write(i + '');}i++}console.log(i); //5return arr;}var myArr = test();console.log(myArr); //[f, f, f, f, f]for (var j = 0; j < 5; j++) {myArr[j]();}//5 5 5 5 5
如何打印0-5
function test() {var arr = [];for (var i = 0; i < 5; i++) {arr[i] = (function () {document.write(i + '');})();}return arr;}test();
继续简写
function test() {for (var i = 0; i < 5; i++) {(function () {document.write(i + '');})();}}test();
写法二借助参数
function test() {var arr = [];for (var i = 0; i < 5; i++) {arr[i] = function (num) {document.write(num + '');}}return arr;}var myArr = test();for (var j = 0; j < 5; j++) {myArr[j](j);}
写法三 借助立即执行函数里新增一个声明函数保存的参数
function test() {var arr = [];for (var i = 0; i < 5; i++) {(function (f) {arr[f] = function () {document.write(f + '');}})(i);}return arr;}var myArr = test();for (var j = 0; j < 5; j++) {myArr[j]();}
模块化
模块化开发:闭包的形式包装圣杯模式(企业级写法)
避免环境污染
利于后期维护和二次开发
var inherit = (function () {var Buffer = function () {}return function (Target, Origin) {Buffer.prototype = Origin.prototype;Target.prototype = new Buffer();Target.prototype.constructor = Target;Target.prototype.super_class = Origin;}})();Teacher.prototype.name = 'Mr.Zhang';function Teacher() {}function Student() {}var s = new Student;var t = new Teacher;console.log(s);console.log(t);inherit(Student, Teacher)
案例:
var inherit = (function () {var Buffer = function () {}return function (Target, Origin) {Buffer.prototype = Origin.prototype;Target.prototype = new Buffer();Target.prototype.constructor = Target;Target.prototype.super_class = Origin;}})();//创建一个独立的空间让其自启动var initProgrammer = (function () {//父级构造函数var Programmer = function () {}//父级原型增加属性和方法Programmer.prototype = {name: '程序员',tool: '计算机',work: ' 编写英语程序',duration: '10个小时',say: function () {console.log('我是一名' +this.myName +this.name +', 我的工作是用' +this.tool +this.work +'我每天工作' +this.duration +'我的工作需要用到' +this.lang.toString() +'。');}}//子级构造函数//实例化以后可以访问父级原型的属性和方法function FrontEnd() {}function BackEnd() {}//继承父级inherit(FrontEnd, Programmer);inherit(BackEnd, Programmer);//子级原型上新增属性FrontEnd.prototype.lang = ['HTML', 'CSS', 'JavaScript'];FrontEnd.prototype.myName = '前端';BackEnd.prototype.lang = ['JAVA', 'Node', 'SQL'];BackEnd.prototype.myName = '后端';//子级构造函数返回出去//return外面必须要有变量接收返回值return {FrontEnd: FrontEnd,BackEnd: BackEnd}})();var frontEnd = new initProgrammer.FrontEnd();var bacnEnd = new initProgrammer.BackEnd();frontEnd.say();//我是一名前端程序员, 我的工作是用计算机 编写英语程序我每天工作10个小时我的工作需要用到HTML,CSS,JavaScript。bacnEnd.say();//我是一名后端程序员, 我的工作是用计算机 编写英语程序我每天工作10个小时我的工作需要用到JAVA,Node,SQL。
关于企业级协助开发
window.onload = function () {init();}function init() {initCompute();initFunctions();}var initCompute = (function () {var a = 1,b = 2;function add() {console.log(a + b);}function minus() {console.log(a - b);}function mul() {console.log(a * b);}function div() {console.log(a / b);}//抛出的函数是需要执行的return function () {add();minus();mul();div();}})();var initFunctions = (function () {})();
插件开发
函数表达式变量接收立即执行函数的闭包
var add = (function test() {var a = 1;function add() {a++;console.log(a);}return add;})();add(); //2add(); //3
利用全局变量保存立即执行函数的闭包
(function test() {var a = 1;function add() {a++;console.log(a);}window.add = add;})();add(); //2add(); //3
插件化写法
(function () {function Test() { }window.Test = Test;})();var test = new Test();
