DOM 和 BOM
- 文档对象模型(DOM):提供访问和操作网页内容的方法和接口
- 浏览器对象模型(BOM):提供与浏览器交互的方法和接口
arguments
arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。例如,它没有 pop 方法。
转换为一个真正的Array:
|
|
关于类型
- Object.prototype.toString.call(arguments); // “[object Arguments]”
- typeof arguments // Object
数据类型
基础数据类型
- string
- Number
- Boolean
- undefined
- Null
引用数据类型
- Object(Array,Date,RegExp,Function)
null 和 undefined 的异同
- 共同点
- 都是表示”无”
- 用if语句时,都会被转成false
- 不同点
- null 是一个表示“无”的对象,转换为数字的时候是
0
- undefined 是一个表示“无”的原始值,转换为数字时是
NaN
|
|
- Null典型用法
- 函数参数传递为空时,使用null 如 foo(null,null)
- 原型链的终点,如 Object.getPrototypeOf(Object.prototype)
- undefined典型用法
- 一个定义了的变量没有赋值
- 一个函数该给的参数没有给
- 一个对象的某个属性没有赋值
- 函数没有返回值时,默认为undefined
检测类型的方法
typeof 适用于基础类型 而不适合引用类型
12typeof undefined; //undefined 有效typeof null; //object 无效instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型
constructor
12let f = new F()f.constructor == F //truetoString()
12let type = Object.prototype.toString.call(true)type.slice(8,-1)
类型转换,判断下列的真假
|
|
执行环境和作用域
js 的作用域有几种?
- 局部作用域 / 函数作用域(块级作用域)
全局作用域
作用域链
当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。执行环境也就是函数之外那一层
无块级作用域:使用var时,变量会自动添加到最接近的环境(函数)中。
this
this有哪些应用场景
作为对象方法调用
1234567var test = {a:0,b:0get:function(){return this.a; // 对象方法调用}}作为构造函数的调用
1234function Point(x, y){this.x = x;this.y = y;}使用 call 和 apply
- 获取全局对象
Tips
- this对象是在运行时基于函数的执行环境绑定的。普通函数调用,函数被谁调用,this就指向谁。
- 记住应当去看当前this指向哪里。普通函数定义时,它里面的this都指向全局(如案例三)。除非去根据构造函数new 一个实例,这个实例的this指向了它本身(案例六)
- 箭头函数和普通函数的this
- 原型链中的this:往上找
- getter 与 setter 中的 this
- 作为一个内联事件处理函数:当代码被内联on-event 处理函数调用时,它的this指向监听器所在的DOM元素:
普通对象函数的this
|
|
闭包或普通函数的this
|
|
构造函数this
- 如果有new关键字,this指向new出来的那个对象
eg: 如在浏览器下执行123456function F(){console.log(this)}F(); // windowlet f = new F() // 这一步会执行F(),且this指向F,而非window
匿名函数的this
参考:匿名函数的执行环境具有全局性《JavaScript高级程序设计》P182
|
|
|
|
箭头函数中的 this
|
|
|
|
此时的 this继承自obj, 指的是定义它的对象obj, 而不是 window!
示例(多层嵌套的箭头函数):
|
|
因为f1定义时所处的函数 中的 this是指的 obj, setTimeout中的箭头函数this继承自f1, 所以不管有多层嵌套,都是 obj
匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window
|
|
创建对象(类)
采用ES5创建对象/类
可以先理清js下的类
- 类 没用于继承的话 它就是一个普通函数
- 类 就是 构造函数
- 构造函数 用来生成 特定类型 的对象
方法:记住各种弊端
- 工厂模式
|
|
弊端:
- 创建后无法识别是何种类型的对象
构造函数模式
1234567function Person(name, age){this.name = name;this.age = age;this.sayName = function(){console.log(this.name)}}
与工厂模式不同的是:
- 不用显示new一个Object
- 将对象方法都赋予this
- 不用return
弊端:
方法不能共享,每个实例都会创建一个新的对象
解决办法:可以将sayName方法写于类之外,然后this.sayName=全局的sayName
但当有很多方法时全局写太多方法会不优雅而且混乱原型式模式
12345678function Person(){}Person.prototype.name = 'abigale'Person.prototype.age = 18Person.prototype.sayName = function(){console.log(this.name)}
弊端:
- 不能传参
- 构造函数模式 + 原型式模式 结合
- 需要传参数的用构造函数模式
- 需要共享的用原型式模式
new 的过程经历哪些步骤
- 第一步: 创建一个Object对象实例。
- 第二步: 将构造函数的执行对象赋给新生成的这个实例。(也就是改变this的指向)
- 第三步: 执行构造函数中的代码
- 第四步: 返回新生成的对象实例
检测是否实例的各个方法
- instanceof
- isPrototypeOf : Person.prototype.isPrototypeOf(person)
- Object.getPrototypeOf() : Object.getPrototypeOf(person) == Person.prototype
检测是否有某个属性
- isOwnPrototype : person.isOwnPrototype(‘name’)
- in : ‘name’ in person
构造函数原型实例原型链
理解:
- 构造函数:用来在创建对象时初始化对象。特点:构造函数名一般为大写字母开头;与new运算符一起使用来实例化对象,其中属性需要用this,否则跟普通函数无差别
- 原型:构造函数在创建的过程中,系统自动创建出来与构造函数相关联的一个空的对象。可以由构造函数.prototype来访问到。
- 实例
- 继承
原型链:每一个对象都有自己的原型对象,原型对象本身也是对象,原型对象也有自己的原型对象,这样就形成了一个链式结构,叫做原型链。
构造函数,原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
原型和实例的关系:instanceof 和 isPrototypeOf
123// 判断A是否是B的实例,B是否是A的原型A instanceof BB.prototype.isPrototypeOf(A)
|
|
Person 为构造函数
p 为实例
Person.prototype 为原型
Person.prototype.constructor == Person
person.proto == Person.prototype
使用new关键字调用函数(new ClassA(…))的具体步骤:
- 创建空对象:var obj = {};
- 设置新对象的constructor属性为构造函数的名称,设置新对象的proto属性指向构造函数的prototype对象:obj.proto = ClassA.prototype;
- 使用新对象调用函数,函数中的this被指向新实例对象:ClassA.call(obj); //{}.构造函数();
- 将初始化完毕的新对象地址,保存到等号左边的变量中
prototype和proto的关系是什么
一个类的实例 的隐式原型(proto)指向 类的原型(prototype)
原型链图解
继承
原型链:采用实例的方式去继承,但会有两个弊端:
- 原型链中如果有变量是引用类型,该值会被共享
- 子类型无法向父类型传递参数
12345678910111213141516function Father(){this.property = true;}Father.prototype.getFatherValue = function(){return this.property;}function Son(){this.sonProperty = false;}//继承 FatherSon.prototype = new Father();//Son.prototype被重写,导致Son.prototype.constructor也一同被重写Son.prototype.getSonVaule = function(){return this.sonProperty;}var instance = new Son();alert(instance.getFatherValue());//true借用构造函数
- 再也不会被共享,每次都是有自己一个方法有些浪费资源
123456789101112131415161718192021222324252627282930313233343536373839404142function Father(){this.colors = ["red","blue","green"];}function Son(){Father.call(this);//继承了Father,且向父类型传递参数}var instance1 = new Son();instance1.colors.push("black");console.log(instance1.colors);//"red,blue,green,black"var instance2 = new Son();console.log(instance2.colors);//"red,blue,green" 可见引用类型值是独立的```* 组合继承:使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承.```jsfunction Father(name){this.name = name;this.colors = ["red","blue","green"];}Father.prototype.sayName = function(){alert(this.name);};function Son(name,age){Father.call(this,name);//继承实例属性,第一次调用Father()this.age = age;}Son.prototype = new Father();//继承父类方法,第二次调用Father()Son.prototype.sayAge = function(){alert(this.age);}var instance1 = new Son("louis",5);instance1.colors.push("black");console.log(instance1.colors);//"red,blue,green,black"instance1.sayName();//louisinstance1.sayAge();//5var instance1 = new Son("zhai",10);console.log(instance1.colors);//"red,blue,green"instance1.sayName();//zhaiinstance1.sayAge();//10原型式继承:如果你指向让一个对象与另一个对象保持类似。(有一个对象可以作为另一个对象的基础)
但与原型模型一样,引用类型会被共享123456789101112// Object.create 的实现方式function object(o){// var F = function(){}// F.prototype = o;// return new F()var F = {}F.__proto__ = o.prototype;o.call(F)return F}A = object(B)寄生式继承:除了以另一个对象作为基础来继承,还为新对象添加新属性或方法,和借用构造函数模式相似
1234567function createAnother(original){var clone = object(original);//通过调用object函数创建一个新对象clone.sayHi = function(){//以某种方式来增强这个对象alert("hi");};return clone;//返回这个对象}
闭包
考点
- 执行环境
- 作用域链(变量):本地活动对象 全局变量对象
- 闭包中this的指向
- 闭包的危害
闭包是什么
一个函数里包含着另一个函数,内部函数可以访问函数外面的变量
闭包的作用/为什么要有闭包这种东西出现
闭包通常用来创建内部变量,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作
闭包有什么副作用
内存泄露
因为内部函数引用了外部函数某个值时,这个值不管函数执行不执行都在内存中,解决办法是将该值设为null
有这样一个函数,如何让b 访问不到a
|
|
js只有函数作用域,可以将a包裹在function或者IIFE中
其他题目
|
|
|
|
|
|
事件流模型
Javascript 的事件流模型都有什么?优点?
事件捕获是从外层元素到目标元素的过程,事件冒泡是从目标元素到外层元素的过程
|
|
|
|
- 输出结果
|
|
阻止冒泡
事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
|
|
|
|
- 输出结果
|
|
事件委托
事件委托就是把一个元素响应事件(click、keydown……)的函数委托到另一个元素 / 委托(代理)事件是那些被绑定到父级元素的事件,但是只有当满足一定匹配条件时才会被挪。这是靠事件的冒泡机制来实现的
事件委托有点
- 可以大量节省内存占用,减少事件注册,比如在table上代理所有td的click事件就非常棒
- 可以实现当新增子对象时无需再次对其绑定事件,对于动态内容部分尤为合适
事件委托缺点
- 事件代理的应用常用应该仅限于上述需求下,如果把所有事件都用代理就可能会出现事件误判,即本不应用触发事件的被绑上了事件。
|
|
|
|
|
|
target 和 currentTarget 的 区别
event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget。
对象
属性类型
- 数据属性:configurale,enumerable,writable,value
|
|
- 访问器属性: configurale,enumerable,get,set
|
|
对象的深拷贝
- Object.assign()
- JSON.parse(JSON.stringify(data))
箭头函数
箭头函数和普通函数的区别
this
- 普通函数this指向执行时调用它的对象
- 箭头函数this总是指向定义时所在的对象,而不是运行时所在的对象
普通函数
个人理解:可以理解为growUp并没有挂载到我们可以看到的对象里面 而是挂载到全局对象了
|
|
箭头函数
个人理解:因为箭头函数没有自己的作用域,所以它在定义时就挂载了Person之上了。
|
|
返回值
只有多行才需要返回值,一行则不需要
|
|
无arguments
但有
|
|
异步
了解JavaScript的异步吗?
- 回调函数
- 事件监听
- 发布/订阅
- Promises对象
- setTimeOut
- ajax
了解 Promise 吗? 简要地描述了一下 resolve、reject 函数和 then 方法
- Promise 是 ES6 的新特性,可以解决ES6新特性的问题。Promise构造函数接受一个函数作为参数,该函数包含两个参数:resolve 和 reject
- resolve: 如果异步操作成功,调用resolve,状态从pending 变为 resolved
- reject: 如果异步操作失败,调用reject,状态从pending 变为 rejected
- then: 返回一个新的Promise对象,因此可以采用链式写法
数组
数组的方法有哪些?
- pop()
- push()
- shift()
- unshift()
- slice()
- splice()
- join()
字符串
- split() // 第一个参数:以什么分割, 第二个参数:设定返回的数组长度
数组的深拷贝
- 用push
用slice
12345var arr = [1,2,3,4,5]var arr2 = arr.slice(0)arr[2] = 5console.log(arr)console.log(arr2)JSON.stringify和JSON.parse转换
该方法的缺点:非标准Json格式无法拷贝以及兼容性问题
判断数组的方法
|
|
窗口位置
获取元素以下信息,可以参考
offset系列 | client系列 | scroll系列 |
---|---|---|
offsetWidth | clientWidth | scrollWidth |
offsetHeight | clientHeight | scrollHeight |
offsetLeft | clientLeft | scrollLeft |
offsetTop | clientTop | scrollTop |
- width: document.body.clientWidth
- height: document.body.clientHeight
给定一个元素获取它相对于视图窗口的坐标
|
|
因此坐标可以从中获取
ES6
ES6新特性,变化
对ES6新特性看法:这些特性可以使写出的代码更加简洁。块级作用域的出现 ,使变量的命名更加安全和规范。新增的模块特性使语言本身能够实现静态化模块依赖,相比于使用requireJS等动态模块来说有更高的效率。只是从现有的规范的模块移植到ES6原生的模块还需要借助模块转换 工具(或者手动更改模块的写法)
- let的作用域:变量只有在let的作用块有效 和const
var:所在函数作用域 变量提升
let:所在作用快 不会代码提升 - 数组的解构 对象的解构:从数组或对象中提取值,对它们进行赋值
- 对象的扩展 :proto Object.setPrototypeOf(object,prototype) Object.getPrototypeOf()
- Set数组:成员没有重复值 Map 键值对
- 函数默认值 rest参数
- 箭头函数:简化了写法;this指向所指对象 ;不能使用argument;不能使用call apply bind
- for..of 循环
- class 对象
- Promise 是异步编程的一种解决方案
- Module:import export
模块管理
- CommonJS 为同步,AMD 为异步。
- CommonJS 是一中规范,NodeJS中所采用的规范。
- ES6 标准为JavaScript新语法,我们不需要做引入。
- CommonJS 和 AMD 为运行时加载,而 ES6 为编译时加载。
参考: 前端模块化
函数节流和函数反抖
函数防抖(debounce)
当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间
|
|
函数节流(throttle)
预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期
|
|
参考: 函数节流与函数防抖
resize和scroll事件的性能优化
|
|
正则表达式
字符 | 等同于 描述 |
---|---|
. | [^\n\r] 除了换行和回车之外的任意字符 |
\d | [0-9] 数字字符 |
\D | [^0-9] 非数字字符 |
\s | [ \t\n\x0B\f\r] 空白字符 |
\S | [^ \t\n\x0B\f\r] 非空白字符 |
\w | [a-zA-Z_0-9] 单词字符(所有的字母) |
\W | [^a-zA-Z_0-9] 非单词字符 |
代码 | 类型 | 描述 |
---|---|---|
? | 软性量词 | 出现零次或一次 |
* | 软性量词 | 出现零次或多次(任意次) |
+ | 软性量词 | 出现一次或多次(至道一次) |
{n} | 硬性量词 | 对应零次或者n次 |
{n,m} | 软性量词 | 至少出现n次但不超过m次 |
{n,} | 软性量词 | 至少出现n次(+的升级版) |
贪婪匹配 和 非贪婪匹配
|
|
全文单词首字母大写
|
|
写一个 function,清除字符串前后的空格。(兼容所有浏览器)
使用自带接口 trim(),考虑兼容性:
|
|
把 aa_bb_cc
变为 aaBbCc
方法一:正则:注意正则表达式中加不加括号的区别
|
|
方法二:采用正则
|
|
方法三:采用数组分割
|
|
var numberArray = [3,6,2,4,1,5]; 实现对该数组的倒排,输出[5,1,4,2,6,3];实现对该数组的降序排列,输出[6,5,4,3,2,1]
|
|
输出今天的日期,以 YYYY-MM-DD 的方式,比如今天是 2017 年 9 月 13 日,则输出 2017-09-13
|
|
将字符串”{$id} {$name} ”中的{$id}替换成 10,{$name}替换成 Tony (使用正则表达式)
|
|
写一个函数,实现{}括号里面的替换
当正则表达式里有字符串时,采用new RegExp的方法
|
|
兼容性
JavaScript兼容性问题
- 标准的事件绑定中绑定事件的方法函数为 addEventListener,而IE使用的是attachEvent
- 事件处理中非常有用的event属性获得亦不相同,获得目标元素ie为e.srcElement 标准浏览器为e.target
- 在ie中是不能操作tr的innerHtml的
- ie日期函数处理与其它浏览器不大一致,比如: var year= new Date().getYear(); 在IE中会获得当前年,但是在firefox中则会获得当前年与1900的差值。
- 获得DOM节点的方法有所差异,其获得子节点方法不一致。IE:parentElement.children;Firefox:parentNode.childNodes
- 当html中节点缺失时,IE和Firefox对parentNode的解释不同。例如:
<form> <table> <input/> </table> </form>
IE:input.parentNode的值为空节点 Firefox:input.parentNode的值为form 解决方法:Firefox中节点没有removeNode方法,必须使用如下方法 node.parentNode.removeChild(node) - 关于AJAX的实现上亦有所不同;
解决浏览器兼容性一些常用的库
- normalize.css : 解决CSS兼容问题
- excanvas.js : 解决IE6-IE8不能采用canvas问题
- html5shiv.js : 解决IE6-IE8不能使用html5问题
- respond.js : 解决响应式布局问题
其他
原生 js 怎么获取某个类名的所有元素
- document.querySelectorAll()
document.getElementByClassName()
querySelector()返回文档中匹配指定 CSS 选择器的一个元素,如
- document.querySelector(‘p’)
- document.querySelector(‘.aa’)
- document.querySelector(‘#aa’)