JS日常随笔

1.querySelector()和querySelectorAll()
例:// 通过querySelector获取ID为q1的节点:
var q1 = document.querySelector('#q1');
// 通过querySelectorAll获取q1节点内的符合条件的所有节点:
var ps = q1.querySelectorAll('div.highlighted > p');
注意:低版本的IE<8不支持querySelector和querySelectorAll。IE8仅有限支持。
例题1:
<!-- HTML结构 -->
<div id="test-div">
<div class="c-red">
    <p id="test-p">JavaScript</p>
    <p>Java</p>
  </div>
  <div class="c-red c-green">
    <p>Python</p>
    <p>Ruby</p>
    <p>Swift</p>
  </div>
  <div class="c-green">
    <p>Scheme</p>
    <p>Haskell</p>
  </div>
</div>
请选择出指定条件的节点:
// 选择<p>JavaScript</p>:
    console.log(document.getElementById("test-p"));
    console.log(document.getElementById("test-div").childNodes[1].childNodes[1]);
    console.log(document.getElementById("test-div").children[0].children[0]);
    console.log(document.querySelector("#test-div").children[0].children[0]);
    console.log(document.querySelector(".c-red").children[0]);
    console.log(document.querySelector(".c-red").childNodes[1]);
    console.log(document.querySelector("#test-p"));
    console.log(document.getElementsByTagName("div").item(1).children[0]);
    console.log(document.getElementsByClassName("c-red").item(0).children[0]);
    console.log(document.querySelectorAll("#test-p").item(0));
    console.log("选择<p>JavaScript</p>")


// 选择<p>Python</p>,<p>Ruby</p>,<p>Swift</p>:
    //Class查找
    var doc = document.getElementsByClassName("c-red c-green").item(0).children;
    for (let i = 0; i < doc.length; i++) {
        console.log(doc[i]);
    }
    //Select查找
    var arr = document.querySelector('.c-red.c-green');
    for (let i = 0; i < arr.children.length; i++) {
        console.log(arr.children[i]);
    }
    //SelectAll查找
    var docAll=document.querySelectorAll(".c-red.c-green").item(0).children;
    for (let i = 0; i < docAll.length; i++) {
        console.log(docAll[i]);
    }


// 选择<p>Haskell</p>:
    console.log(document.getElementsByClassName("c-green")[1].lastElementChild);
    //querySelector会查找到class="c-red c-green"
    console.log(document.querySelectorAll(".c-green").item(1).children[1]);
    console.log("选择<p>Haskell</p>");

例题2:
<!-- HTML结构 -->
<div id="test-div">
  <p id="test-js">javascript</p>
  <p>Java</p>
</div>
请尝试获取指定节点并修改:
// 获取<p>javascript</p>节点:
var js = document.getElementById('test-js');


// 修改文本为JavaScript:
js.innerText = 'JavaScript'


// 修改CSS为: color: #ff0000, font-weight: bold
js.style.color = '#ff0000'
js.style.fontWeight = 'bold'

例题3:
<!-- HTML结构 -->
<ol id="test-list">
    <li class="lang">Scheme</li>
    <li class="lang">JavaScript</li>
    <li class="lang">Python</li>
    <li class="lang">Ruby</li>
    <li class="lang">Haskell</li>
</ol>
按字符串顺序重新排序DOM节点:
// sort list:
var list=document.getElementById('test-list'),
arr=[];
for(let i = 0;i<list.children.length;i++)
{
arr.push(list.getElementsByClassName('lang')[i]);
}
arr.sort(function(x,y){return x.innerHTML>y.innerHTML;});
for(let i=0;i<arr.length;i++){
list.appendChild(arr[i]);
}

例题4:
<!-- HTML结构 -->
<ul id="test-list">
    <li>JavaScript</li>
    <li>Swift</li>
    <li>HTML</li>
    <li>ANSI C</li>
    <li>CSS</li>
    <li>DirectX</li>
</ul>
把与Web开发技术不相关的节点删掉:
var par=document.getElementById('test-list');
par.removeChild(par.children[1]);
par.removeChild(par.children[2]);
par.removeChild(par.children[3]);


