简介
https://zhuanlan.zhihu.com/p/531318329
JavaScript 组成:核心(ECMAScript) + 文档对象模型(DOM) + 浏览器对象模型(BOM)
位于前端的核心,主要用来操控和重新调整DOM树,通过修改DOM结构 来达到修改页面效果的目的。
ECMAScript 规定了以下内容:
语法、类型、语句、关键字、保留字、操作符、对象。
ECMAScript 就是对实现该标准规定的各个方面内容的语言描述。
DOM——针对XML 但将扩展用于HTML的应用程序编程接口(API)。
DOM把整个页面映射为一个多层节点结构,页面中的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。
借助 DOM 提供的 API,可以轻松自如地删除、添加、替换、修改任何节点。
BOM —— 可以访问和操作浏览器对象模型。
根本上讲,BOM 只处理浏览器窗口和框架,但习惯上把所有针对浏览器的 JavaScript 扩展都算作 BOM 的一部分。如:
弹出新浏览器窗口;
移动、缩放和关闭浏览器窗口的功能;
- 提供浏览器详细信息的 navigator 对象;
- 提供浏览器所加载页面的详细信息的 location 对象;
- 提供用户显示器分辨率详细信息的 screen 对象;
- 对 cookies 的支持;
- 像 XMLHttpRequest 和 IE 的 ActiveXObject 这样的自定义对象。
在 HTML 中使用 JavaScript
<script>
元素
- src 属性:可选,当加载外部 js 文件时,此属性必需;可以指向当前页面所在域之外的某个域中的完整 URL 。
- type 属性:可选,写代码使用的脚本语言的内容类型,默认 text/javascript。
- async 属性: 可选,立即下载脚本,但不应妨碍页面中的其他操作,如下载其他资源或等待加载其他脚本。只对外部脚本文件有效。
- defer 属性:可选。立即下载,延迟执行。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部文件有效。defer=’defer’。
无论如何包含代码,只要不存在 defer 和 async 属性,浏览器都会按照<script>
元素在页面中出现的先后顺序对他们依次进行解析。
undefined和null
1、定义
- (1)undefined:是所有没有赋值变量的默认值,自动赋值。
- (2)null:主动释放一个变量引用的对象,表示一个变量不再指向任何对象地址。
2、何时使用null?
当使用完一个比较大的对象时,需要对其进行释放内存时,设置为 null。
DOM
getElementsByTagName 和 getElementsByClassName 这两个方法查找多个 dom 元素,返回的是 htmlcollection 类型,是伪数组而不是真数组,故不能使用数组的方法。
我们可以使用数组原型配合 slice 方法,利用 call,apply,bind 方法将伪数组转为真数组。
var x=document.getElementById("main");
var y=x.getElementsByTagName("p");
console.log(y)//在控制台我们可以看到原型proto为htmlcollection,是伪数组
//伪数组转为真数组方法1
console.log(Array.prototype.slice.call(y))//在控制台我们可以看到原型proto为Array(0),是真数组
//伪数组转为真数组方法2
console.log(Array.prototype.slice.apply(y))//在控制台我们可以看到原型proto为Array(0),是真数组
//伪数组转为真数组方法3
console.log(Array.prototype.slice.bind(y)())//在控制台我们可以看到原型proto为Array(0),是真数组
Prototype
通常使用构造器(函数体)定义属性,使用原型对象(prototype)定义方法。
如此,构造器只包含属性定义,而方法则分装在不同的代码块,使代码更具可读性
三个js语法
1.一个全局变量是在全局作用域被声明的变量,对于其它所有的作用域可见。在javascript中,全局变量是全局对象的一个属性。这个全局对象在node中是global
, 在浏览器中是window
,也就是说
var a=6;
//=== window.a=6
2.this的指向完全取决于函数调用的位置
3.在node(指在js文件)中,顶层作用域中在函数外的 this
指向的是module.exports
,在函数内(若函数未绑定特定对象),则this
指向的是global
而node在执行一个js文件,是将该js文件当作一个模块,而模块在node中大体是这样运行的
function Module(){
this.exports={}
}
function Fun(exports, require,module,__filename,__dirname){
//你的在js中的代码
}
var module=new Module();
var exports=module.exports;
var options = [exports, require, module, filename, dirname];
Fun.apply(exports,options);
现在来看,答案已经非常明显啦,在浏览器和node repl中,运行foo()
时候的this指向的是全局对象,而你在运行foo()
的前一句var bar=2
实际上已经在全局对象上添加了一个bar
的属性,而且值为2.
而在node执行js文件时,把它当作一个模块,var bar=2
中的bar只是顶层作用域的变量,而非全局变量,自然不会在全局对象global
上添加一个bar
的属性,故为undefined
.
转载:https://juejin.cn/post/6844904136161361933#1
变量类型
==与===
==的判断
- 并不是那么严谨的判断左右两端是否相等
- 它会优先对比数据的类型是否一致
- 不一致则进行隐式转换,一致则判断值的大小,得出结果
- 继续判断两个类型是否为null与undefined,如果是则返回true
- 接着判断是否为string与number,如果是把string转换为number再对比大小
- 判断其中一方是否为boolean,如果是就转为number再进一步判断
- 判断一方是否为object,另一方为string、number、symbol,如果是则把object转为原始类型再判断
比较情况
- 数组 == 值,(值类型指的是原始类型)会先转成数值再比较,与字符串比较会先转成字符串再比较
- 引用 == 值,会把引用类型转成原始类型再比较
- 值 == 值,直接比较类型再比较值的大小
- 字符串 == 数字,则把字符串转为数值再比较
- 其他类型 == boolean,则把boolean转成数值再进一步比较
- undefined == null,也会发生隐式转换,且2者可以相互转换,即2者相等,与自身也相等
- 对象 == 非对象,如果非对象为string或number,则返回ToPrimitive(对象) == 非对象,的结果;ToPrimitive方法的参数如果是原始类型则直接返回;如果是对象,则调用valueOf方法,如果是原始值再进行原始类型转换和大小对比;如果不是原始值则调用toString,且结果为原始值则进行原始类型比较,如果不是原始值则抛出错误
// 以下结果都为true
console.log([5]==5,['5']==5)
console.log({name:'5'}=='[object Object]')
console.log('5'==5,true==1,false==0)
console.log(undefined==null)
console.log([5,6]=='5,6',['5','6']=='5,6')
大白话:优先比较类型,同类型,比大小,非原始,调ToPrimitive,为对象调valueOf,还非原始调toString,最后还非原始则报错,如果为原始则进行类型对比,如果不同类型再转换,之后对比大小。
优先比类型,再比null与undefined,再比string和number,再比boolean与any,再比object与string、number、symbol;以上如果转为原始类型比较,则进行类型转换,直到类型相同再比较值的大小。
JavaScript中数组迭代方法
forEach
让数组中的每一项做一件事
//我们先用它来遍历数组
let arry=[9,8,7,6,5,4]
array.forEach(function(value,index,arr){
console.log(value)
}) //输出结果为9 8 7 6 5 4
//尝试遍历对象
let obj={a:1,b:2,c:3,d:4}
obj.forEach(function(value,index,oObj){
console.log(value)
} //输出结果会是obj.forEach is not a function,
//所以forEach不可以遍历对象,这也是它和for in的一个区别
一般用于对数组的遍历,不用于对对象的遍历,此方法会对数组中的每一个值进行遍历,直至全部遍历完成。故在其中的return,break会失效。
for in
一般用于遍历对象,循环遍历对象的key,不推荐遍历数组。fot in循环里面的index是string类型的
缺点:某些情况下,会出现随机顺序的遍历,因为里面的值是string类型,所以 增加了转换过程,因此开销较大
let person={name:"老王",age:23,city:"大唐"}
let text=""
for (let i in person){
text+=person[i]
}
输出结果为:老王23大唐 //其次在尝试一些数组
let arry=[1,2,3,4,5] for (let i in arry){
console.log(arry[i])
} //能输出出来,证明也是可以的
for of
可遍历map,object,array,set string等,与forEach不同的是,它可以正常的响应break, return,continue,避免了for in的所有缺点
缺点:不适用于处理原有的原生对象(原生对象是一个子集,包含一些在运动过程中动态创建的对象)
//遍历数组
let arr=["nick","freddy","mike","james"]; for (let item of arr){
console.log(item)
} //暑促结果为nice freddy mike james
//遍历对象
let person={name:"老王",age:23,city:"唐山"} for (let item of person){
console.log(item)
} //我们发现它是不可以的
map
让数组通过某种计算产生一个新数组
var newArr = arr.map(function(item,index){
return item * 2
});
filter
筛选出数组中符合条件的项,组成新数组
var newArr = arr.map(function(item,index){
return item > 3
});
reduce
让数组中的前项和后项做某种计算,并累计最终值
var result = arr.reduce(function(prev,next){
return prev + next;
})
every
检测数组中的每一项是否符合条件
var result = arr.every(function(item,index){
return item > 0;
})
some
检测数组中是否有至少一个项符合条件
var result = arr.some(function(item,index){
return item > 1;
})
Apply
call和apply的区别
不同之处是:
call()
方法分别接受参数。
apply()
方法接受数组形式的参数。
如果要使用数组而不是参数列表,则 apply()
方法非常方便。
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
person.fullName.apply(person1, ["Oslo", "Norway"]);
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
person.fullName.call(person1, "Oslo", "Norway");
在数组上模拟 max 方法
Math.max.apply(null, [1,2,3]); // 也会返回 3
第一个参数(null)无关紧要。在本例中未使用它。