1、基本常识
浏览器的组成:1)shell部分
2)内核部分:(1)渲染引擎(语法规则和渲染)
(2)js引擎
(3)其他模块
JS特点:1)解释性语言
2)单线程(同步、异步)
3)ECMA标注
JS执行队列:轮转时间片(类似吃法)
主流浏览器 内核
IE trident
Chrome webkit/blink
firefox Gecko
Opera presto
Safari webkit
2、基本语法
1、数据类型:1)原始值:Number Boolean String undefined null
2)引用值:array Object function ...date RegExp
2、"+"的作用:1)数学运算 2)字符串链接:任何数据类型加字符串都等于字符串
3、逻辑运算符: && || !
3.1 &&运算符:只有前后两个表达式的情况,如果第一个表达式的结果为true,那么直接返回第二个表达式的结果。如果第一个表达式的结果为false时,直接返回第一个表达式的值(undefined、null、NaN、""、0、false的布尔值为false)。
具体应用:短路语句
var data = ...;
data && function(data)
3.2 ||运算符:只有前后两个表达式的情况,如果第一个表达式的结果为true,那么直接返回第一个表达式的结果。遇见true就返回。
具体应用:浏览器兼容问题(IE浏览器和非IE浏览器的兼容)
div.onclick = function(e) {
var event = e || window.event;
}
3.3 !运算符:转换成布尔值再取反
4、if else for
通过几个实例来了解。
计算2的N次幂
var n = parseInt(window.prompt('输入:'));
var count = 1;
if (n == 0) { console.log(count); } else {
for (var i = 1; i <= n; i++) { count *= 2; }
console.log(count); }
递归计算N的阶乘
function factorial(number) {
if (number == 0 || number == 1) { return 1; }
else { return number * factorial(number - 1); }
}
斐波那契额数列
var n = parseInt(window.prompt('输入:'));
var first = 1,
second = 1,
third;
if (n == 1 || n == 2) { console.log("1"); }
else if (n >= 3) {
for (var i = 0; i < n - 2; i++)
{third = first + second;
first = second;
second = third;}
console.log(third); }
反向输出一个三位数
var num = window.prompt("输入:");
var str = "";
for (var i = num.length - 1; i >= 0; i--){
str +=i; }
console.log(str);
条件语句补充
switch case
var date = window.prompt('input');
switch(date) {
case "monday":
case "tuesday":
case "wednesday":
case "thursday":
case "friday":
console.log("working");
break;
case "saturday":
case "sunday":
console.log("relaxing");
break;
}
break:终止循环
continue:终止本次循环,进行下一个循环
5、typeof操作符:返回数据是什么类型的 类型转换
5.1 六种数据类型:number、string、boolean、undefined、object、function
5.2 显示类型转化
1)String(mix)、Boolean(mix)、Number(mix):把对象转换成字符串/布尔/数字类型
2)parseInt(string,radix):1)把对象转换成整型数字
2)有两个参数的时候,以目标进制(第二个参数)为基底,转化成10进制
3)parseFloat(只有一个参数):把对象转换成浮点类型数字
4)toString(radix):1)把对象转换成字符串,用法与String不同 xxx.toString();
undefined和null不能用toString方法
2)以10进制为基底,转化成目标进制(参数)
5.3隐式类型转化(内部都是调用显示类型转化)
1)isNaN():判断一个数是不是NaN,返回boolean值(调用Number转化成数字再判断)
2)++/--/+/-(一元正负):转化成数字类型(调用Number转化成数字)
3)+号:当加号两边有一个是string类型,就会调用String,把另一个也转化成字符串类型
4)+-*/:调用Number转化成数字类型
5)&& || !:调用boolean进行类型转化
6)== != < > <= >=:返回boolean值
5.4特殊:undefined == null 返回true NaN == NaN 返回false(NaN跟谁都不等)
5.5typeof返回的数据类型的类型是String类型
6、函数
6.1函数声明:function test() {}
6.2函数表达式(匿名函数表达式):var demo = function () {}
arguments是一个存放实参的数组
实现累加
function sum() {
var result = 0;
for (var i = 0; i < arguments.length; i++) {
result += arguments[i]; }
console.log(result);
return; //1、终止函数 2、返回值 }
sum(1, 2, 3, 4, 5, 6, 7, 8, 9);
7、作用域
7.1 函数的属性:[[scope]],里面存放的是函数的作用域,是一个隐式的属性
7.2 执行期上下文(AO和GO):函数的每次执行都会产生一个执行期上下文,函数执行完毕后,执行期上下文销毁
7.4 作用域链:[[scope]]中所储存的执行期上下文对象的集合,呈链式链接
举例
function a() {
function b()
} {
var b = 234;
}
var a = 123;
b();
var glob = 100;
a();
a函数被定义:a.[[scope]] --> 0 : GO{}
a函数执行:a.[[scope]] --> 0 : AO{}
1 : GO{}
b函数被定义:b的[[scope]]就是a的[[scope]]
b函数执行: b产生一个AO{} 放在作用域链的顶端
0 : b.AO{}
1 : a.AO{}
2 : a.GO{}
function a() {
function b() {
function c() {}
c();
}
b();
}
a();
a函数被定义:a.[[scope]] --> 0 : GO
a函数执行: a.[[scope]] --> 0 : a.AO a函数执行完,销毁a.AO,再次执行a函数,new a.AO
1 : GO
b函数被定义:b.[[scope]] --> 0 : a.AO
1 : GO
b函数执行: b.[[scope]] --> 0 : b.AO b函数执行完,销毁b.AO,再次执行b函数,new b.AO
1 : a.AO
2 : GO
c函数被定义: c[[scope]] --> 0 : b.AO
1 : a.AO
2 : GO
c函数执行: c[[scope]] -->0 : c.AO c函数执行完,销毁c.AO,再次执行c函数,new c.AO
1 : b.AO
2 : a.AO
3 : GO
8、预编译
8.1 预编译是发生在函数执行的前一刻
函数声明 整体提升
变量 声明提升(提升 = 优先执行)
8.2 任何变量未经声明,直接赋值,此变量就为全局对象所有
8.3 一切声明的全局变量,都是window的属性(window就是全局的域)
8.4 预编译的步骤
8.4.1 1)创建AO对象
2)找形参和变量声明,将变量和参数名作为AO的属性名,值为undefined
3)将实参值和形参统一
4)在函数体里面找函数声明,值赋予函数体
举例:
function fn(a) {
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
var b = function() {}
console.log(b);
}
fn(1);
AO {
a : undefined, -->1-->function a (){}-->123
b ; undefined -->function (){}
}
function test(a, b) {
console.log(a);
c = 0;
var c;
a = 3;
b = 2;
console.log(b);
function b() {}
function d() {}
console.log(b);
}
test(1);
AO {
a : undefined,-->1 --> 3
b : undefined,-->function b () {}-->2
c : undefined,-->0
d : undefined-->function d () {}
}
function test() {
console.log(a); //function a () {}
console.log(b); //undefined
var b = 234;
console.log(b); //234
a = 123;
console.log(a); //123
function a() {}
var a;
b = 234;
var b = function() {}
console.log(a); //123
console.log(b); //function () {}
} test(1);
console.log(test);
function test(test) {
console.log(test);
var test = 234;
console.log(test);
function test() {}
}
test(1);
var test = 123;
console.log(test);
GO {
test: undefined-- > function test(test) {
console.log(test); //function test () {}
var test = 234; -- > 123
console.log(test); //234
function test() {}
}
}
AO {
test: undefined-- > 1-- > function test() {}-- > 234
}
a = 100;
console.log(a);//100
function fn () {
console.log(a);//undefined
a = 200;
console.log(a);//200
var a = 300;
console.log(a);//300
}
fn();
var a;
GO {
a : undefined--> 100
}
AO {
a : undefined --> 200 --> 300
}
百度面试题
function bar() {
return foo; //直接返回,后面的赋值语句不执行
foo = 10;
function foo() {}
var foo = 11;
}
console.log(bar());
AO {
bar : undefined --> function foo () { ....}
}
百度面试题
console.log(bar());
function bar() {
foo = 10;
function foo() {}
var foo = 11;
return foo;
}
AO {
bar : undefined --> 10 --> function foo () {...} --> 11
}
a = 100;
function demo(e) {
function e () {}
arguments[0] = 2;
console.log(e);//2
if (a) {//a = undefined 不执行 //if 里面不允许声明function
var b = 123;
function c() {}
}
var c;
a = 10;
var a;
console.log(b);//undefined
f = 123;
console.log(c);//undefined
console.log(a);//10
}
var a ;
demo(1);
console.log(a);//100 这里的a是全局变量
console.log(f);//123
GO {
a : undefined --> 100
demo : undefined --> function () {}
f :undefined --> 123
}
AO {
e : undefined --> 1 -->function e () {} --> 2
c : undefined
b : undefined
a : undefined --> 10
}
9、立即执行函数
9.1 目的:1)防止浪费空间,执行一次就立即释放
2)针对初始化功能的函数
9.2 形式:建议用第一种形式
1)(function () {}())
2)(function () {})()
几点说明:1.只有表达式才能被执行符号执行(函数表达式可以被执行,但是函数声明不可以)
2.被执行符号执行的表达式,会自动忽略函数的名称
3.只要能变成表达式,就能被执行符号执行
可被执行的例子:
var num = (function(a, b) {//返回的值给了num
var c = a + b;
return c;
}(1, 2));
不可被执行的例子:
function test() {
var a = 123;
console.log(a);
} //函数声明,所以它不能被执行符号执行
test();
面试题
说明:逗号(,)操作符,(2, 3)先看前面的表达式,如果前面的表达式需要计算的先计算,然后再计算后面的表达式,如果后面的表达式需要计算的话,就计算后面的表达式,都计算完之后,把后面的表达式的计算结果返回回去。
var f = (
function f() {
return "1";
},
function g() {
return 2;
}
)();
console.log(typeof f);
10、闭包
10.1 闭包的形成:两个或多个函数互相嵌套,把里面的函数保存到了外面函数的外部,形成闭包。
10.2 闭包的效果:让局部的函数保存到全局
10.3 闭包的危害:闭包会导致原有的作用域链不被释放,造成内存泄漏
10.4 闭包的作用:
1) 实现公有变量(函数累加器)
function add() {
var count = 0;
function demo() {
count++;
console.log(count);
}
return demo;//将demo函数保存到add函数外部
}
var counter = add();
counter();
counter();
执行几次,就进行几次的累加。
2)可以做缓存(存储结构)
function eater() {
var food = "";
var obj = {
eat: function() {
console.log("i am eating " + food);
food = "";
},
push: function(myFood) {
food = myFood;
}
}
return obj; //返回了eat和push,都和eater形成了闭包
}
var eater1 = eater();
eater1.push('banana');
eater1.eat();
3)可以实现封装,属性私有化
4)模块化开发,防止污染全局变量
闭包的例子:
按顺序打印出0~9
function test() {
var arr = []; //arr数组里存储了10个函数
for (var i = 0; i < 10; i++) {
arr[i] = function() {
document.write(i + " "); //赋值语句,这个函数在这里不会执行,只有在执行函数的时候才会看函数内部的内容
}
}
return arr;
}
var myArr = test();
for (var j = 0; j < 10; j++) {
myArr[j](); //在这里执行 arr[i] = function() { document.write (i + " ");},执行的时候去判断i的值
}
以上代码的显示结果不正确,通过立即执行函数来解决
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
(function(j) {
arr[j] = function() {
document.write(j + " ");
}
}(i));
}
return arr;
}
var myArr = test();
for (var j = 0; j < 10; j++) {
myArr[j]();
}
11、对象
var ZhangSan = {
name: "ZhangSan",
age: 22,
sex: "male",
health: 100,
somke: function () {
console.log("i am somking!");
this.health--;
},
ball: function () {
console.log("i am playing ball");
this.health++;
}
}
ZhangSan.apet = "计算机系"; //添加属性
console.log(ZhangSan.sex); //查看属性
ZhangSan.age = 21; //修改属性
delete ZhangSan.sex; //删除属性
当一个对象的属性没声明就访问,会返回undefined
11.1 对象的创建方法
1)var obj = {} plainObject 对象字面量/对象直接量
2)构造函数创建方法:(1)系统自带的构造函数
new Object();Arrary();Number();Boolean();String();Date();
var obj = new Object();<==>var obj = {};
(2)自定义
function Person() {}
var person = new Person();
11.2 构造函数命名规则:大驼峰式命名规则 TheFirstName
函数命名规则 小驼峰式命名规则 theFirstName
11.3 自定义构造函数
构造函数内部原理(new)
(1)在函数体最前面隐式的加上this = {}
(2)执行 this.xxx = xxx;
(3)隐式的返回this
function Car(color) {
//var this = {
name : "xxx";
height : "xxx";
...
};
this.color = color;
this.name = "BMW";
this.height = "1400";
this.lang = "4900";
this.weight = 1000;
this.health = 100;
this.run = function () {
this.health--;
}
//return this;
}
var car = new Car("red");
var car1 = new Car("yellow");
function Person(name, height) {
//var this = {}
this.name = name;
this.height = height;
this.say = function () {
console.log(this.say);
}
return 123;//除了对象类型,返回其他任何类型的原始值都会转化成对象类型
//return this;
}
console.log(new Person('xiaowang', 180).name);
var person1 = new Person('xiaoliu', 175);
几点说明:1)构造函数特点:命名大驼峰式
2)构造函数创建对象必须通过new关键字
12、包装类
12.1 原始值不可能有属性和方法,对象才有属性和方法(对象包括object、数组、function)
12.2 原始值不能操作属性,只能通过包装类操作
var num = 123;//这个num是原始值,是没有属性和方法的
var num = new Number(123);//数字对象可以操作属性,也可以进行运算,但是在运算之后就变成了数字类型的了
同样的还有String和Boolean
var str = new String('abcd');//字符串对象
var bol = new Boolean('true');//布尔对象
通过包装类操作之后,可以操作以上变量的方法
num.abc = "abc";
str.abcd = "abcd";
undefined和null不可以
12.3 隐式的发生包装类
var num = 4;
num.len = 3;
//隐式发生 new Number(4).len = 3; 在完成之后会自动删除len(delete)
console.log(num.len);
包装类的例子:
var str = "abc";
str += 1; //'abc1'
var test = typeof (str); //test = "String"
if (test.length == 6) {
test.sign = "typeof的返回结果可能为String";
//new String(test).sign = 'xxx' 调用包装类赋值给原始值
}
//重新new String(test).sign 但是没有赋值
console.log(test.sign);//undefined