变量作用域:

1、全局变量:在全局作用域下声明的变量

​ 在函数内部没有声明直接赋值的变量也是属于全局变量

全局变量:只有浏览器关闭的时候才会销毁,比较占内存资源

局部变量 :当我们程序执行完毕就会销毁,比较节约内存资源

作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值 这种结构我们称之为作用域链 就近原则

var申明变量会存在变量提升

js引擎运行js分为两步:

1、解析 2、代码执行

​ (1)预解析:js 引擎会把 js 里面所有的 var 和 function 提升到当前作用域的最前面。

​ (2)代码执行:按照代码速写的顺序从上往下执行

2、预解析分为变量预解析(变量提升)和函数预解析(函数提升)

​ (1)变量提升:就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作

​ (2)函数提升:就是把所有的函数声明提升到当前作用域的最前面 不调用函数

构造函数:

​ 1.构造函数名字首字母要大写

​ 2.构造函数不需要return 就可以返回结果

​ 3.调用构造函数必须使用new

​ 4.只要new Star() 调用函数就创建了一个对象

object.setAttribute(sName, vValue [, iFlags]):给元素设置自定义属性

参数:
sName 
必填项. String类型,属性名
vValue
必填项. 为属性指定的变量,可以为string, number, 或者 Boolean类型
iFlags
选填. 下面指定的两种 Integer 类型的标志
覆盖同名属性.
1
默认值. 为属性添加指定的值.

let attribute = element.getAttribute(attributeName);查看元素的自定义属性

添加事件监听:addEventlistener(事件,函数)

事件捕获和事件冒泡

事件捕获:发生事件时从document一级一级往下寻找目标

事件冒泡:当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发,这一过程被称之为事件冒泡(简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件)

阻止事件冒泡

事件对象.stopPropagation()

事件委托

事件对象的常用对象方法:

阻止冒泡传播:stopPropagation()

获取当前的被操作的对象:target()

阻止默认事件的发生:preventDefult()

等待页面内容全部记载完毕:load()

等待DOM加载完毕,不包含图、css等等:DOMContentLoaded()

定时器(只调用一次):setTimeout(函数,延时时间)

var t1 = setTimeout(function () {
    console.log('时间到')
}, 3000)

清除定时器:clearTimeout(定时器名称)/clearInterval(定时器名称)

var t1 = setTimeout(function () {
    console.log('时间到')
}, 3000)
var btn = document.querySelector('button')
btn.addEventListener('click', function () {
  clearTimeout(t1)
  console.log('已阻止');
})

间歇函数 setInterval(函数,间隔时间)

每隔一段时间执行setInterval中的函数

let s1 = setInterval(function () {
    console.log('持续输出')
}, 1000)

关闭定时器 clearInterval(变量名)

let 变量名 = setInterval(函数,间隔时间)
clearInterval(变量名)

offset和style的区别

offset可以得到任意样式表中的样式值

所以我们想要获取元素大小位置,用offset更合适

style只能得到行内样式表中的样式值

所以我们想要给元素更改值,则需要用style改变

立即执行函数

作用:创建一个独立的作用域,避免了命名冲突问题

两种写法:(function(){})() 或者 (function(){}())

获取dom元素

let box = document.querySelector('div')  //返回一个dom对象

修改dom的样式 (className属性)

dom.className = 'newClassName'

格式化输出

let i = 'tuoni'
console.log(`名字叫${i}`)  //用反引号包裹

事件监听 addEventListener('事件',触发事件后执行的函数)

