一些你不知道的js特性【一】
关于js
我们知道完整的js包括三个方面ECMAScript、DOM(文档对象模型)、BOM(浏览器对象模型)。
ECMAScript定义了与宿主无关的预言基础,比如:语法(包含正则语法)、类型、语句、关键字、保留字、操作符、对象
DOM是针对HTML(基于XML但经过拓展)的api。主成部分主要有DOM Core(映射基于XML的文档结构)、DOM HTML(拓展DOM Core,增加的针对HTML的对象和方法)、DOM视图(跟踪不同文档视图的接口)、DOM事件、DOM样式(基于css为元素应用样式的接口)、DOM遍历和范围、DOM加载和保存、DOM验证等
BOM是访问和操作浏览器窗口的api。一般来说针对浏览器的js拓展都算是BOM的一部分,比如:弹出新窗口的功能、关闭窗口功能、访问浏览器属性等。比较典型的就是window对象、navigator对象、location对象。其中window对象比较特殊,他及时BOM的核心,也是js的全局对象。
关于变量
1.不推荐修改变量所保存值的类型
2.使用操作符var定义的变量是该变量作用域下的局部变量。而不使用var定义的变量是全局变量。如
function a(){
var t = 1;
}
function b(){
m = 2;
}
a();
alert(t);//报错
b();
alert(m)//
但是推荐使用var或es6语法let/const定义变量,且局部作用域中定义全局变量很难维护。
3.非对象的变量比较使用"===",这样比较不会去转换。使用"=="比较,如果其中有字符串、数字的比较可能涉及到转换成数字或字符串。
4.undefined表示变量未赋值,null表示是一个空对象指针。使用"=="比较两者会是true,undefined派生至null,比较的时候会转换起操作数。给将来要保存对象的变量赋值null是一种好的实践,也进一步区分null和undefined。
5.在进行算数计算时,所有的八进制和十六进制都转换成十进制计算,结果也是十进制。
6.es5中没有块级的作用域,如
if(1){
var tt = 1;
}
alert(tt);//
es6新增了块级作用域,使用let/const定义。
7.某个作用域下的直接变量(包括函数和普通变量)都会在解析该作用域时首先声明,如
function m(){alert(a); var a = 2;}
m();//“undefind”,变量a在函数m解析时最开始就声明(不过赋值需要按代码顺序执行到相应位置才赋值)
function s(){alert(a); if(1){var a = 2;}}
s();//“undefined”,参考第6项。
function n(){alert(b);}
n();//浏览器报错,变量b没有声明
8.强烈建议不要实例化数据类型,特别是基本类型对应的对象实例;
var t = new Number('1');//不推荐使用
typeof t;//"object"
var m = Number('1');//推荐使用
typeof m;//"number"
var q = 1;//如果能直接定义变量值,就没必要使用Number多此一举了
typeof q;//"number"
NaN
任何有NaN参与的计算结果是NaN;NaN与任何值都不相等,包括他自己。
valueOf和toString
JS数据类型都拥有valueOf和toString这两个方法.
valueOf用于返回指定对象的原始值。对于number/string/boolean/object/array/function不用说,就是返回其本身。date类型会返回其毫秒时间数值。
toString将指定元素转换成字符串。但是其中Date/Array/Object/Function有些不同。
var num = 1,
str = 'chua',
bol = true,
fun = function(){alert(1)},
//und = undefined,nul = null,//这两个没有toString和valueOf属性
obj = {},
arr = [1,2,3],
dat = new Date(); dat.toString();//"Thu Jul 21 2016 20:37:34 GMT+0800 (中国标准时间)"
arr.toString();//"1,2,3"
obj.toString();//"[object Object]"
fun.toString();//"function (){alert(1)}"
bol.toString();//"true"
当然其中有些不一样的对象,比如 new Number(1);new String(1);new Boolean(1),这些特殊的对象使用toString得到的结果会和1/'1'/true使用toString的结果相同
运算符+和运算符-
需要特别注意的是:数字与字符串相加时数字会转换成字符串相加;数字与字符串相减时,字符串会转换成数字再相减;
比较运算符
比较运算符比较字符串时比较两个字符串对应位置的字符所对应的编码大小。所以大写字母始终是小于任何一个小写字母。
所以要想得到我们想要的结果("B" > "a")那么需要将两者都转化为小写形式。
而且注意"123" > "23"结果是false,因为这两个都是字符串,比较对应位置的字符就得到这样的结果。如果有任何一个是数字那就不会出现问题
"a" < 3返回false,因为"a"转换成了NaN;"a" >= 3也返回false
"=="比较会转换类型,"==="不会转换类型。对象比较"=="需要是引用同一个对象才会返回true
关于delete
现代浏览器(IE9+)全局变量不能删除,全局属性可以删除
关于页面加载渲染过程
无论是css还是js都是并行下载的,我们看chrome的network时间就能明白(时间重叠)
资料:网页加载历程详解http://www.educity.cn/wenda/143254.html
获取iframe的window对象
<body>
<iframe id="frame1" name="frame2" class="frame1" frameborder="0" scrolling="no" width="500px" height="500px" src="v_components.html"></iframe>
<iframe id="frame2" name="frame3" class="frame2" frameborder="0" scrolling="no" width="400px" height="400px" src="v_components.html"></iframe>
</body>
1.通过css查询节点: $('#frame1')[0].contentWindow;$('#frame2')[0].contentWindow;
2.通过window.frames[0]
网页的锚部分location.hash
hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。
#代表网页中的一个位置,比如
http://www.cnblogs.com/chuaWeb/p/gulp.html#!comments
就代表网页的!comments位置。浏览器读取这个URL后,会自动滚动到标签的name="!comments"或id="!comments"的位置。
单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页。如
http://www.cnblogs.com/chuaWeb/p/gulp.html#blog-comments-placeholder
//修改
http://www.cnblogs.com/chuaWeb/p/gulp.html#!comments
更改url的属性如location.(href/hash/search/host/hostname/port/pathname)都会根据新值来改变url
改变#会改变浏览器的访问历史
Google还规定,如果你希望Ajax生成的内容被浏览引擎读取,那么URL中可以使用"#!",Google会自动将其后面的内容转成查询字符串_escaped_fragment_的值。
比如,Google发现新版twitter的URL如下:
http://twitter.com/#!/username
等价于
http://twitter.com/?_escaped_fragment_=/username
通过这种机制,Google就可以索引动态的Ajax内容。
location.replace(url)方法会替换当前的url,但是不会产生浏览记录(用户不能回到前一个页面了)
setTimeout/setInterval
请不要给这两个函数的第一个参数传递字符串,这样会导致性能损失,传递函数最好。
延时调用的代码都是在全局作用域下执行的,因此函数中的this在非严格模式下指的是window,在严格模式下是undefined。
使用延时调用来模拟间歇调用(setInterval)是一种最佳方式.因为在前一个间歇调用排队调用的时候(因为前面有一个需要消耗大量时间的计算还没有执行完)后一个间歇调用也进入调用排队了,结果就是两个间歇调用连续执行。
alert/comfirm/prompt
浏览器对话框都是同步执行的,也就是说弹出对话框的时候代码会停止执行,关闭对话框后代码会恢复执行。
innerHTML
innerHTML中插入script节点是不会执行的(IE8-是唯一能运行里面脚本的浏览器,且必须满足必须为<script>元素指定defer 属性,并且<script>元素必须位于(微软所谓的)“有作用域的元素”(scoped element)之后。)
document.getElementById('form').innerHTML = '<script defer="defer"
>alert(1)</script>';
innerHTML中插入style节点在IE9+浏览其中会起作用但是在IE8-中不起作用
label
label语句可以在代码中添加标签,以便将来使用。通常都与for一起使用用来跳出多层循环(警告:尽量避免过多的循环层)
var num = 0;
start: for (var i = 0 ; i < 10 ; i++){
for (var j = 0 ; j < 10 ; j++){
if( i == 5 && j == 5 ){
break start;
}
num++;
}
}
alert(num); // 循环在 i 为5,j 为5的时候跳出双循环,返回到outPoint层继续执行,输出 55
switch【避免使用,参考严格模式】
相比其他语言他要灵活很多,case后面可以是表达式,只要这个表达式的值能和switch中传递的值全等就会进入这个分支
var num = 25;
switch(true){
case num == '25':
alert(0);
break;
case num < 25:
alert(1);
break;
detault:
alert(2);
}
很明显,ture和num == '25'值全等,所以弹出“0”
arguments
函数中可以通过arguments获取参数,可以修改arguments中的值(会同步到对应的传参)
function a(tt,mm){arguments[1] = 10;alert(mm)}
a(1);//'undefined',因为根本就没有传递第二个参数
a(1,2);//10,第二个参数被修改,同步mm
js中的参数都是值传递,不可能引用传值的情况。对象可以看做一个引用类型,同一个对象只有一份数据空间,如果传递对象的话,在函数内部修改对象实际就改变了这个唯一的一份数据空间
var a = {name: 'chua'}
function tt(b){
b.name = 'yyqing';
alert(a.name);
}
tt(a);//'yyqing',对象a只有一份空间,函数tt中b和a指向同一份空间
function a(){};
a.tname = 'chua';
function tt(c){
c.tname = 'yyqing';
alert(a.tname);
}
tt(a);//'yyqing',对象a只有一份空间,函数tt中b和a指向同一份空间
arguments.callee和function.caller【避免使用,参考严格模式】
function a(){
alert(arguments.callee);
}
a();/*function a(){
alert(arguments.callee);
}*/
function a(){
b();
}
function b(){
alert(b.caller);
}
a();/*function a(){
b();
}
*/
Array
数组的length属性并非只读属性,可以为length属性赋值以添加或减少数组的长度。
数组的sort方法排序,接收一个比较函数,如果使第一项在第二项前面,则返回负数;使第一项在第二项后面,则返回正数;
var tar = [1,8,2,4,10];
function compare(v1,v2){
if(v1 < v2){
return -1;
}else if(v1 > v2){
return 1;
}else{
return 0;
}
}
tar.sort(compare); //[1, 2, 4, 8, 10]
concat方法
var cor = [1,2,3];
cor.concat(4,[5,6]);//[1, 2, 3, 4, 5, 6]
cor.concat(4,[[5,6]]);//[1, 2, 3, 4, Array[2]]
数组的5个遍历方法every/filter/forEach/map/some
数组的reduce和reduceRight迭代所有的项,然后构建一个最终返回值
this
最外层this是window对象,函数作用域中this是调用这个函数的那个对象(或者说作用域)
var t = 1;
function a(){
this.m = 2;
alert(this.t);
}
a();//
alert(m);//2;
如上,函数a属于window,所以a中的this指的是window对象。
var v = {
o: function(){
this.p = 2;
alert(this.p);
}
}
v.o();//
alert(v.p);//
上面这个例子中o函数中的this指的是v对象。
箭头函数中this指向函数定义时的this。
Function.prototype.bind
作用是创建一个函数实例,并将参数作为这个实例的this使用。
function a(){
alert(this.b);
}
var t = {b:1};
var c = a.bind(t);
c();
这个比使用self等保存this更加专业
var myObj = {
tname: 'chua',
getAsyncData: function(fn){
fn();
},
render: function () {
var self = this;
this.getAsyncData(function () {
console.log(self.tname);
});
}
}; myObj.render();//'chua'
可以改成
var myObj = {
tname: 'chua',
getAsyncData: function(fn){
fn();
},
render: function () {
this.getAsyncData(function () {
console.log(this.tname);
}.bind(this));
}
}; myObj.render();//'chua'
但是需要注意的是,IE9+才支持该方法。
文件下载
正常情况下使用
<a href='xxx.png'>download</a>
点击标签正常情况下是展示该图片,而非弹出下载提示。可以通过后台设置协议头Content-Disposition属性为attachment来强制资源作为附件下载。
读取和设置文本域光标位置
/**
* 获得光标位置兼容IE/FF
*
例:
var obj = document.getElementById("tx1");
var pos = getCaretPosition(obj);
alert("--"+pos);
*/
function getCaretPosition(obj) {
var result = 0;
if (obj.selectionStart) { //IE以外
result = obj.selectionStart;
} else { //IE
try{
var rng;
if (obj.tagName == "textarea") { //TEXTAREA
rng = event.srcElement.createTextRange();
rng.moveToPoint(event.x, event.y);
} else { //Text
rng = document.selection.createRange();
}
rng.moveStart("character", -event.srcElement.value.length);
result = rng.text.length;
}catch (e){
throw new Error(10,"asdasdasd")
}
}
return result;
}
/**
* 设置光标位置兼容IE/FF
* @param tObj
* @param sPos
*
例:
var obj =document.getElementById("tx1");
var sPos = obj.value.length-1;
setCaretPosition(obj, sPos);
*/
function setCaretPosition(tObj, sPos){
if(tObj && sPos){
if(tObj.setSelectionRange){
setTimeout(function(){
tObj.setSelectionRange(sPos, sPos);
tObj.focus();
}, 0);
}else if(tObj.createTextRange){
var rng = tObj.createTextRange();
rng.move('character', sPos);
rng.select();
}
}
}
JSON
JSON对象中属性是函数的会被忽略情况,比如
var obj = {
fn: function(){},
name: 'chua'
};
JSON.stringify(obj);//"{"name":"chua"}"
=======================================================
后记:
2019.12.20 笔记大部分是很久很久之前整理的,主要涉及es5,es6的后续开篇
如果觉得本文不错,请点击右下方【推荐】!
一些你不知道的js特性【一】的更多相关文章
- 翻译连载 | 附录 B: 谦虚的 Monad-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 你不知道的JS之作用域和闭包 附录
原文:你不知道的js系列 A 动态作用域 动态作用域 是和 JavaScript中的词法作用域 对立的概念. 动态作用域和 JavaScript 中的另外一个机制 (this)很相似. 词法作用域是 ...
- 你不知道的JS之作用域和闭包(五)作用域闭包
原文:你不知道的js系列 一个简单粗暴的定义 闭包就是即使一个函数在它所在的词法作用域外部被执行,这个函数依然可以访问这个作用域. 比如: function foo() { var a = 2; fu ...
- 你不知道的JS之作用域和闭包(三)函数 vs. 块级作用域
原文:你不知道的js系列 在第(二)节中提到的,标识符在作用域中声明,这些作用域就像是一个容器,一个嵌套一个,这个嵌套关系是在代码编写时定义的. 那么到底是什么产生了一个新的作用域,只有函数能做到 ...
- 你不知道的JS之作用域和闭包(二)词法作用域
原文:你不知道的js系列 词法作用域(Lexical Scope) Lex time 一个标准的编译器的第一个阶段就是分词(token化) 词法作用域就是在词法分析时定义的作用域.换句话说,词法作用域 ...
- 翻译连载 | 第 9 章:递归(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 翻译连载 | 第 10 章:异步的函数式(上)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 翻译连载 | 第 10 章:异步的函数式(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 翻译连载 | 第 11 章:融会贯通 -《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
随机推荐
- MFC unicode字符集与多字节字符集 问题之彻底终结!
Unicode 和多字节字符集 (MBCS) 支持 Visual Studio .NET 2003 有些国际市场以大字符集来使用日文和中文等语言.为了支持这些市场的编程,Microsoft 基础类 ...
- Java实现数列的排列组合
定义: 排列:从给定个数的元素中取出指定个数的元素,进行排序 组合:从给定个数的元素中仅取出指定个数的元素,不考虑排序 公式: 从n个元素中取出m个元素进行排序的个数: A(m,n)=n(n-1)(n ...
- 【Redis】349- Redis 入门指南
点击上方"前端自习课"关注,学习起来~ 1. 概述 1.1. Redis 简介 Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的映 ...
- ruby 构建API接口流程代码
来源:https://ruby-china.org/topics/25822 1.创建新项目 rails new api_demo 2.生成控制器: # 我们不需要生成资源文件 $ bundle ex ...
- Linux内核构建过程
构建内核 # shell 执行如下指令make zImage 全局变量 srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))objtree ...
- NodeJS2-1环境&调试----CommonJS
CommonJS 每个文件是一个模块,有自己的作用域 在模块内部module变量代表模块本身 module.exports属性代表模块对外接口 require规则 /表示绝对路径,./表示型对于当前文 ...
- JS---DOM---part4 课程介绍 & part3 复习
part4 课程介绍 事件 1. 绑定事件的区别 2. 移除绑定事件的方式及区别和兼容代码 3. 事件的三个阶段 4. 事件冒泡 5. 为同一个元素绑定多个不同的事件,指向的是同一个事件处理函数 6. ...
- Neo4j安装过程详解
在安装neo4j之前,需要安装Java JRE,并配置Java开发环境,然后安装neo4j服务. 一.CentOS下安装 1.下载Neo4j 去官网下载最新的neo4j,选择社区版.地址:https: ...
- spark-3.0 application 调度算法解析
spark 各个版本的application 调度算法还是有这明显的不同之处的.从spark1.3.0 到 spark 1.6.1.spark2.0 到 现在最新的spark 3.0 ,调度算法有了一 ...
- JS reduce()方法详解,使用reduce数组去重
壹 ❀ 引 稍微有了解JavaScript数组API的同学,对于reduce方法至少有过一面之缘,也许是for与forEach太强大,或者filter,find很实用,在实际开发中我至始至终没使用过 ...