NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
## **1.****构造函数原型对象:****prototype** ### **①****构造函数独立创建对象,消耗性能**     function Person(**name**) {         this.name =**name**;         this.sayHello = function () {             console.log("Hello,my name is " + this.name)         }     }     var P1 = new Person("Tom");     var P2 = new Person("Tom");     P1.sayHello();     P2.sayHello();     console.log(P1.sayHello == P2.sayHello)  **返回值为****false** 返回值为false说明通过同一个构造函数独立创建的两个构造函数对象P1和P2的sayHello方法不相等,说明他们分别在内存中开辟了存储空间,消耗性能 ### **②prototype****:每一个函数都会有一个****prototype****属性** 将同一个构造函数创建出的不同对象的不同函数方法,创建在该构造函数的prototype属性中,可实现只创建一次,所有该构造函数对象都可以调用这一方法 ![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224155426695-543029163.png) **prototype**是构造函数的原型属性,也是构造函数对象例如图中P1、P2的原型对象 ### **③****prototype****代码演示** ### **(****1****)动态添加方法属性,方法是独立分布添加上的,保留****prototype****指向构造函数的****constructor****属性** ![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224155957273-1296273974.png) function**Person**(name) {         this.name = name;     }     Person.**prototype**.sayHello = function () {         console.log("sayHello");     }     Person.**prototype.**study = function () {         console.log("study");     }     Person.**prototype**.goHome = function () {         console.log("goHome");     }     var P1 = new Person("Tom");     var P2 = new Person("Jim");     var P3 = new Person("Jack");     P1.sayHello();     P2.study();     P3.goHome(); **(****2****)直接替换,创建一个对象添加方法属性,原本指向构造函数的****constructor****属性消失,****该替换添加在构造函数实例对象声明之前** **![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224160240695-1415486163.png)**  function**Person**(name) {         this.name = name;     } **Person.****prototype****\= {** **constructor:Person,****手动添加****constructor****属性** **        sayHello: function () {** **            console.log("sayHello");** **        },** **        study: function () {** **            console.log("study");** **        },** **        goHome: function () {** **            console.log("goHome");** **        }** **    }**     var P1 = new Person("Tom");**声明构造函数对象**     var P2 = new Person("Jim");     var P3 = new Person("Jack");     P1.sayHello();     P2.study();     P3.goHome(); ### **④****\_\_proto\_\_:****实例对象访问原型属性(双下划线)****  IE8****以下不支持** **构造函数通过****prototype****访问原型** **实例对象通过****\_\_proto\_\_****访问原型** (1)示例代码如下:         var object = {};         object.name = "Tom";         object.age = 18;         object.\_\_proto\_\_ = {             hello: "hello",             color: "red"         }         console.log(object.hello); 通过这个方法,可以给实例对象统一添加方法属性 (2)兼容性处理  **IE8****兼容处理** 利用构造函数,访问**constructor**的**prototype**,这样就可以访问原型     function**Person**(name) {         this.name = name;     }     function**\_\_getProto\_\_**(**object**) {         return**object**.**constructor**.**prototype**;     }     var ob = new**Person**("Jack"); console.log(**\_\_getProto\_\_**(ob) === ob.**\_\_proto\_\_**);  **返回值为****true** ## **2.****继承** ### **①****HTML****对象原型继承关系,示例****div:** **![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224160442820-1547902602.png)** ### **② ****混入** **通过给对象添加一个****extend****方法,动态给对象添加属性**  **arguments**: 函数中默认的类似**数组类型**对象,里面存储了所有传入的**参数** 相关代码示例如下:     var**object**\= {       ** extend**: function (obj) {             for (var i = 0; i <**arguments**.length; i++) {                 for (var k in**arguments**\[i\]) {                     this\[k\] =**arguments**\[i\]\[k\];                 }             }         }     }     object.**extend**({name: "Tom"}, {age: 20, gender: "male"}, {         sayHello: function () {             console.log("Hello");         }     }); console.log(**object**) ### **③****混合式继承****通过给构造函数的原型属性添加方法实现** 示例代码如下:     function**Person**() {        **Person.prototype****.extend**\= function (**obj**) {             for (var i = 0; i < arguments.length; i++) {                 for (var k in arguments\[i\]) {                     this\[k\] = arguments\[i\]\[k\];                 }             }         }     }     var**p**\= new**Person**();    **p**.**extend**({name: "Tom"}, {age: 20, gender: "male"}, {         sayHello: function () {             console.log("Hello");         }     }); console.log(**p**); ### **④****Object.create( ) ****创建对象****    IE8****以下不支持该方法** 示例代码如下:     varo\= {name: "Tom", age: 20, gender: "male"};     varobj\= Object.create(o);     console.log(obj); ![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224160726960-2029469342.png) 创建的对象obj的属性和方法均继承自传入的对象o **Object.create( )****方法的实现原理如下:**     Object.create = function (**obj**) {         function**F**() { };        **F**.**prototype**\=**obj**;         return new**F**(); } **IE8****兼容性封装:**     function**createWithObject**(**obj**) {         if (Object.create) {             return Object.create(**obj**);         } else {             function**F**() { };            **F.**prototype =**obj**;             return new**F**();         } } ## **3.****对象的原型链****(构造函数)** 示例代码如下:     function**Person**(**name**,**age, gender**) {         this.name =**name**;         this.age =**age;**         this.gender =**gender**;     };     function**Student**() { };    **Student**.**prototype**\= new**Person**("Tom", 18, "male"); var student = new**Student**(); function**Instance**(){ };    **所有构造函数都指向相同的原型** 以上代码所对应的原型链结构示意图如下: ![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224160917054-1990360730.png) ## **4\. Function****创建函数** **Function****是一个构造函数****  new Function****得到一个函数** **new Function(arg0,arg1,…,argN,body);****最后一个参数****body****是函数执行的代码块(函数体),其他参数都是传入函数代码块的参数** 代码示例如下: var getSum = new**Function**(“**num1**” , ”**num2**”, ”return num1+num2”); 函数代码块、函数体中内容太多时书写方法: ### **1.****直接书写:** **高斯求和函数**  var**getSum**\= new**Function**(“**min**” , ”**max**”, ” var sum = 0;for (var i = min; i <= max; i++) { sum = sum + i;}return sum;”); ### **2.****字符串拼接书写:**     var**getSum**\= new Function("**min**", "**max**",             "var sum = 0;"**+**             "for (var i = min; i <= max; i++) {"**+**             "sum = sum + i;"**+**             "}"**+**             "return sum;"); ### **3.****获取****HTML****中的****value****书写:** 封装一个tool函数:     function**tool**(**idName**) {         var**ele**\= document.getElementById(**idName**);         var**code**\=**ele**.**innerText**;        **ele**.parentNode.removeChild(ele);        **ele**\=**null;**         return**code**; } 将需要传入的参数内容写入HTML中:        var sum = 0;         for (var i = min; i <= max; i++) {           sum = sum + i;     }     return sum; 再创建函数: var**getSum**\= new Function("min", "max",**tool**("**div**")); ## **5.****函数的原型链** **在****js****中任何函数都是****Function****的实例** console.log(**Function**)   结果:function Function() { \[native code\] } 函数的基本原型链结构如下图所示: ![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224161738710-234242617.png) ##  **6.****完整的原型链结构图(对象与函数)** **![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224162048273-1611949554.png)** **instanceof:****判断构造函数的原型属性是否在该对象的原型链上**     function Person() {};     var p = new Person();     console.log(p**instanceof**Object)           **返回****ture**     console.log(p**instanceof**Person)          **返回****ture**     console.log(Personi**nstanceof**Function)      **返回****ture**     console.log(Person**instanceof**Object)       **返回****ture** **不应该过多依赖原型链继承,非常消耗性能,解决办法如下:**     var**o**\= {         method: function () {             console.log("这是一个方法");         }     }     function**Person**() { };     Person.prototype =**o;**     function**Student**() {      **  this.method = Person.prototype.method;  ****通过这种方式快速访问****method**     }    Student.prototype = new**Person**();    **这样访问消耗性能,可以省略**     var s = new**Student**();     s.method(); ## **7.****闭包**** js****中函数是具有作用域隔离特性的内存结果,可以作为一个闭包** ### **①****返回函数**     function**func**() {         var num = Math.random();         function**fn**() {             console.log(num);             return num;         }         return**fn**;     }     var foo =**func**();     var f1 = foo(); var f2 = foo(); 因为在**func**中返回了**fn**,所以**func**只会被调用一次,**fn**被调用两次,打印结果相同 ### **②****沙箱模式****一个隔离的执行环境** **(****1****)递归函数性能优化,以斐波拉契数列为例:**     var**count1**\= 0;     function**fib1**(n) {        **count1**++;         if (n == 1 || n == 2) {             return 1;         } else {             return**fib1**(n - 1) +**fib1**(n - 2);         }     }     console.log(**fib1**(30));     console.log(**count1**);     var**count2**\= 0;     var data = \[1, 1\];     **声明一个数组接收创建的****fib(n)**     function**fib2**(n) {        **count2**++;         if (data\[n-1\]) {     **如果数组中有值,直接返回该值**             return data\[n-1\];         } else {             return data\[n-1\] =**arguments.callee**(n - 1) +**arguments.callee**(n - 2);         }     }     console.log(**fib2**(30));     console.log(**count2**);  ![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224165140523-2064381134.png) 通过比较count1与count2的值可以发现,使用数组接收存储fib2(n)值的函数递归次数明显小于直接递归的fib1函数,性能得到极大优化 **对斐波拉契数列函数进行闭包封装:****封装一个自执行函数****fib**     var**fib**\= (function () {         var data = \[1, 1\];         return function(n) {             if (data\[n - 1\]) {              return data\[n - 1\];             } else {              return data\[n - 1\] = arguments.callee(n - 1) + arguments.callee(n - 2);             }         } })();  **(****2****)闭包应用:封装一个带有事件添加和移除的函数**     var**tabbLoad**\= (function () {         var data = \[\];         window.onload = function () {             for (var i = 0; i < data.length; i++) {                 data\[i\]();             }         }         return {            **addEvent**: function (fn) {                 data.push(fn);             },**removeEvent**: function (fn) {                 for (var i = data.length - 1; i >= 0; i--) {                     if (fn.toString() === data\[i\].toString()) {                         data.splice(i, 1);                     }                 }             }         } })();  **  tabbLoad**.**addEvent**(function () {         console.log("执行函数1")     })   ** tabbLoad**.**addEvent**(function () {         console.log("执行函数2")     })   ** tabbLoad**.**removeEvent**(function () {         console.log("执行函数2")     }) **(****3****)闭包应用:创建一个可以缓存的函数****cache**     var**createCache**\= (function () {       ** var**data = \[\], max = 3;    **max****为设置的缓存最大值,在查看****data****数据时可以将****var****去掉,将****data****变为全局变量,但在实际应用时一定不能去掉**         function**cache**(**key**,**value**) {             data.push(**key**);           ** cache**\[**key**\] =**value**;             if (data.length > max) {                 var temp = data.shift();                **delete****cache**\[temp\];             }         }         return**cache**;     })();    **cache**("name1","Tom")    **cache**("name2","Jim")   ** cache**("name3","Jack") **   cache**("name4","Lily") ![](https://images2015.cnblogs.com/blog/1071151/201702/1071151-20170224162844476-1327866470.png)