let btn = document.querySelector('button')
btn.addEventListener('click',function () {
    console.log('被点击了!')
  )

回调函数

如果将函数A作为参数传递给函数B时,我们称函数A为回调函数

简单理解:当一个函数被当做参数来传递给另外一个函数的时候,这个函数就是回调函数

常见的使用场景:

function fn(){
  console.log('我是回调函数...')
}
// fn传递给了setInterval,fn就是回调函数
setInterval(fn, 1000)

事件对象

1.什么是事件对象?

​ 也是个对象,这个对象是有事件触发时的相关信息

2.事件对象在哪里?

​ 在事件绑定的回调函数的第一个参数就是事件对象

元素.addEventListener('click', function(e){})  // 这里的e就是鼠标的事件对象

常用的事件对象中的属性:

type:获取当前的事件类型

clientX/clientY:获取光标相当于浏览器可见窗口左上角的位置

offsetX/offsetY:获取光标相当于当前DOM元素左上角的位置

key:用户按下的键盘键的值,现在不提倡使用keyCode

srcroll家族

scrollWidthscrollHeight:获取元素的内容总宽高(不含滚动条)返回值不带单位

scrollLeft scrollTop:获取元素内容往左、往上滚出去看不到的距离

属性可以修改

offset家族

offsetWidthoffsetHeight:获取元素的自身宽高、包含元素自身设置的宽高、padding、border

offsetLeftoffsetTop:获取元素距离自己定位父级元素的左、上距离

注意:offsetLeftoffsetTop是只读属性不能修改

client家族

clientWidthclientHeight:获取元素的可见部分宽高(不含滚动条和边框)

clientLeftclientTop:获取元素的位置

js中的同步异步执行顺序(即事件循环)

1.先执行执行栈中的同步任务

2.异步任务放入任务队

3.一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行

注意:如果存在多个异步任务,会根据异步任务的实际情况来决定他们的优先级

location对象

location的数据类型是对象,它拆分并保存了URL地址的各个组成部分

常用属性和方法:

href属性获取完整的URL地址,对其赋值时用于地址跳转

search属性获取地址中携带的参数,符号?后面部分

hash属性获取地址中的哈希值,符号#后面部分

reload方法用来刷新当前页面,传入参数true时表示强制刷新

本地存储 localStorage

存储数据:localStorage.setItem('key', value)

读取数据:localStorage.getItem('key')

删除数据:localStorage.removeItem('key')

JSON.stringify(复杂数据类型)

将复杂数据类型转换成JSON字符串 存储到本地存储中

JSON.parse(JSON字符串)

将JSON字符串转换成对象 取出时候使用

正则

定义:let re = /正则表达式/的方式定义正则表达式,得到一个正则对象

test(): 用于判断是否有符合规则的字符串,返回的是布尔值

let re = /.*/
console.log(re.test('slasjdf'));  // true

exec(): 用于查找符合规则的字符串,返回一个数组

let re = /.*/
console.log(re.exec('slasjdf'));  // ['slasjdf']

面向对象(类,es6新增)

创建类的关键字:class

类中的构造方法:constructor()

实例化对象的关键字:new

class Student{
  constructor(name, age){
    this.name = name
    this.age = age
  }
}
let user = new Student('tuoni', 18)

类的继承

继承的关键字:extends

class Father{
  constructor(x, y){
    this.x = x;
    this.y = y;
  }
  sum(){
    console.log(this.x + this.y);
  }
  say(){
    console.log('我是爸爸')
  }
}
class Son extends Father{
  constructor(x, y){
    super(x, y);  //调用了父类中的构造函数,必须放在子类中this之前
    // super.say()  // 调用了父类中的其他方法
  }
}
var son = new Son(1, 2);
son.sum();

插入新的标签

element.insertAdjacentHTML(position, text)

构造函数创建对象(es6之前)

构造函数是一种特殊的函数,主要用来初始化对象即为对象成员变量赋初始值,它总与new一起使用,我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。

function Student(name, age) {
            this.name = name;
            this.age = age;
            this.run = function(){
                console.log('跑');
            }
        }
        var student1 = new Student('tuoni', 19);
        var student2 = new Student('张学友', 29);
        console.log(student1.age);
        console.log(student2.age);
        console.log(student1.run());
        console.log(student2.run());

构造函数原型 prototype

构造函数通过原型分配的函数是所有对象所共享的

JavaScript规定,每一个构造函数都有一个prototype属性,指向的是另一个对象,注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有

我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。

function Student(name, age) {
  this.name = name;
  this.age = age;
  Student.prototype.run = function () {
    console.log('跑');
  }
}
var student1 = new Student('tuoni', 19);
var student2 = new Student('孙悟空', 29);
student1.run(); // 跑
student2.run(); // 跑
console.log(student1.run === student2.run); // true 说明内存地址相同

对象原型

为什么studnet1对象可以直接调用prototype对象中的run方法?

​ 因为每个对象身上会有一个__proto__属性,这个属性等价于构造函数中prototype属性

方法的查找规则:首先看student1对象身上是否有run方法,如果有就执行这个对象上的run方法,如果没有,因为有__proto__的存在,就去构造函数原型对象prototype身上去查找

每个实例对象都会自带一个__proto__属性(原型),在上图中Star原型对象中也出现了__proto__属性(原型),说明Star的原型对象也是一个对象,那么Star原型对象__proto__属性(原型)来自于Object原型对象中,最终Object原型对象中的__proto__指向null

JavaScript的成员查找机制(规则)

  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
  2. 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
  3. 如果还没有就查找原型对象的原型(Object的原型对象)
  4. 以此类推一直找到Object为止(null)
  5. __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条线路

call方法改变this指向

fn.call(obj,形参1,形参2)

fn : 需要执行的函数

obj : 需要指向的对象

形参 :被执行函数所需要的参数

类的本质

  1. class本质还是function
  2. 类的所有方法都定义在类的prototype属性上
  3. 类创建的实例,里面也有__proto__指向类的prototype原型对象
  4. 所以ES6的类他的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
  5. 所以ES6的类其实就是语法糖

ES5中的新增方法

数组方法

forEach 迭代(遍历)数组

array.forrEach(function(currentValue, index, arr))

var list = [1, 2, 3, 34, 5]
list.forEach(function (value, index, arr) {
  console.log(value); 
  console.log(index);
  console.log(arr);
})

filter()

filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组

array.filter(function(currentValue, index, arr))

var li = [1, 2, 3, 4, 5]
var ar = li.filter(function (value, index, arr) {
  return value > 3;
})
console.log(ar); // [4, 5]

some()

var li = [1, 2, 3, 4, 5]
var ar = li.some(function (value, index, arr) {
  return value > 3;
})
console.log(ar); // true

对象方法

Object.defineProperty()定义新属性或修改原有的属性

Object.defineProperty(obj, prop, descriptor)

obj : 被操作的对象

prop : 属性名

descriptor : 说明,以对象形式{ }书写

var obj = {
  name: '1231',
  age: '232222'
}
Object.defineProperty(obj, 'sex', {
  value: '男',
  // 如果为false  不允许修改这个属性值 
  writable:false,
  // 如果为false  不允许遍历
  enumerable:false,
  // 如果为false  不允许删除这个属性 不允许在修改第三个参数里的特性
  configurable:false
})

字符串方法

trim()方法会从一个字符串的两端删除空白字符,并返回一个新的字符串

let st = '  andy   '
console.log(st.trim()) // 'andy'

Object.keys(obj)

获取对象中所有的键,以列表的形式返回

var obj = {
  name: '1231',
  age: '232222'
}
console.log(Object.keys(obj)); //['name', 'age']

bind方法

bind()方法不会调用函数,但是能改变函数内部this指向

fun.bind(thisArg, arg1, arg2, ...)

var obj = {
  name: 'tuoni',
  age: '19'
}
function fn(){
  console.log(this);
}
var f = fn.bind(obj)
f() // 指向obj

ES6语法

let 关键字

  1. 不能重复声明:
let a = 1;
let a = 2; // 报错
  1. 与var不同,没有变量提升

  2. 拥有块级作用域(在大括号中的才会存在)

if (true){
  let a = 1
}
console.log(a) //报错
-----------------------------
{
  let name = 'tuoni'
}
console.log(name) // 报错

const 关键字

  1. 不能重复声明:

    const a = 1;
    const a = 2; // 报错
    
  2. 用来定义常量,定义后不能修改,但是可以修改复杂数据类型

    const a = 1;
    a = 2 ;
    console.log(a); // 报错
    const list = [1,2,3];
    list.push(4);
    console.log(list); // [1,2,3,4]
    

箭头函数

  1. 无法改变箭头函数中的this指向,this始终指向函数声明时所在作用域下的this的值
// 普通函数
function a() {
  console.log(this);
}
// 箭头函数
let b = () => {
  console.log(this)
}
a() // window
b() // window
let obj = {
  name: 'tuoni'
}
a.call(obj) // tuoni
b.call(obj) // window
  1. 不能作为构造函数实例化对象

    let Person = (name, age) => {
      this.name = name;
      this.age = age;
    }
    let me = new Person('tuoni', 19)
    console.log(me); // 报错
    

对象定义简写

let obj = {
  name,
  say(){
    console.log('hhhhhh')
  }
}
等同于>>>>>>
let obj = {
  name: ''
  say: function(){
			console.log('hhhhhh')
  }
}

迭代器(需要自定义遍历数据的时候)

迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署 iterator 接口(对象中的一个属性),就可以完成遍历操作。

  1. ES6创造了一种新的遍历命令for...of循环,iterator接口主要提供for...of 消费
  2. 原生具备iterator接口的数据(可用for of遍历)
    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypeArray
    • NodeList
  3. 工作原理
    • 创建一个指针对象,指向当前数据结构的起始位置
    • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
    • 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
    • 每调用next方法返回一个包含value和done属性的对象

给自定对象添加iterator接口实现for...of遍历:

let obj = {
  name: '终极一班',
  stus: [
    'xiaomin',
    'xiaohuam',
    'xiaogao',
    'tuoni'
  ],
  [Symbol.iterator]() {
    // 索引变量
    let index = 0;
    let _this = this
    return {
      next: function () {
        if (index < _this.stus.length) {
          const result = { value: _this.stus[index], done: false 			}
          index++;
          return result
        } else {
          return { value: undefined, done: true }
        }
      }
    }
  }
}
// 使用for of 对对象进行自定义遍历
for (const i of obj) {
  console.log(i);
}