摘要:访问属性是通过操作符完成的,但这要求属性名必须是一个有效的变量名小红的属性名不是一个有效的变量,就需要用括起来。闭包应用封装私有变量箭头函数箭头函数相当于匿名函数,并且简化了函数定义。
数据类型
NAN
NaN === NaN; // false
唯一能判断NaN的方法是通过isNaN()函数:
isNaN(NaN); // true
浮点数的相等比较:
1 / 3 === (1 - 2 / 3); // false
这不是JavaScript的设计缺陷。浮点数在运算过程中会产生误差,因为计算机无法精确表示无限循环小数。要比较两个浮点数是否相等,只能计算它们之差的绝对值,看是否小于某个阈值:
Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001; // true
避免使用new Array(1, 2, 3); // 创建了数组[1, 2, 3]方式
字符串
需要特别注意的是,字符串是不可变的
如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果:
var s = "Test"; s[0] = "X"; alert(s); // s仍然为"Test"
JavaScript为字符串提供了一些常用方法,注意,调用这些方法本身不会改变原有字符串的内容,而是返回一个新字符串
数组大多数其他编程语言不允许直接改变数组的大小,越界访问索引会报错。然而,JavaScript的Array却不会有任何错误。在编写代码时,不建议直接修改Array的大小,访问索引时要确保索引不会越界。
对原数组进行操作的方法和返回新数组的方法
原数组:
pop/push,unshift/shift
sort
reverse
splice
新数组:
slice
concat
join返回的是新的字符串
扩展:数组扁平化的几种方法
var myArray = [[1, 2],[3, 4, 5], [6, 7, 8, 9]];
使用concat()和apply()
var myNewArray = [].concat.apply([], myArray); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
使用reduce()
var myNewArray = myArray.reduce(function(prev, curr) { return prev.concat(curr); }); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
MSDN reduce 方法
使用 ES6 的展开运算符
var myNewArray4 = [].concat(...myArray); console.log(myNewArray4); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
MDN 展开运算符
最后这个方法返回的是字符串
myArray.join(",") //"1,2,3,4,5,6,7,8,9"
请注意,for ... in对Array的循环得到的是String而不是Number
对象注意,最后一个键值对不需要在末尾加,,如果加了,有的浏览器(如低版本的IE)将报错。
访问属性是通过.操作符完成的,但这要求属性名必须是一个有效的变量名
var xiaohong = { name: "小红", "middle-school": "No.1 Middle School" };
xiaohong的属性名middle-school不是一个有效的变量,就需要用""括起来。访问这个属性也无法使用.操作符,必须用["xxx"]来访问:
xiaohong["middle-school"]; // "No.1 Middle School" xiaohong["name"]; // "小红" xiaohong.name; // "小红"
访问不存在的属性不报错,而是返回undefined
函数
小心你的return语句
如果把return语句拆成两行:
function foo() { return { name: "foo" }; } foo(); // undefined
要小心了,由于JavaScript引擎在行末自动添加分号的机制,上面的代码实际上变成了:
function foo() { return; // 自动添加了分号,相当于return undefined; { name: "foo" }; // 这行语句已经没法执行到了 }
所以正确的多行写法是:
function foo() { return { // 这里不会自动加分号,因为{表示语句尚未结束 name: "foo" }; }
变量提升
由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。
闭包应用:封装私有变量
function create_counter(initial) { var x = initial || 0; return { inc: function () { x += 1; return x; } } }
箭头函数
箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种只包含一个表达式,连{ ... }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }和return
返回对象:
// SyntaxError: x => { foo: x } // ok: x => ({ foo: x })
箭头函数完全修复了this的指向,箭头函数内部的this是词法作用域,由上下文确定
扩展:装饰器
现在假定我们想统计一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt():
var count = 0; var oldParseInt = parseInt; // 保存原函数 window.parseInt = function () { count += 1; return oldParseInt.apply(null, arguments); // 调用原函数 }; // 测试: parseInt("10"); parseInt("20"); parseInt("30"); count; // 3对象
需要遵守的规则
不要使用new Number()、new Boolean()、new String()创建包装对象;
用parseInt()或parseFloat()来转换任意类型到number;
用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...};
typeof操作符可以判断出number、boolean、string、function和undefined;
判断Array要使用Array.isArray(arr);
判断null请使用myVar === null;
判断某个全局变量是否存在用typeof window.myVar === "undefined";
函数内部判断某个变量是否存在用typeof myVar === "undefined"。
获取时间戳
if (Date.now) { alert(Date.now()); // 老版本IE没有now()方法 } else { alert(new Date().getTime()); }
JSON.stringify()
格式化
var xiaoming = { name: "小明", age: 14, gender: true, height: 1.65, grade: null, "middle-school": ""W3C" Middle School", skills: ["JavaScript", "Java", "Python", "Lisp"] }; undefined JSON.stringify(xiaoming, null, " "); "{ "name": "小明", "age": 14, "gender": true, "height": 1.65, "grade": null, "middle-school": ""W3C" Middle School", "skills": [ "JavaScript", "Java", "Python", "Lisp" ] }"
筛选数据
第二个参数用于控制如何筛选对象的键值,如果我们只想输出指定的属性,可以传入Array:
JSON.stringify(xiaoming, ["name", "height"], " ");
"{ "name": "小明", "height": 1.65 }"
也可以传入函数进行处理
浏览器
获取UA
function whatBrowser() { document.Browser.Name.value=navigator.appName; document.Browser.Version.value=navigator.appVersion; document.Browser.Code.value=navigator.appCodeName; document.Browser.Agent.value=navigator.userAgent; }
请注意,navigator的信息可以很容易地被用户修改,所以JavaScript读取的值不一定是正确的
cookie安全问题
由于JavaScript能读取到页面的Cookie,而用户的登录信息通常也存在Cookie中,这就造成了巨大的安全 隐患。为了解决这个问题,服务器在设置Cookie时可以使用httpOnly,设定了httpOnly的Cookie将不能被JavaScript读取。这个行为由浏览器实现,主流浏览器均支持httpOnly选项,IE从IE6 SP1开始支持。
为了确保安全,服务器端在设置Cookie时,应该始终坚持使用httpOnly。
按字符串顺序重新排序DOM节点
- Scheme
- JavaScript
- Python
- Ruby
- Haskell
var ol = document.getElementById("test-list"), lis = [].slice.call(ol.children); lis.sort((a,b)=> a.innerText.toUpperCase() > b.innerText.toUpperCase()); lis.forEach(x=>{ol.appendChild(x)})
children属性时刻都在变化
当你遍历一个父节点的子节点并进行删除操作时,要注意,children属性是一个只读属性,并且它在子节点变化时会实时更新。
例如,对于如下HTML结构:
First
Second
当我们用如下代码删除子节点时:
var parent = document.getElementById("parent"); parent.removeChild(parent.children[0]); parent.removeChild(parent.children[1]); // <-- 浏览器报错
浏览器报错:parent.children[1]不是一个有效的节点。原因就在于,当
First
节点被删除后,parent.children的节点数量已经从2变为了1,索引[1]已经不存在了。
扩展练习
把与Web开发技术不相关的节点删掉
var parent = document.getElementById("test-list"); var children = [].slice.call(parent.children); //Array.prototype.slice.call() children.forEach((element) => { for(var s of ["Swift", "ANSI C", "DirectX"]){ if(element.innerText == s){ parent.removeChild(element); } } });事件
需要特别注意的是,下面这种写法是无效的:
// 绑定事件: a.click(function () { alert("hello!"); }); // 解除绑定: a.off("click", function () { alert("hello!"); });
这是因为两个匿名函数虽然长得一模一样,但是它们是两个不同的函数对象,off("click", function () {...})无法移除已绑定的第一个匿名函数。
为了实现移除效果,可以使用off("click")一次性移除已绑定的click事件的所有处理函数。
同理,无参数调用off()一次性移除已绑定的所有类型的事件处理函数。
事件触发条件
一个需要注意的问题是,事件的触发总是由用户操作引发的,但是,如果用JavaScript代码去改动,将不会触发change事件
有些时候,我们希望用代码触发change事件,可以直接调用无参数的change()方法来触发该事件
var input = $("#test-input"); input.val("change it!"); input.change(); // 触发change事件
input.change()相当于input.trigger("change"),它是trigger()方法的简写。
浏览器安全限制
在浏览器中,有些JavaScript代码只有在用户触发下才能执行,例如,window.open()函数:
// 无法弹出新窗口,将被浏览器屏蔽: $(function () { window.open("/"); });
这些“敏感代码”只能由用户操作来触发:
var button1 = $("#testPopupButton1"); var button2 = $("#testPopupButton2"); function popupTestWindow() { window.open("/"); } button1.click(function () { popupTestWindow(); }); button2.click(function () { // 不立刻执行popupTestWindow(),100毫秒后执行: setTimeout(popupTestWindow, 100); });
当用户点击button1时,click事件被触发,由于popupTestWindow()在click事件处理函数内执行,这是浏览器允许的,而button2的click事件并未立刻执行popupTestWindow(),延迟执行的popupTestWindow()将被浏览器拦截。
Ajaxopen方法的第三个参数
千万不要把第三个参数指定为false,否则浏览器将停止响应,直到AJAX请求完成。
跨域方案
flash插件,现在用的很少
代理服务器,需要服务器端做额外开发
jsonp,只支持get请求
cors,通过http头的Access-Control-Allow-Origin验证
编写jquery插件原则给$.fn绑定函数,实现插件的代码逻辑;
插件函数最后要return this;以支持链式调用;
插件函数要有默认值,绑定在$.fn.
用户在调用时可传入设定值以便覆盖默认值。
扩展jQuery对象的功能十分简单,但是我们要遵循jQuery的原则,编写的扩展方法能支持链式调用、具备默认值和过滤特定元素,使得扩展方法看上去和jQuery本身的方法没有什么区别。
此篇跳过了js中的面向对象,高阶函数,正则,原型等难点,下篇等我好好研究一下继续
参考资料 Javascript多维数组扁平化
廖雪峰老师的js教程
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/80603.html
摘要:巅峰人生年老兵思路上的转变,远比单纯提升技术更有价值本文节选自赵成教授在极客时间开设的赵成的运维体系管理课,是其对自己十年技术生涯的回顾与总结。赵成教授来自美丽联合集团,集团旗下两大主力产品是蘑菇街和美丽说,目前负责管理集团的技术服务团队。 showImg(https://segmentfault.com/img/remote/1460000012476504?w=1240&h=826...
摘要:应该非常小心,避免出现不使用命令直接调用构造函数的情况。上面代码表示,使用属性,确定实例对象的构造函数是,而不是。当然,从继承链来看,只有一个父类,但是由于在的实例上,同时执行和的构造函数,所以它同时继承了这两个类的方法。 基本概念 类和实例是大多数面向对象编程语言的基本概念 类:类是对象的类型模板 实例:实例是根据类创建的对象但是,JavaScript语言的对象体系,不是基于类的,...
摘要:原文发布在数组应该是日常开发中最常见的数据结构了,虽然常见,但是却不一定能优雅地处理好,中数组的处理方法很多,各个方法的参数返回值是否修改原数组等也容易记混。 原文发布在:http://blog.xiaofeixu.cn/2017... 数组应该是日常开发中最常见的数据结构了,虽然常见,但是却不一定能优雅地处理好,JavaScript中数组的处理方法很多,各个方法的参数、返回值、是否修...
摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...
阅读 935·2021-11-22 09:34
阅读 2146·2021-11-11 16:54
阅读 2174·2021-09-27 14:00
阅读 921·2019-08-30 15:55
阅读 1508·2019-08-29 12:46
阅读 579·2019-08-26 18:42
阅读 614·2019-08-26 13:31
阅读 3165·2019-08-26 11:52