要注意,children属性是一个只读属性,并且它在子节点变化时会实时更新
也就是说在删掉Swift时整个html结构变成:
<ul id="test-list">
    <li>JavaScript</li>
    <li>HTML</li>
    <li>ANSI C</li>
    <li>CSS</li>
    <li>DirectX</li>
</ul>
所以ANSI C变成了par.children[2]


例题5:
<!-- HTML结构 -->
<form id="test-register" action="#" target="_blank" οnsubmit="return checkRegisterForm()">
    <p id="test-error" style="color:red"></p>
    <p>
        用户名: <input type="text" id="username" name="username">
    </p>
    <p>
        口令: <input type="password" id="password" name="password">
    </p>
    <p>
        重复口令: <input type="password" id="password-2">
    </p>
    <p>
        <button type="submit">提交</button> <button type="reset">重置</button>
    </p>
</form>
利用JavaScript检查用户注册信息是否正确,在以下情况不满足时报错并阻止提交表单:
用户名必须是3-10位英文字母或数字;
口令必须是6-20位;
两次输入口令必须一致。
var checkRegisterForm = function () {
 var username = document.getElementById('username');
    var error = document.getElementById('test-error');
    if(!new RegExp(/\w{3,10}/).test(username.value)){
        error.innerText = 'error name';
        return false;
    }
    var pwd = document.getElementById('password');
    if(!new RegExp(/\S{6,20}/).test(pwd.value)){
       error.innerText = 'error pwd';
       return false;
    }
    var pwd2 = document.getElementById('password-2');
    if(pwd.value !== pwd2.value){
        error.innerText = 'error pwd2';
        return false;
    }
    return true;
}
2)Map和Set
Map:
举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array:
var names = ['Michael', 'Bob', 'Tracy'];
var scores = [95, 75, 85];
给定一个名字,要查找对应的成绩,就先要在names中找到对应的位置,再从scores取出对应的成绩,Array越长,耗时越长。
如果用Map实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。
用JavaScript写一个Map如下:
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95

初始化Map需要一个二维数组,或者直接初始化一个空Map。Map具有以下方法:
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined

由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:
var m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); // 88

Set:
Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:=
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3

重复元素在Set中自动被过滤:
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
注意:数字3和字符串'3'是不同的元素!


通过add(key)方法可以添加元素到Set中,可以重复添加,但不会有效果:
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, 4}

通过delete(key)方法可以删除元素:
var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}

3)for...of循环
用for ... of循环遍历集合,用法如下:
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
console.log(x);//ABC
}
for (var x of s) { // 遍历Set
console.log(x);//ABC
}
for (var x of m) { // 遍历Map
console.log(x[0] + '=' + x[1]);//1=X,2=Y,3=Z

forEach()方法:
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
console.log(element + ', index = ' + index);
});//A, index = 0
B, index = 1
C, index = 2
 
Set与Array类似,但Set没有索引,因此回调函数的前两个参数都是元素本身:
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
console.log(element);
});

Map的回调函数参数依次为value、key和map本身:
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
console.log(value);
});

如果对某些参数不感兴趣,由于JavaScript的函数调用不要求参数必须一致,因此可以忽略它们。例如,只需要获得Array的element:
var a = ['A', 'B', 'C'];
a.forEach(function (element) {
console.log(element);
});


4)定义函数
方法一:
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}

方法二:
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};

