JS基础
变量
js中的变量类型(按存储方式区分)
- 值类型
- 引用类型(指针):数组、函数、对象
//共享内存,数据改变存在联动性。
//可以随意的扩展属性
在javascript中,判断数据类型主要依赖下面两种方式:
- 如果值应为一个引用类型,使用 instanceof 操作符检查其构造函数;
- 如果值应为一个基本类型,使用 typeof 检查其类型
type of 函数
typeof只能区分值类型的详细类型,无法区分引用类型,但可以区分出函数来
typeof undefined;//undefined
typeof 'abc';//string
typeof 123;//number
typeof true;//boolean
typeof {};//object
typeof [];//object
typeof null;//object
typeof console.log//function
===与==
if (obj.a == null){
// 这里相当于 obj.a === null || obj.a ===undefined ,因为 undefined == null 值为true
// 其他情况最好都用===
}
原型
对于引用类型来说
//都有__proto__属性,指向其构造函数的 prototype 属性值
//所有的函数,都有一个 prototype 属性,属性值也是一个普通的对象
//函数的 prototype 称显式原型,引用类型的 _proto 成为隐式原型
//
原型是一个对象,其他对象可以通过它实现属性继承。
原型链:
所有的引用类型(数组,对象,函数), __proto__属性(隐式原型)指向它的构造函数的“prototype”属性值(显式原型)
执行上下文
在代码执行之前,先执行(解析)变量定义和函数声明。
==范围==:一段<script>
或者一个函数之内都会生成一个上下文
==全局==:变量定义,函数声明.执行之前,一段<script>
会生成全局上下文
==函数==:变量定义,函数声明,this,arguments.函数执行之前会生成函数上下文
函数声明
function fn(name) {
...
}
函数表达式
var func = function () {
...
}
this
this要在执行时才能确认值,定义时无法确认
使用场景
- 作为构造函数执行
- 作为对象属性执行
- 作为普通函数执行
作用域链
函数的父级作用域是函数定义时候的作用域,不是函数执行时候的作用域,也就是说那个作用域定义了这个函数,这个函数的父级作用域就是谁,跟函数执行没有关系,函数自由变量要到父级作用域中找,就形成了作用域链
闭包
闭包使用场景
- 函数作为返回值
- 函数作为参数传递
(函数自由变量要到父级作用域(定义时的作用域)中找)
闭包在实际中的应用
在函数外无法修改函数内的值
function isFirstLoad(){
var _list = []
return function(id) {
//函数作用域
if(_list.indexOf(id) >= 0) {
return false
} else {
_list.push(id)
return true
}
}
}
var firstLoad = isFirstLoad()
firstLoad(1) //true
firstLoad(1) //false
firstLoad(10) //true
firstLoad(10) //false
//对于这个程序来说,在isFirstLoad函数外面,无法修改_list的值
问题:创建10个<a>
标签,点击的时候弹出来对应的序号
错误方法
var i,a
for(i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e) {
//点击时执行
e.preventDefault()
alert(i) //自由变量,要去父作用域(全局作用域)寻找
})
document.body.appendChild(a)
在执行时,当click事件发生时,外层for循环已经执行完毕,即i已经加到10了。
所以无论点击哪个元素,弹出来的序号都是10.
正确方法
var i
for(i=0;i<10;i++) {
(function(i) {
//函数作用域
//自执行函数,不用调用,只要定义完成,就会立即执行。
var a = document.createElement('a');
a.innerHTML = i + '<br>'
a.addEventListener('click',function(e) {
e.preventDefault()
alert(i)
//改变了父级作用域
})
document.body.appendChild(a)
})(i)//相当于创建了10个函数,每个函数都带着从0-9的i作为参数
}
异步与同步
异步,即为提高程序效率,将会阻碍代码执行的代码段暂存起来,不会立即执行。等待所有程序执行完,处于空闲状态时,再执行暂存的代码,使程序的执行顺序与代码顺序不一致。
何时需要异步
- 在可能发生等待的情况下
- 等待过程中不能像alert一样阻塞程序运行
- 因此,所有需要等待的时候都要使用异步
前端使用异步的场景
- 定时任务:setTimeout,setInterval
- 网络请求:ajax请求,动态加载
- 事件绑定
同步与异步的区别
- 同步会阻塞代码执行,而异步不会
- alert是同步(会阻塞程序执行),setTimeout是异步
数组与对象
问题:一个能遍历对象和数组的通用forEach函数
function forEach(obj, fn) {
var key
//判断是否为数组
//数组本身的forEach(item,index),需改变参数顺序
if (obj instanceof Array) {
obj.forEach( function (item, index) {
//改变参数顺序
fn(index, item)
})
} else {
for (key in obj) {
if(obj.hasOwnProperty(key)) {
fn(key, obj[key])
}
}
}
}
var arr = [1,2,3]
forEach(arr, function(index, item) {
console.log(index, item)
})
var obj = {x:100,y:200}
forEach(obj, function(key, val) {
console.log(key, val)
})
DOM与BOM
对于js来说,可以分为两大类:
- JS基础知识:ECMA 262标准, 规定一些基础语法
- WEB-API:W3C标准,它参与规定任何JS基础相关的东西,只管定义用于浏览器JS操作页面的API和全局变量
DOM操作常用api
- 新增节点 //appendChild
- 获取节点以及节点的property和Attribute
其中,property是对JS对象属性的修改,而attribute是对html标签的属性修改。s
- 查询父(parentElement)、子节点(childNodes)
- 删除节点 //appendChild
- 创建元素 //createElement