一、JavaScript基础知识回顾
1.1 JavaScript
1.1.1 javascript是什么?
JavaScript是一门编程语言,用来操作页面标签和样式。
1.1.2 javascript的组成
-
ECMAScript:可以为不同种类的宿主环境提供核心的脚本编程能力,因此核心的脚本语言是与任何特定的宿
主环境分开进行规定的。Web 浏览器对于 ECMAScript 来说是一个宿主环境,但它并不是唯一的宿主环境。
ECMAScript描述了以下内容:语法、类型、语句、关键字、保留字、运算符、对象。 -
DOM:(Document Object Model 文档对象模型)是 HTML 和 XML 的应用程序接口(API)。DOM 将把
整个页面规划成由节点层级构成的文档。HTML 或 XML 页面的每个部分都是一个节点的衍生物。用 DOM
API 可以轻松地删除、添加和替换节点。 - BOM:(Browser Object Model 浏览器对象模型)可以对浏览器窗口进行访问和操作。
1.1.3 ECMAScript与JavaScript的关系
前者是后者的规格,后者是前者的一种实现。
1.1.4 JavaScript中的数据类型
- 基本类型:number string boolean null undefined
- 引用类型:object (Array Date Math(比较特别) RegExp Function Object Error Number String Boolean XMLHttpRequest )
- 基本类型与引用类型的差别:
- 存储方式不同:基本类型数据存储在栈stack;引用类型存储在堆heap。
- 赋值方式不同:基本类型赋值的时候传递的是具体的值;引用类型赋值的时候传递的是内存的地址。
1.1.5 JavaScript中的语句
- 分支:if,if else,switch
- 循环:do while,while,for,for in
1.2 异常处理
作用:
- 防止某些程序出错时影响后面代码的执行。
- 屏蔽底层的报错细节,从而给用户一个友好提示。
var abc = 123;
try{
var data = false;
if(!false){
throw new Error('数据格式异常');
}
//try当中的代码一旦发生错误,try当中之后的代码就不再执行了
console.log(abc);
}catch(e){
//只有try当中的代码发生错误,这里才会执行
console.log(e.message);//表示错误原因
console.log(e.name);//表示错误类型
}finally{
//无论try当中的代码是否执行,这里都会执行
console.log(abc);
}
二、面向对象
2.1 面向对象概述
2.1.1 什么是对象
所谓的对象就是某种事物,万物皆对象。
用程序的方式描述对象:属性+行为。
2.1.2 对象创建方式
-
字面量:各种数据类型的字面量表示。
var obj1 = { username : '张三', age : 12, gender : 'male' };
-
构造函数:内置对象和自定义对象。
var obj2 = new Object(); obj2.username = '李四'; obj2.age = 13; obj2.gender = 'female';
如果构造函数不需要传递参数,那么后面的括号可以省略。
var obj = new Object(); var obj = new Object;
2.1.3 属性的访问方式
-
对象名.属性名称
。 -
对象名['属性名称']
。
两种方式的区别:方括号的方式可以使用变量。
2.1.4 实例化的本质
构造函数实例化对象本质上做了什么工作?
- 开辟堆内存用来存储实例中数据(属性和方法)。
- 用this指向该区域。
- 通过this向该区域中放置数据。
- 返回this
function Foo(info){
// 构造函数中的this指的是构造函数所创建的实例对象
this.info = info;
this.showInfo = function(){
// 实例方法中的this指向方法的调用者(实例对象本身)
console.log(this.info);
}
// 构造函数的默认返回值就是this
}
var foo = new Foo('tom');
foo.showInfo();
var foo1 = new Foo('jerry');
foo1.showInfo();
2.1.5 构造函数的返回值
- 构造函数如果显示的返回基本数据类型,那么和不返回等效。
- 构造函数如果显示的返回引用数据类型,那么就以此为准,就不再返回默认的this了。
function Person(name){
this.name = name;
return 123; //输出:Person {name: "zhangsan"}
return 'hello'; //输出:Person {name: "zhangsan"}
return {
name : 'lisi',
age : 12
}; //输出:Object {name: "lisi", age: 12}
return [1,2,3]; //输出:[1,2,3]
}
var p = new Person('zhangsan');
console.log(p);
2.1.6 对象原型
JavaScript中对象的本质:无序的键值对集合。
原型:实现数据共享(实例对象之间进行数据共享)。
function Foo(info){
this.info = info;
this.showInfo = function(){
console.log(this.info);
}
}
var f1 = new Foo('tom');
var f2 = new Foo('jerry');
console.log(f1.showInfo === f2.showInfo);//false
-------------------------------------------------------------------------------
function fn(){
console.log(this.name);
}
function Person(name,age){
this.name = name;
this.age = age;
this.showName = fn;
}
var p1 = new Person('zhangsan');
var p2 = new Person('lisi');
console.log(p1.showName === p2.showName);//true
2.1.7 原型分析
原型:函数都有一个原型属性prototype,该属性值本质上也是对象(实际就是Object的实例)。
原型的作用:实现数据共享(实例对象之间进行共享);实现继承。
__proto__
:构造函数产生的实例对象都有一个属性__proto__
,该属性不是标准属性,不可以在编程中使用,实际上该属性是浏览器内部使用的,该属性和构造函数中的prototype指向相同。
__proto__
属性在实例对象中,prototype属性在构造函数中,这两个属性的指向是相同的。
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.showName = function(){
console.log(this.name);
}
Person.prototype.showAge = function(){
console.log(this.age);
}
Person.prototype.flag = 123;
Person.prototype.arr = ['red','green','blue'];
var p1 = new Person('tom',12);
p1.flag = 456;
p1.arr.push('pink');
var p2 = new Person('jerry',13);
console.log(p1.flag,p2.flag); //456 123
console.log(p1.arr,p2.arr); //["red", "green", "blue", "pink"] ["red", "green", "blue", "pink"]
//解释:
//通过对象.属性名称=值 这种做法会向对象中添加一个属性
//但是obj.arr.push(123); 这种结构不会再obj中添加属性,而会obj.arr数组中添加一项数据
2.2 面向过程与面向对象
2.2.1 相关概念
-
面向对象是一种编程模式,就是以对象的方式写代码。
三大特性:封装、继承那个、多态。
面向过程的编程模式的缺点:团队开发容易产生命名冲突;不方便代码的重用;可维护性差。
-
JavaScript面向对象相关概念:
- 构造函数
- 实例对象
- 原型
2.2.2 面向对象开发
//实现如下功能:点击一个按钮改变div的背景色
//用面向对象的风格封装(构造函数+原型)
function ChangeColor(btnId,divId){
this.btn = document.getElementById(btnId);
this.div = document.getElementById(divId);
}
ChangeColor.prototype.init = function(){
// 原型方法中的this指的是该原型所属的构造函数的实例化对象,实际上与构造函数中的this指向相同
var that = this;//缓存实例对象
this.btn.onclick = function(){
// 这里的this是绑定事件函数的DOM对象
that.div.style.backgroundColor = 'yellow';
}
}
onload = function(){
var cc = new ChangeColor('btn','div1');
cc.init();
}
//不同的this场景:
//1、构造函数中的this
//2、原型方法中的this
//3、事件方法中的this
//1) 构造函数中的this和原型方法中的this指向相同:都是指向实例对象
//2)事件方法中的this指的是绑定事件的对象
2.2.3 对象中属性的判断
- in:判断对象中是否存在某个属性(属性在实例对象和原型对象都可以)。
- hasOwnProperty():判断属性是否在实例对象上。
//小测试:
if('a' in window) {
var a = 123
console.log(a);
}
//输出:123
//考点:
//1.全局作用域中的变量和函数都是window对象的成员
//2.预解析
//3.js中没有块级作用域
//实现一份方法,判断某个属性是否在原型上
function check(attr,obj){
if(attr in obj && !obj.hasOwnProperty(attr)){
return true;
}else{
return false;
}
}
2.3 构造函数、原型与实例的关系
2.3.1 构造函数、原型与实例的关系
- 构造函数中都有原型属性prototype,该属性值本质也是对象(Object的实例对象)
- 原型对象中都有一个属性constructor,该属性指向原型所属的构造函数
- 实例对象中都有一个属性
__proto__
,该属性不是标准属性,不可以在编程中使用,实际上是浏览器内部使用的,并且该属性指向原型对象。
2.3.2 原型链
原型链:实例对象和原型对象之间形成的有限链式结构,该链式结构通过
__proto__
连接起来,用于实现继承和共享属性。-
对象是有原型对象的,原型对象也有原型对象,原型对象也有原型对象,对象的原型对象一直往上找,会找到一个null。
var obj = new Object(); // obj -> Object.prototype -> null var arr = new Array(); // arr -> Array.prototype -> Object.prototype -> null var date = new Date(); // date -> Date.prototype -> Object.prototype -> null
-
原型链的结构可以通过重置原型对象的方式来修改。
function Foo1(info){ this.info = info; } Foo2.prototype = new Foo1('tom'); //Foo2.prototype.constructor = Foo1; function Foo2(info){ this.info = info; } Foo3.prototype = new Foo2('jerry'); //Foo3.prototype.constructor = Foo2; function Foo3(info){ this.info = info; } var f = new Foo3('spike'); console.dir(f); // f -> new Foo2('jerry') -> new Foo1('tom') -> Foo1.prototype -> Object.prototype -> null
2.4 继承
继承:别人的拿过来,自己的还是自己的。可以通过修改原型的指向来实现。
2.4.1 原型继承
function Animal() {
this.name = '动物';
}
function Tiger(color) {
this.color = color;
}
Tiger.prototype = new Animal();
var tiger = new Tiger('黄色');
console.log(tiger.name);
console.log(tiger.color);
缺点:没有办法给基础过来的属性赋值,而不影响所有的实例。继承过来的引用类型的数据,所有的实例时共享的。
2.4.2 借用构造函数继承
-
call和apply的基本使用:
- call和apply可以调用函数。
- 改变所调用函数内部的this指向。
- 在非严格模式下,普通函数中this是window;在严格模式下,普通函数中this是undefined。
-
借用构造函数继承:
function Person(name,favour){ this.name = name; this.favour = favour; } Person.prototype.showName = function(){ console.log(this.name); } function Student(num,name,favour){ // 这里的this是Student构造函数的实例 // Person.call(this,name,favour); Person.apply(this,[name,favour]); this.num = num; } var stu1 = new Student(1,'zhangsan',['coding']); stu1.favour.push('swimming'); var stu2 = new Student(2,'lisi',['dancing']); console.dir(stu1); console.dir(stu2); stu1.showName();
缺点:没有办法继承父级构造函数原型上的成员。
2.4.3 组合继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.show=function(){
console.log(this.name+"今年"+this.age+"岁了");
}
Person.prototype.flag=1;
function Teacher(name,age,level){
Person.call(this,name,age);
this.level=level;
}
Teacher.prototype=new Person();
var t1 = new Teacher("张三",33,"T5");
var t2 = new Teacher("李四",30,"T4");
t1.show();
2.5 Object.create的基本使用
//ES5新特性,方法的作用:创建对象
var create = function(obj){
if(Object.create){
return Object.create(obj);
}else{
function F(){}
F.prototype = obj;
return new F();
}
}
2.6 属性的复制
2.6.1 浅拷贝
var obj = {};
var obj1 = {
username : 'zhangsan',
age : 12,
gender : 'male'
}
function extend(des,origin){
for(var key in origin){
des[key] = origin[key];
}
}
extend(obj,obj1);
console.log(obj);
2.6.2 深拷贝
function foo(set){
var defaultSettings = {
width : '100',
height : '200',
backgroundColor : 'gray',
sets : {
flag : 12,
abc : 'message'
}
}
var obj = {
www : 'www'
}
var obj1 = {
qqq : 'qqq'
}
$.extend(true,defaultSettings,set,obj,obj1);
console.dir(defaultSettings);
console.log(defaultSettings.width);
console.log(defaultSettings.sets.flag);
console.log(defaultSettings.sets.abc);
}
var settings = {
width : '1000',
sets : {
flag : 123,
}
}
foo(settings);
2.7 函数
2.7.1 函数的原型链
-
Function:
- 所有的函数都是Function的实例。
- Funciton也是一个函数。
2.7.2 函数的三种角色
- 构造函数
- 普通函数
- 函数作为对象
function Foo(){}
var foo = new Foo(); //构造函数
Foo(); //普通函数
Foo.info = 'hello'; //函数作为对象
函数到底是哪种角色,取决于函数的调用方式
2.7.3 函数的定义方式
系统函数(类库、库函数)
-
自定义函数
-
函数声明
function foo(){ console.log(123); }
-
函数表达式
var fn = function(){ console.log(456); } fn();
-
new Function()
var fn1 = new Function('console.log(789);');//需要把字符串转成js代码并执行,性能没有前两者好 fn1();
区别:
- 函数声明是在预解析阶段创建的,而函数表达式是在程序执行阶段创建的。
- 函数声明只能在全局或者函数内部定义,而函数表达式只能在表达式中定义。
-
函数都是对象,但对象不一定是函数。
Math不是函数,而是对象
2.7.4 this的不同指向场景
-
函数的调用方式:(函数中的this指向取决与函数的调用方式)
- 构造函数
- 普通函数
- 对象方法
- call和apply调用(bind)
-
this的不同指向:
- 构造函数中的this指向实例对象
- 原型方法中的this指向实例对象,与构造函数中的this指向相同
- 在非严格模式下,普通函数中的this指向window,在严格模式下,普通函数中的this指向undefined
- 对象方法中的this就是调用方法的对象
- 事件方法中的this指的是绑定事件的对象
- 定时函数中的this指的是window
- call或apply所调用的函数中的this就是call或apply中的第一个参数(该参数必须是引用类型)
-
bind的基本用法:
- bind方法是ES5的新特性(函数的柯里化)
- bind用来改变函数内部的this指向,但是不调用函数,并且bind会返回一个新函数(其实还是原来的函数内容,只是this改变为bind中的第一个参数,该参数必须为引用类型)
var inner = function(a,b){ console.log(a+b); } var newInner = inner.bind({info:'hello'},12,13); setTimeout(newInner,1000);
2.7.5 高阶函数
高阶函数:
-
作为参数的函数
function foo(fn) { var data = { info: 'hello' } fn(data); } var fn = function(data) { console.log(data.info); }; foo(fn);
-
作为返回值的函数(闭包)
function foo(){ var num = 1; return function(){ return num++; } } var fn = foo(); var r1 = fn(); var r2 = fn(); console.log(r1,r2);
2.8 对象加深
2.8.1 对象的体系结构
- 所有的实例对象都有一个
__proto__
属性,该属性指向产生实例对象的构造函数的原型。 - 所有的构造函数都有一个prototype属性,该属性本质上也是一个对象(Object的实例对象)
- 所有的原型对象都有一个constructor属性,该属性指向原型所属的构造函数。
- 原型对象中有一个
__proto__
属性,该属性指向Object.prototype(Object的原型对象中没有__proto__
,因为这里就是原型链的终点) - 所有的函数都是Function的实例对象。
- Function函数本身也是它自己的实例对象(也就是
Function.__proto__
===Function.prototype)
2.8.2 基本类型与引用类型深入理解
-
基本类型
var num = 123 function foo(data){ data = '456'; return data; } var ret = foo(num); console.log(ret,num);//456 123
-
引用类型
var arr = [1,2,3]; function foo(data){ data.push(4); return data; } var ret = foo(arr); console.log(ret,arr);//[1, 2, 3, 4] [1, 2, 3, 4]
2.8.3 标准库
- 常用对象:Object、Array、Date、RegExp、Math、Function、Error
- 包装对象:Number、String、Boolean
2.8.4 类数组(关联数组)详解
-
类数组:
var obj = { 0 : 'qqq', 1 : 'www', 2 : 'eee', length : 3 }
-
类数组转数组:
var arr = [].slice.call(obj,0);
-
delete的用法:
var obj = { info : 'abc', username : 'lisi' } delete obj.info; console.log(obj);//Object {username: "lisi"} var flag = 123; delete flag; console.log(flag);//123
- delete的作用就是删除对象的属性。
- 全局作用域中var声明的变量,delete无法删除,但是不用var声明的全局变量可以delete删除。
-
求数组中的最大值:
//排序 var arr = [12321,234,99999999,4454,12,454545,343,34,342]; arr.sort(function(a,b){ return b - a; }); console.log(arr);//[99999999, 454545, 12321, 4454, 343, 342, 234, 34, 12] //对象中的Math方法 var max = Math.max(123,23,4324,45,4,645,6,45645); console.log(max); //借用对象的方法 var max = Math.max.apply(null,arr); console.log(max);
call和apply的应用场景:
- 调用函数
- 改变所调用函数的内部this指向
- 转换类数组
- 借用别的对象方法
2.9 递归
2.9.1 递归的执行原理
function fn(n){
if(n == 1){
console.log('递归结束' + n);
return 1;
}else{
console.log('递归前' + n);
var ret = n * fn(n-1);
console.log('递归后' + n);
return ret;
}
}
var ret = fn(5);
console.log(ret);
/* 输出结果:
递归前5
递归前4
递归前3
递归前2
递归结束1
递归后2
递归后3
递归后4
递归后5
120
*/
2.9.2 递归的应用
function getChildNodes(node, arr) {
for (var i = 0; i < node.childNodes.length; i++) {
var subNode = node.childNodes[i];
//如果子节点是元素类型就放到数组中
if (subNode.nodeType == 1) {
arr.push(subNode);
//以当前子节点作为新的父节点继续递归
getChildNodes(subNode, arr);
}
}
}
window.onload = function () {
var arr = [];
var div = document.getElementById('div');
getChildNodes(div, arr);
console.log(arr);
}
2.9.3 jQuery实例化过程
$(function(){
// var ret = $('.active');
// console.dir(ret);
// ret.html('123').css('backgroundColor','green');
// var aDiv = document.getElementsByTagName('div')[0];
// console.dir(aDiv);
// // ret[0];
// console.log(ret.get(0) === aDiv);
function jQuery(selector){
return new jQuery.prototype.init(selector);
}
jQuery.prototype = {
constructor : jQuery,
html : function(){
console.log(123);
return this;
},
css : function(){
console.log(456);
return this;
},
init : function(selector){
// 实现选择器功能
// div .active #div1 div span .active div span
// Sizzle
var aDiv = document.getElementsByTagName(selector);
// 把每一个div都放到this中,那么this就是一个类数组
[].push.apply(this,aDiv);
this.length = aDiv.length;
}
}
jQuery.prototype.init.prototype = jQuery.prototype;
var obj = jQuery('div');
obj.html('123').css(456);
// obj.html('hello').css();
$('div').css('width');//获取某个样式值
$('div').css('width','100px');//设置样式值
$('div').css({
width : '100px',
height : '100px'
});
$('div').css(['width','height']);//{width : 100px,height : 100px}
});
//待整理
2.10 作用域与闭包
2.10.1 作用域
作用域:指的是变量的作用范围。
- 全局作用域
- 函数作用域
- js没有块级作用域
作用域链:链是一个对象列表(list of objects) ,用以检索上下文代码中出现的标识符(identifiers) 。标示符可以理解为变量名称、函数声明和普通参数。作用域链包括活动对象和父级变量对象。
- 函数内层作用域可以访问外层作用,但是反过来不可以。
2.10.2 预解析
JavaScript解析器在执行代码的时候分为两个阶段:
- 预解析
- 全局预解析(所有的变量和函数声明都会提前;同名的函数和变量函数的优先级高)
- 函数内部预解析(所有的变量、函数和形参都会预解析,优先级:函数 > 形参 > 变量)
- 从上到下逐行执行
先预解析全局作用域,然后执行全局作用域中的代码,在执行全局代码的过程中遇到函数调用就会先进行函数预解析,然后再执行函数内的代码。
2.10.3 闭包
闭包是一系列代码块(在ECMAScript中是函数),并且静态保存所有父级的作用域。通过这些保存的作用域来搜寻到函数中的自由变量。
当一个函数在自身函数体内需要引用一个变量,但是这个变量并没有在函数内部声明(或者也不是某个参数名),那么这个变量就可以称为自由变量[free variable]。
闭包:
- 封闭的区域
- 函数的嵌套形成闭包(内层函数和内层函数所处的作用域)
- 闭包可以操作函数内部的变量(间接的)
闭包的作用:
- 可以缓存中间状态值
- 延长变量的生命周期
var arr = [];
for (var i = 0; i < 3; i++) {
arr[i] = (function(num){
return function(){
console.log(num);
}
})(i);
}
arr[0](); //0
arr[1](); //1
arr[2](); //2
闭包的应用:
onload = function(){
var aInput = document.getElementsByTagName('input');
for (var i = 0; i < aInput.length; i++) {
// aInput[i].onclick = (function(){
// var num = 0;
// return function(){
// ++num;
// console.log(num);
// }
// })();
aInput[i].onclick = function(){
this.num?++this.num:this.num=1;
console.log(this.num);
console.dir(this);
}
}
}
2.10.4 对象排序
function sortFn(sortName){
return function(a,b){
var v1 = a[sortName];
var v2 = b[sortName];
if(v1 > v2){
return 1;
}else if(v1 < v2){
return -1;
}else{
return 0;
}
}
}
2.11 事件
2.11.1 函数相关属性补充
- arguments 表示实参的集合
- length 形参的个数
- caller 函数的调用者
- name 函数的名称
- arguments.callee 表示函数本身,但是不推荐使用
2.11.2 事件处理机制
- 浏览器本身是单线程还是多线程?多线程(多进程)
- 页面标签的渲染
- 网络通信
- 解析js的运行
- js的运行是单线程的
- 事件队列(队列中放什么?任务(实际上就是函数))
- 定时函数(延时时间到了)
- 事件函数(对应的事件触发)
- Ajax的回调函数(接收到服务器完整的数据(readyState值发生变化的时候))
- 事件队列中任务执行的条件:
- 主线程空闲
- 满足任务的触发条件
2.11.3 事件绑定方式
-
行内绑定
<div onclick="fn3();"> <div onclick="fn2();"> <div onclick="fn1();">点击</div> </div> </div>
-
给DOM元素直接绑定 btn.onclick
div.onclick = function(){ console.log(1); }
-
addEventListener / attachEvent
div.addEventListener('click',function(){ console.log(11); },false)
2.11.4 阻止冒泡与阻止默认行为
- 在原生js中,return false只能阻止默认行为,不能阻止冒泡;只能阻止btn.onclick这种方式绑定的事件,不能阻止addEventListener绑定的事件。
- 在jQuery中,return false既可以阻止冒泡也可以阻止默认行为。
2.11.5 自定义事件
-
注册事件
function addEvent(obj,type,fn){ obj.arrs = obj.arrs || {}; obj.arrs[type] = obj.arrs[type] || []; obj.arrs[type].push(fn); } var obj = {}; addEvent(obj,'abc',function(){ console.log('abc'); }); addEvent(obj,'abc',function(){ console.log('abc1'); }); addEvent(obj,'hi',function(){ console.log('hi'); });
-
触发事件
function fireEvent(obj,type){ var fnList = obj.arrs[type]; for (var i = 0; i < fnList.length; i++) { fnList[i](); } } fireEvent(obj,'hi');
2.12 正则
2.12.1 正则相关API
-
正则的API:
-
test
var reg = /\d/; console.log(reg.test('123'));
-
exec
var str = 'adsfasdf123asdfasdf21312sfdsadfad'; var reg = /\d+/g; // var ret = reg.exec(str); // console.log(ret); var result = null; while((result = reg.exec(str)) != null) { console.log("Matched `" + result[0] + "' at position " + result.index + " next search begins at position " + reg.lastIndex); }
-
-
字符串API:
-
search:查询匹配字符串的索引
var str = 'dsdaf123asdfasdf'; console.log(str.search('123')); console.log(str.search(/\d+/));
-
match
//从字符串中找出数字 var str = '1212adsfasdf123asdfasd234fqewrqew3434rqwerw54qerqwerqwer21321'; console.log(str.match(/\d+/g));
-
split
var str = 'zhangsan:12:male;lisi:13:female'; var arr = str.split(';'); for (var i = 0; i < arr.length; i++) { var item = arr[i].split(':'); console.log(item[0]); console.log(item[1]); console.log(item[2]); } var str = 'asdfasdfasdf123asdfas4545dfads'; var arr = str.split(/\d+/g); console.log(arr);
-
replace
var str = 'adsfasdf123asdfasdf21312sfdsadfad'; str = str.replace(/\d+/g,'***'); console.log(str);
-
在非全局匹配模式下,
str.match(reg)
和reg.exec(str)
的作用等效。
2.12.2 正则的规则
- 元字符:
三、面试题
3.1 ==和===相关的比较问题
[] ==![] //true
[1] == [1] //false
[1] == ![1] //false
比较规则:
- 对象之间的比较是内存地址的比较
- 单个空对象转成布尔值是true
- 空数组与布尔值的比较会转换成数值的比较(空数组会转化成0)
- 转成false的情况:
false null '' undefined 0 NaN
3.2 in使用中的问题
3.2.1 变量声明时的问题
console.log('a' in window); //true
if('a' in window){
var a = 123;
console.log(a);
}
console.log('a' in window); //false
if('a' in window){
a = 123;
console.log(a);
}
- 不使用var不会预解析,但是也会向window中添加属性。
3.2.2 window中的undefined
console.log(a in window); //true
if(a in window){
var a = 123;
console.log(a);
}
- 不加引号,a是undefined,window中本身就有一个属性undefined,并且undefined的值也是undefined。
3.3 以下代码的输出结果是什么?
var a = {n:1};
var b = a;
a.x = a = {n:2}; //运算符的优先级 .的优先级最高 赋值操作是从右向左运算的
console.log(a.x); //undefined
console.log(b.x); //{n:2}
考点:
- 基本类型和引用类型
- 引用类型变量和对象属性(在内存实际上就是内存地址)
- 运算符的优先级
.
的优先级最高 ,赋值操作是从右向左运算的
3.4 下列代码输出结果是什么?
var a = {name:'zhangsan'};
var b = {age : 26};
var arr = [];
arr[a] = 123;
arr[b] = 456;
console.log(arr);//Array[0] -->[object Object]:456
数组也是对象
对象属性的访问方式
Object的toString方法作用:把构造函数转成这种形式的字符串:[object Object]
3.5 跨域解决方案有哪些?
- jsonp
- cors
- 反向代理
- flash插件
3.6 DNS解析过程是什么?
- DNS Domain Name System : 负责域名和IP地址的映射关系
- 域名解析的规则:先去本机的hosts文件中查找IP,如果没有找到,就去公网的DNS服务器查找,如果还没有找到,那就无法上网;如果在hosts文件中找到了,那么就返回ip,就不再去公网查找了
3.7 前端有多少种方式可以发送请求?
1)浏览器地址直接输入url
2)表单的action属性
3)a标签href属性
4)img的src属性
5)script的src属性
6)link标签的href属性
7)iframe的src属性
8)Ajax发送请求
9)postMessage h5新的API
10)flash插件也可以
11)location.href
url的规范格式:
scheme://host:port/path?query#fragment
echeme 表示协议 http https ftp file ssh
host 表示域名或者IP地址
port 端口 用来确定计算机上的具体某个网络应用程序
path 域名之后,?之前的内容 /abc/qqq/rrr
query 查询字符串,作用是向服务器传递数据,格式:键=值&键=值
fragment hash 锚点 定位页面的某一部分