arguments参数:
其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中国每个函数都会有一个Arguments对象实例arguments,它引用着函数的实参,可以用数组下标的方式"[]"引用arguments的元素。
arguments.length为函数实参个数,arguments.callee引用函数自身。
arguments他的特性和使用方法
特性:
arguments对象和Function是分不开的。因为arguments这个对象不能显式创建,arguments对象只有函数开始时才可用。
使用方法:
虽然arguments对象并不是一个数组,但是访问单个参数的方式与访问数组元素的方式相同
例如:
arguments[0],arguments[1],。。。。。。。。arguments[n],
在js中 不需要明确指出参数名,就能访问它们,例如:
function test() {
var s = "";
for (var i = 0; i < arguments.length; i++) {
alert(arguments[i]);
s += arguments[i] + ",";
}
return s;
}
test("name", "age")
输出结果:
name,age
我们知道每一个对象都有自己的属性,arguments对象也不例外,首先arguments的访问犹如Array对象一样,
用0到arguments.length-1来枚举每一个元素。下面我们来看看callee属性,返回正被执行的 Function 对象,
也就是所指定的 Function 对象的正文。callee 属性是 arguments 对象的一个成员,仅当相关函数正在执行时才可用。
callee 属性的初始值就是正被执行的 Function 对象,这允许匿名的递归函数。
var sum = function (n) {
if (1 == n) {
return 1;
} else {
return n + arguments.callee(n - 1);
}
}
alert(sum(6));
通俗一点就是,arguments此对象大多用来针对同个方法多处调用并且传递参数个数不一样时进行使用。根据arguments的索引来判断执行的方法。
 
rest参数:
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}


foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]


foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
 
5)变量相关
function foo() {
var x = 'Hello, ' + y;
console.log(x);//Hello, undefined
var y = 'Bob';
}


foo();
虽然是strict模式,但语句var x = 'Hello, ' + y;并不报错,原因是变量y在稍后申明了。但是console.log显示Hello, undefined,说明变量y的值为undefined。
这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。
对于上述foo()函数,JavaScript引擎看到的代码相当于:
function foo() {
var y; // 提升变量y的申明,此时y为undefined
var x = 'Hello, ' + y;
console.log(x);
y = 'Bob';
}

JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:
var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'
因此,直接访问全局变量course和访问window.course是完全一样的。

6)箭头函数
// 两个参数:
(x, y) => x * x + y * y


// 无参数:
() => 3.14


// 可变参数:
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}
如果要返回一个对象:
x => ({ foo: x })

箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 28

注意:由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略!

7)js对象
typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'

包装对象:
number、boolean和string都有包装对象,包装对象用new创建
var n = new Number(123); // 123,生成了新的包装类型
var b = new Boolean(true); // true,生成了新的包装类型
var s = new String('str'); // 'str',生成了新的包装类型

虽然包装对象看上去和原来的值一模一样,显示出来也是一模一样,但他们的类型已经变为object了!所以,包装对象和原始值用===比较会返回false:
typeof new Number(123); // 'object'
new Number(123) === 123; // false


typeof new Boolean(true); // 'object'
new Boolean(true) === true; // false


typeof new String('str'); // 'object'
new String('str') === 'str'; // false
注意:尽量不要用包装对象!尤其是针对string类型!!!

如果我们在使用Number、Boolean和String时,没有写new会发生什么情况?
此时,Number()、Boolean和String()被当做普通函数,把任何类型的数据转换为number、boolean和string类型(注意不是其包装类型):
var n = Number('123'); // 123,相当于parseInt()或parseFloat()
typeof n; // 'number'


var b = Boolean('true'); // true
typeof b; // 'boolean'


var b2 = Boolean('false'); // true! 'false'字符串转换结果为true!因为它是非空字符串!
var b3 = Boolean(''); // false


var s = String(123.45); // '123.45'
typeof s; // 'string'

总结几点:
a.不要使用new Number()、new Boolean()、new String()创建包装对象;
b.用parseInt()或parseFloat()来转换任意类型到number;
c.用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
d.通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...};
e.typeof操作符可以判断出number、boolean、string、function和undefined;
f.判断Array要使用Array.isArray(arr);
g.判断null请使用myVar === null;
h.判断某个全局变量是否存在用typeof window.myVar === 'undefined';
i.函数内部判断某个变量是否存在用typeof myVar === 'undefined'。

当number对象调用toString()报SyntaxError时:
123.toString(); // SyntaxError
遇到这种情况,要特殊处理一下:
123..toString(); // '123', 注意是两个点!
(123).toString(); // '123'

8)Date对象
var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳

