目录
一、css
1.用纯CSS创建一个三角形的原理是什么?(▲)
上、左、右三条边隐藏掉(颜色设为 transparent)
#demo {
width: 0;
height: 0;
border-width: 20px;
border-style: solid;
border-color: transparent transparent red transparent;
}
display: flex;
justify-content: center;
aligin-items: center;
二、js基础
1.判断一个对象是否为jquery对象可以用 obj instanceof jQuery
2.js原生方法操作节点
var box=document.getElementById("box");
var tags=document.getElementsByTagName("*");//获取HTML的所有标签
var box2=document.getElementsByClassName("box");//获取class名为box的所有元素
var formName=document.getElementsByName("user");//含有name属性的元素
var p2=document.createElement("p"); //创建元素节点
p2.className = "info-top";//给元素设置className
var txt=document.createTextNode("这是另一个段落"); //创建文本节点
p2.appendChild(txt); //把创建的文本节点追加到元素节点中
var attr=document.createAttribute("id"); //创建属性节点
attr.value="p2"; //给属性节点设置值
p2.setAttributeNode(attr); //给元素设置属性节点
box.appendChild(p2); //把创建的p元素追加到box最后
console.log(box);
let box1 = document.querySelector(".box");//仅返回匹配指定选择器的第一个元素
let boxes= document.querySelectorAll(".box");//返回匹配的所有的元素
总结:1.所有获取DOM对象的方法中,只有getElementById()和querySelector()这两个方法直接返回的DOM对象本身,可直接为其绑定事件。
2.getElementXXX类型的方法,除了通过Id获取元素,其他都返回一个集合,如果需要取到具体的DOM元素,需要加索引,如:document.getElementsByClassName(“box”)[0] =>获取class为box的所有元素中的第一个DOM元素。
3.querySelector()与querySelectorAll()两者的联系与区别:
联系: 两者括号中的取值都是选择器
区别: 当有多个class相同的元素时,使用querySelector()方法只能获取到第一个class为box的元素,而querySelectorAll()获取到了所有class为box的元素集合。
3.js的拷贝 (这题涉及到的就是你能不能清楚的分辨深拷贝和浅拷贝)
var a = {name:'Tom'}; var b = a; b.name = 'Peter';
请问a.name = ?
正确答案是Peter,如果你的答案是Tom的话,那么你要好好去看看js的深拷贝。
如果要被拷贝的是数组:slice和concat都可以直接让数组进行深拷贝
arr.slice();
arr.concat();
4. javascript的同源策略,jsonp的原理
一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是域名、协议和端口号的组合
同源策略带来的麻烦:ajax在不同域名下的请求无法实现,如果说想要请求其他来源的js文件,或者json数据,那么可以通过jsonp来解决
JSONP的实现原理:通过动态创建script标签,给请求的地址中添加一个get参数,这个参数代表回调函数,也就是希望服务器处理完我的请求之后,在前端执行这个回调函数
$.ajax({
//url:"http://localhost:8081/rest/itemcat/list?callback=getMessage",
url:"http://localhost:8081/rest/itemcat/message",
type:"get",
cache:false,
dataType:"jsonp",
jsonp:"callback", //这里定义了callback的参数名称,以便服务获取callback的函数名即getMessage
jsonpCallback:"getMessage", //这里定义了jsonp的回调函数
success:function(data){
alert("success:"+data);
},
error:function(){
alert("发生异常");
}
});
jsonp:"callback", jsonpCallback:"getMessage",
这两个参数的值会自动拼接在url后面,所以用jquery的$.ajax方法发出的url可以不用在后面添加callback=getMessage
5.Js获取当前日期时间
var myDate = new Date();
myDate.getYear(); //获取当前年份(2位)
myDate.getFullYear(); //获取完整的年份(4位,1970-????)
myDate.getMonth(); //获取当前月份(0-11,0代表1月)
myDate.getDate(); //获取当前日(1-31)
myDate.getDay(); //获取当前星期X(0-6,0代表星期天)
myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数)
myDate.getHours(); //获取当前小时数(0-23)
myDate.getMinutes(); //获取当前分钟数(0-59)
myDate.getSeconds(); //获取当前秒数(0-59)
myDate.getMilliseconds(); //获取当前毫秒数(0-999)
myDate.toLocaleDateString(); //获取当前日期
var mytime=myDate.toLocaleTimeString(); //获取当前时间
myDate.toLocaleString( ); //获取日期与时间
6.js数据类型
基础数据类型: number,string,null,undefined,boolean,存放在栈内存
引用数据类型:Object ,Array,Function(Date,RegExp),存放在堆内存
7.数组的操作方法
8. 字符串的操作
总结:
截取字符串:substr、substring、slice这三个方法,它们接收的第一个参数都为开始的位置,而substr(),第二个参数表示截取的长度,slice()和substring(),表示结束的位置,而不包括它。
查找字符:
1.search()、indexOf() / lastIndexOf():查找字符并返回该字符在字符串中的索引,没有则返回-1;
2.match():匹配字符,并返回匹配到的字符组成的数组,没有则返回null,可填入正则;
3.replace():用来查找并替代字符,两个参数,第一个是需要被替代的字符,第二个是用来替代的字符;
str.search(/w3school/i)//忽略大小写的检索
9. 什么叫优雅降级和渐进增强?
渐进增强 :针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
区别:
a. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给
b. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要
c. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带
10.浏览器的内核分别是什么?
IE: trident内核
Firefox:gecko内核
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink(基于webkit,Google与Opera Software共同开发)
11.谈谈垃圾回收机制方式,内存管理,和内存泄漏
垃圾回收机制方式
1、定义和用法:Javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境负责管理代码执行过程中使用的内存。
2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生命周期直至浏览器卸载页面才会结束。局部变量只在函数的执行过程中存在,而在这个过程中会为局部变量在栈或堆上分配相应的空间,以存储它们的值,然后在函数中使用这些变量,直至函数结束,而闭包中由于内部函数的原因,外部函数并不能算是结束。
3. 垃圾回收策略:标记清除(较为常用)和引用计数。
标记清除:
定义和用法:当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:"离开环境"。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。
到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。
内存管理
1.什么时候触发垃圾回收?
垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。IE6的垃圾回收是根据内存分配量运行的,当环境中的变量,对象,字符串达到一定数量时触发垃圾回收。垃圾回收器一直处于工作状态,严重影响浏览器性能。IE7中,垃圾回收器会根据内存分配量与程序占用内存的比例进行动态调整,开始回收工作。
2、合理的GC方案:(1)、遍历所有可访问的对象; (2)、回收已不可访问的对象。
3、GC缺陷:(1)、停止响应其他操作;
4、GC优化策略:
(1)、分代回收(Generation GC):这个和Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。
(2)、增量GC:这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推”。
开发过程中遇到的内存泄露情况,如何解决的?
1、定义和用法:内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。C#和Java等语言采用了自动垃圾回收方法管理内存,几乎不会发生内存泄露。我们知道,浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。
2、内存泄露的几种情况:
(1)、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。
解决方法如下:
(2)、由于是函数内定义函数,并且内部函数--事件回调的引用外暴了,形成了闭包。闭包可以维持函数内局部变量,使其得不到释放。
解决方法如下:
function bindEvent(){
var obj=document.createElement("XXX");
obj.onclick=function(){
//Even if it's a empty function
}
obj=null;
}
12.display:none和visibility:hidden区别
1.display:none是彻底消失,不在文档流中占位,浏览器也不会解析该元素;visibility:hidden是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;
2.使用visibility:hidden比display:none性能上要好,display:none切换显示时visibility,页面产生回流(当页面中的一部分元素需要改变规模尺寸、布局、显示隐藏等,页面重新构建,此时就是回流。所有页面第一次加载时需要产生一次回流),而visibility切换是否显示时则不会引起回流。
13.JS有哪些手段可以实现继承?
1.原型链继承:将父类的为父类实例添加新特性,作为子类实例返回实例作为子类的原型
2.构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
3.实例继承:为父类实例添加新特性,作为子类实例返回
4.拷贝继承:
5.组合继承:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
6.寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
14.undefined和null的区别, 还有undeclared
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
15.什么是闭包? 闭包有什么作用?
16.apply和call的用法和区别?
17.前端开发的优化问题?
(1) 减少http请求次数:css spirit,data uri
(2) JS,CSS源码压缩
(3) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
(4) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能
(5) 用setTimeout来避免页面失去响应
(6) 用hash-table来优化查找
(7) 当需要设置的样式很多时设置className而不是直接操作style
(8) 少用全局变量
(9) 缓存DOM节点查找的结果
(10) 避免使用CSS Expression
(11) 图片预载
(12) 避免在页面的主体布局中使用table,table要等其中的内容完全下载之后才会显示出来,显示比div+css布局慢
18.javascript中的this是什么,有什么用,指向上面?
19.使用模块化加载时,模块记载的顺序是怎么样的,如果不知道,根据已有的知识,加载顺序是怎么样的
20.请用js去除字符串空格?
方法一:使用replace正则匹配的方法
去除所有空格: str = str.replace(/\s*/g,"");
去除两头空格: str = str.replace(/^\s*|\s*$/g,"");
去除左空格: str = str.replace( /^\s*/, “”);
去除右空格: str = str.replace(/(\s*$)/g, "");
str为要去除空格的字符串,实例如下:
var str = " 23 23 ";
var str2 = str.replace(/\s*/g,"");
console.log(str2); // 2323
方法二:使用str.trim()方法
str.trim()局限性:无法去除中间的空格,实例如下:
var str = " xiao ming ";
var str2 = str.trim();
console.log(str2); //xiao ming
同理,str.trimLeft(),str.trimRight()分别用于去除字符串左右空格。
方法三:使用jquery,$.trim(str)方法
$.trim(str)局限性:无法去除中间的空格,实例如下:
var str = " xiao ming ";
var str2 = $.trim(str)
console.log(str2); // xiao ming
使用正则表达式验证邮箱格式:
var reg = /^(\w)+(\.\w+)*@(\w)+((\.\w{2,3}){1,3})$/; var email = "[email protected]"; console.log(reg.test(email)); // true
21.jquery中$.get()提交和$.post()提交有区别吗?
相同点:都是异步请求的方式来获取服务端的数据;
异同点:
1、请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。
2、参数传递方式不同:get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。
3、数据传输大小不同:get方式传输的数据大小不能超过2KB 而POST要大的多
4、安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。
三、网络&存储&优化性能
1.http请求?
一次完整的HTTP请求所经历的7个步骤:
建立TCP连接->发送请求行->发送请求头->(到达服务器)发送状态行->发送响应头->发送响应数据->断TCP连接
2.websocket和ajax轮询
优点:只要建立一次连接,就可以连续不断的得到服务器推送消息,节省带宽和服务器端的压力。
缺点:每次都要建立HTTP连接,即使需要传输的数据非常少,浪费带宽
3.请描述一下 cookies sessionStorage和localstorage区别
相同点:都存储在客户端
不同点:1)存储大小
· cookie数据大小不能超过4k。
· sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
2)有效时间
· localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
· sessionStorage 数据在当前浏览器窗口关闭后自动删除。
· cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
3)数据与服务器之间的交互方式
· cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端
· sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
4.计算机网络的分层概述
5.HTTP和HTTPS
6.浏览器是如何渲染页面的?
1.解析HTML文件,创建DOM树。
自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。
2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式
3.将CSS与DOM合并,构建渲染树(Render Tree)
4.布局和绘制,重绘(repaint)和重排(reflow)
四、es6
1.ES6新特性
1) 箭头操作符 inputs=>outputs: 操作符左边是输入的参数,而右边则是进行的操作以及返回的值
2) 支持类, 引入了class关键字. ES6提供的类实际上就是JS原型模式的包装
3) 增强的对象字面量.
1. 可以在对象字面量中定义原型 __proto__: xxx //设置其原型为xxx,相当于继承xxx
2. 定义方法可以不用function关键字
3. 直接调用父类方法
4) 字符串模板: ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。
5) 自动解析数组或对象中的值。比如若一个函数要返回多个值,常规的做法是返回一个对象,将每个值做为这个对象的属性返回。但在ES6中,利用解构这一特性,可以直接返回一个数组,然后数组中的值会自动被解析到对应接收该值的变量中。
6) 默认参数值: 现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了。
7) 不定参数是在函数中使用命名参数同时接收不定数量的未命名参数。在以前的JavaScript代码中我们可以通过arguments变量来达到这一目的。不定参数的格式是三个句点后跟代表所有不定参数的变量名。比如下面这个例子中,…x代表了所有传入add函数的参数。
8) 拓展参数则是另一种形式的语法糖,它允许传递数组或者类数组直接做为函数的参数而不用通过apply。
9) let和const关键字: 可以把let看成var,只是它定义的变量被限定在了特定范围内才能使用,而离开这个范围则无效。const则很直观,用来定义常量,即无法被更改值的变量。
10) for of值遍历 每次循环它提供的不是序号而是值。
11) iterator, generator
12) 模块
13) Map, Set, WeakMap, WeakSet
14) Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。一下子让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处。
15) Symbols Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。之后就可以用这个返回值做为对象的键了。Symbol还可以用来创建私有属性,外部无法直接访问由symbol做为键的属性值。
16) Math, Number, String, Object的新API
17) Promises是处理异步操作的一种模式
五、js算法
1.js随机生成10000个,长度为8 位的数字号码,找出所有靓号(AAAA,AABB,ABAB,并且后四位不含4 )
2. 写一个原型链继承的例子
//DOM封装查询
function Elem(id){
this.elem = document.getElementById(id);
}
Elem.prototype.html = function(val){
var elem = this.elem;
if(val){
elem.innerHTML = val;
return this;
}else{
return elem.innerHTML;
}
}
Elem.prototype.on = function (type,fn){
var elem = this.elem;
elem.addEventListener(type,fn);
return this;
}
var div1 = new Elem('div1');
div1.html('hello world
').on('click',function(){
alert('clicked');
}).html('hello javascript
');
3.用js创建10个标签,点击的时候弹出来对应的序号
var i;
for(i=0;i<10;i++){
(function(i){
var a = document.createElement('a');
a.innerHTML = i + '
';
a.addEventListener('click',function(e){
e.preventDefault();
alert(i);
});
document.body.appendChild(a);
})(i);
}
4.获取2018-4-26格式的日期
function formatDate(dt){
if(!dt){
dt = new Date();
}
var year = dt.getFullYear();
var month = dt.getMonth() + 1;
var date = dt.getDate();
if(month<10){
month = '0' + month;
}
if(date<10){
date = '0' +date;
}
return year + '-' + month + '-' + date;
}
var dt = new Date();
var formatDate = formatDate(dt);
console.log(formatDate);
5.写一个能遍历对象和数组的通用的forEach函数
function forEach(obj,fn){
var key;
if(obj instanceof Array){
obj.forEach(function(item,index){
fn(index,item);
});
}else{
for(key in obj){
fn(key,obj[key]);
}
}
}
var arr = [1,2,3];//数组
forEach(arr,function(index,item){
console.log(index,item);
})
var obj = {x:1,y:2};//对象
forEach(obj,function(key,val){
console.log(key,val);
})
6.冒泡排序
function bubbleSort(arr) {
for(let i = 0,l=arr.length;iarr[j]) {
let tem = arr[i];
arr[i] = arr[j];
arr[j] = tem;
}
}
}
return arr;
}
module.exports = bubbleSort;
//es6写法
let arr = [43, 32, 1, 5, 9, 22];
const sort = arr => {
let res = []
arr.forEach((v, i) => {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
[arr[i],arr[j]] = [arr[j],arr[i]]
}
}
})
return arr
}
console.log(sort(arr)) // [1, 5, 9, 22, 32, 43]
7.字符串转驼峰
var str="border-bottom-color";
function Change(str){
var arr=str.split("-");
for(var i=1;i
8.查找字符串中出现次数最多的字符和次数
解决方法一:
var str = "sdddrtkjsfkkkasjdddj";
var max = 0;
var char;
function Search(str) {
var obj = {};
for (var i = 0; i < str.length; i++) {
if (!obj[str[i]]) {
obj[str[i]] = str[i];
} else {
obj[str[i]] += str[i];
}
}
for (var i = 0; i < str.length; i++) {
if (obj[str[i]].length > max) {
max = obj[str[i]].length;
char = str[i];
}
}
console.log("出现次数最多的字符是" + char + ",出现了" + max + "次")
}
Search(str);
解决方法二:
function repeatCharNum(str){
var arr = str.split('');
str = arr.sort().join('');
var re = /(\w)\1+/g;
var index = 0;
var value = '';
str.replace(re,function($0,$1){
if(index < $0.length){
index = $0.length;
value = $1 ;
}
});
alert ('最多字符'+value+'出现的次数'+index);
}
9.编写一个函数,将输入的参数中的数字字符追加为一个数字字符串,参数输入不确定
function getStrChange(){
var len = arguments.length;//参数不确定时使用arguments关键字
var re = /^\d+$/;
var str = '';debugger;
for(var i =0; i< len; i++){
if(!(re.test(arguments[i]))){
continue;
}
if(i == len-1){
str = str+arguments[i];
}else{
str = str+arguments[i]+',';
}
}
return str;
}
alert(getStrChange('1','a','45','b','3',1));//('1,45,3,1')
10.JS 把url的参数解析成对象
function parseUrl(str) {
// 判断是否传入参数
if (str) {
var obj = {};
var queryArr = [];
// 正则表达式规则
var re = /^(http\w?):\/\/([0-9a-zA-Z\.]+)([a-zA-Z0-9\/]+)\?([a-zA-Z0-9\=\&]+)#([0-9a-zA-Z\.]+)/;
// 利用正则表达式将字符串分组
var reArr = re.exec(str);
if (reArr) {
obj.peotocol = reArr[1];
obj.host = reArr[2];
obj.path = reArr[3];
queryArr = reArr[4].split(/[\&\=]+/);
obj.query = {};
for (var i = 0; i < queryArr.length; i += 2) {
obj.query[queryArr[i]] = queryArr[i + 1];
}
obj.hash = reArr[5]
return obj;
} else {
return null;
}
} else {
return null;
}
}
方法二:
// url参数解析
function getUrlkey(url) {
var params = {};
var urls = url.split("?"); console.log('1_分割url:', urls)
var arr = urls[1].split("&"); console.log('2_分割urls[1]:', arr)
for (var i = 0, l = arr.length; i < l; i++) {
var a = arr[i].split("="); console.log('3_遍历 arr 并分割后赋值给a:', a[0], a[1])
params[a[0]] = a[1]; console.log('4_a给params对象赋值:', params)
} console.log('5_结果:', params)
return params;
}
console.log(6,getUrlkey('http//aaa/txt.php?a=1&b=2&c=3'))
11.JS实现add(1)(2)(3)(4)的调用方式
第一种:
var add = function (m) {
var temp = function (n) {
return add(m + n);
}
temp.toString = function () {
return m;
}
return temp;
};
add(3)(4)(5); // 12
add(3)(6)(9)(25); // 43
这个add函数可以无限次调用循环调用,并且把所有传进去的值相加,最后返回相加总数。这道题咋一看有点特别,但代码量极其少而精,重点技术在于:作用域、交替、匿名函数、toString的巧妙。
让我们来解释这个过程:add(3)(4)(5)
1、先执行add(3),此时m=3,并且返回temp函数;
2、执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数
3、执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数
4、关键性一步来了,后面没有传入参数,等于返回的temp函数不被执行而是打印,了解JS的朋友都知道对象的toString是修改对象转换字符串的方法,因此代码中temp函数的toString函数return m值,而m值是最后一步执行函数时的值m=12,所以返回值是12。
看到这其实就很明白了,代码中temp.toString的重写只是为了函数不执行时能够返回最后运算的结果值,所以这个地方是可以任意修改的,你让它返回什么它就返回什么,比如改写:
temp.toString = function () {
return “total : ” + m;
}
执行结果:add(3)(4)(5); //total : 12
第二种:
function add(x) {
var sum = x;
var tmp = function (y) {
sum = sum + y;
return tmp;
};
tmp.toString = function () {
return sum;
};
return tmp;
}
console.log(add(1)(2)(3)); //6
console.log(add(1)(2)(3)(4)); //10
首先要一个数记住每次的计算值,所以使用了闭包,在tmp中记住了x的值,第一次调用add(),初始化了tmp,并将x保存在tmp的作用链中,然后返回tmp保证了第二次调用的是tmp函数,后面的计算都是在调用tmp, 因为tmp也是返回的自己,保证了第二次之后的调用也是调用tmp,而在tmp中将传入的参数与保存在作用链中x相加并付给sum,这样就保证了计算;
但是在计算完成后还是返回了tmp这个函数,这样就获取不到计算的结果了,我们需要的结果是一个计算的数字那么怎么办呢,首先要知道JavaScript中,打印和相加计算,会分别调用toString或valueOf函数,所以我们重写tmp的toString和valueOf方法,返回sum的值。