如果要创建一个指定日期和时间的Date对象,可以用:
var d = new Date(2015, 5, 19, 20, 15, 30, 123);
d; // Fri Jun 19 2015 20:15:30 GMT+0800 (CST)
注意:JavaScript的Date对象月份值从0开始,牢记0=1月,1=2月,2=3月,……,11=12月!!

第二种创建一个指定日期和时间的方法是解析一个符合ISO 8601格式的字符串:
var d = Date.parse('2015-06-24T19:49:22.875+08:00');
d; // 1435146562875
但它返回的不是Date对象,而是一个时间戳。不过有时间戳就可以很容易地把它转换为一个Date:
var d = new Date(1435146562875);
d; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
d.getMonth(); // 5
注意:使用Date.parse()时传入的字符串使用实际月份01~12,转换为Date对象后getMonth()获取的月份值为0~11!!

Date对象表示的时间总是按浏览器所在时区显示的,不过我们既可以显示本地时间,也可以显示调整后的UTC时间:
var d = new Date(1435146562875);
d.toLocaleString(); // '2015/6/24 下午7:49:22',本地时间(北京时区+8:00),显示的字符串与操作系统设定的格式有关
d.toUTCString(); // 'Wed, 24 Jun 2015 11:49:22 GMT',UTC时间,与本地时间相差8小时

9)RegExp对象
JavaScript有两种方式创建一个正则表达式:
第一种方式是直接通过/正则表达式/写出来,第二种方式是通过new RegExp('正则表达式')创建一个RegExp对象。
两种写法是一样的:
var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');
re1; // /ABC\-001/
re2; // /ABC\-001/
注意:如果使用第二种写法,因为字符串的转义问题,字符串的两个\\实际上是一个\!


先看看如何判断正则表达式是否匹配:
var re = /^\d{3}\-\d{3,8}$/;
re.test('010-12345'); // true
re.test('010-1234x'); // false
re.test('010 12345'); // false
RegExp对象的test()方法用于测试给定的字符串是否符合条件。

切分字符串:
用正则表达式切分字符串比用固定的字符更灵活,请看正常的切分代码:
'a b   c'.split(' '); // ['a', 'b', '', '', 'c']
嗯,无法识别连续的空格,用正则表达式试试:
'a b   c'.split(/\s+/); // ['a', 'b', 'c']
无论多少个空格都可以正常分割。加入,试试:
'a,b, c  d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
再加入;试试:
'a,b;; c  d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']

分组:
除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(Group)。比如:
^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:
var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
re.exec('010 12345'); // null
如果正则表达式中定义了组,就可以在RegExp对象上用exec()方法提取出子串来。
exec()方法在匹配成功后,会返回一个Array,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串。
exec()方法在匹配失败时返回null。

全局搜索:
JavaScript的正则表达式还有几个特殊的标志,最常用的是g,表示全局匹配:
var r1 = /test/g;
// 等价于:
var r2 = new RegExp('test', 'g');

全局匹配可以多次执行exec()方法来搜索一个匹配的字符串。当我们指定g标志后,每次运行exec(),正则表达式本身会更新lastIndex属性,表示上次匹配到的最后索引:
var s = 'JavaScript, VBScript, JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;
// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10


re.exec(s); // ['VBScript']
re.lastIndex; // 20


re.exec(s); // ['JScript']
re.lastIndex; // 29


re.exec(s); // ['ECMAScript']
re.lastIndex; // 44


re.exec(s); // null,直到结束仍没有匹配到

全局匹配类似搜索,因此不能使用/^...$/,那样只会最多匹配一次。
正则表达式还可以指定i标志,表示忽略大小写,m标志,表示执行多行匹配。

10)JSON
数据类型:
number:和JavaScript的number完全一致;
boolean:就是JavaScript的true或false;
string:就是JavaScript的string;
null:就是JavaScript的null;
array:就是JavaScript的Array表示方式——[];
object:就是JavaScript的{ ... }表示方式。
注意:JSON字符集必须是UTF-8,JSON的字符串规定必须用双引号"",Object的键也必须用双引号""!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值