1.JavaScript基本数据类型
number typeof -> number
boolean typeof -> boolean
string typeof -> string
undefined typeof -> undefined
null typeof -> object
2.全局变量/局部变量
全局变量:
1.定义在函数外面的变量,称为全局变量;很少用
2.定义在函数内部,没有使用var声明的变量,称为全局变量。
局部变量:
方法内部,用var声明的变量,称为局部变量。
3.使用Array模拟栈结构
var arr = [1, 2, 3];
arr.push(true, false); //push可以向数组尾部添加一个或者多个元素,返回新增元素后数组的长度
arr.pop(); //从数组尾部移除一个元素,返回移除的元素 false
4.使用Array模拟队列结构
var arr = [1, 2, 3];
arr.push(true); //数组【1, 2, 3, true】
arr.shift(); //从数组头部移除一个元素,返回移除元素 1 数组【2, 3, true】
//unshift(1, 2); 向数组头部添加一个或者多个元素
5.数组 splice/slice
/**
* splice
* 第一个参数:起始位置
* 第二个参数:截取的个数(没有此参数表示截除起始位置后面的所有元素)
* 第三个参数及以后:追加的新元素(没有此参数表示截除起始位置后n(参数2的值)个元素)
*/
var arr = [1, 2, 3, 4, 5];
arr.splice(1, 2, 3, 4, 5);
console.log(arr); //[1, 3, 4, 5, 4, 5]
/**
* slice,不操作数组本身
* 第一个参数:起始位置
* 第二个参数:结束位置(不包含结束的元素)
*/
var arr = [1, 2, 3, 4, 5];
var result = arr.slice(2, 4);
console.log(arr); //[1, 2, 3, 4, 5]
console.log(result); //[3, 4]
6.数组 concat/join
/**
* concat,合并两个数组,生成一个新的数组,不操作数组本身
*/
var arr1 = [1, 2, 3, 4, 5];
var arr2 = [true, false]
var result = arr1.concat(arr2);
console.log(arr1); //[1, 2, 3, 4, 5]
console.log(arr2); //[true, false]
console.log(result); //[1, 2, 3, 4, 5, true, false]
/**
* join,用指定连接符链接数组所有元素,不操作数组本身
* 第一个参数:起始位置
* 第二个参数:结束位置(不包含结束的元素)
*/
var arr1 = [1, 2, 3, 4, 5];
var result = arr1.join("-");
console.log(arr1); //[1, 2, 3, 4, 5]
console.log(result); //1-2-3-4-5
7.数组 sort/reverse
var arr = [5, 2, 1, 4, 3];
/**
* sort,正序排列数组
*/
arr.sort();
console.log(arr);//[1, 2, 3, 4, 5]
var arr1 = [10, 2, 4, 1, 7];
arr1.sort();
console.log(arr1); //[1, 10, 2, 4, 7] 按照字符串来值比较
//解决方案
arr.sort(function (value1, value2) {
if(value1 < value2){
return -1;
}else if(value1 > value2){
return 1;
}else{
return 0
}
});
/**
* reverse,倒序排列数组,不是按照元素大小,而是按照元素索引倒序
*/
arr.reverse();
console.log(arr); //[3, 4, 1, 2, 5]
8.数组新特性-迭代(every/filter/forEach/map/some)
every:对数组的每一个元素执行一次函数调用,都返回true,则返回true,若有一个返回false,则返回false
var arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var result = arr.every(function (value, index, array) {
return value > 2;
});
console.log(result); //false
filter:对数组的每一个元素执行一次函数调用,函数执行结果为false,则把该元素过滤掉,最后返回过滤后的结果
var arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var result = arr.filter(function (value, index, array) {
return value > 2;
});
console.log(result); //[3, 4, 5, 4, 3]
forEach:对数组的每一个元素执行一次函数调用,对每个元素进行操作,无返回
var arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
arr.forEach(function (value, index, array) {
console.log(value); //遍历输出数组的每一个元素
})
map:对数组的每一个元素执行一次函数调用,返回函数调用后的结果
var arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var result = arr.map(function (value, index, array) {
return value * 2;
});
console.log(result); //[2, 4, 6, 8, 10, 8, 6, 4, 2]
some:对数组的每一个元素执行一次函数调用,若有一个返回true,则返回true,如果都返回false,则返回false
var arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var result = arr.some(function (value, index, array) {
return value >= 5;
});
console.log(result); //true
reduce:从前往后遍历,preValue保留上一次函数运算的结果
var arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var result = arr.reduce(function (preValue, curValue, index, array) {
return preValue + curValue;
});
console.log(result); //25 (1+2+3+4+5+4+3+2+1)
reduceRight:与reduce相反,从后往前遍历
9.Object基本方法
每一个object对象都会有一下属性和方法
--Constructor:构造函数,保存着用于创建当前对象的函数;
--hasOwnProperty(propertyName):用于检测propertyName属性是否再当前实例中存在(不包括原型);
--isPrototypeOf(Object):检查传入的对象是否是另外一个对象的原型;
--propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for iny语句来枚举;
--toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应;
--toString():返回对象的字符串显示;
--valueOf():返回对象的字符串、数值、布尔显示;
10.函数的3中定义方式
//函数3中定义方式
//1.function语句式,这种方法定义的函数会被提前提取编译
function test1() {
console.log("function语句式");
}
test1(); //function语句式
//2.函数的直接量
var test2 = function () {
console.log("函数的直接量");
}
test2(); //函数的直接量
//3.Function构造函数式,有动态性,拥有顶级作用于
var test3 = new Function("a", "b", "console.log(a+b);");
test3(10, 20); //30
//函数作用于概念
var k = 1;
function t1() {
var k = 2;
//function test() {return k;} 2
//var test = function () {return k;}; 2
//var test = new Function("return k;"); 1
alert(test());
}
t1();
11.function中的arguments
每个function对象中都自带一个arguments对象,该对象存储了该function的实际参数列表,arguments是一个数组对象,通过 方法名.length 可以获取到方法申明的参数列表
arguments.callee 指向函数自己本身,类似递归的时候推荐使用,仔细看下面例子
function fact(num) {
if(num <= 1) {
return 1;
} else{
return num * fact(num - 1);
}
}
console.log(fact(5)); //120
var F = fact;
console.log(F(5)); //120
fact = null;
console.log(F(5)); //Uncaught TypeError:fact is not a function
//标准定义
function fact(num) {
if(num <= 1) {
return 1;
} else{
return num * arguments.callee(num - 1);
}
}
12.this
this对象是再运行时基于函数的执行环境绑定的,在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。也就是说,this关键字总指向调用者。
//this总是指向调用者
var k = 10;
function test() {
this.k = 20;
}
console.log(test.k); //undefined,因为test函数还未被调用
test(); //此处相当于window.test(),所以this指向的时window
console.log(test.k); //undefined
console.log(k); //20,相当于window.k
13.call/apply
call/apply这两个方法是每一个function自带的成员方法,他们的作用一样,都是为function指定执行作用域,区别在于,call接受的参数是以参数列表的形式接受,而apple是将参数封装成数组进行接受的。
var color = "red";
var obj = {color:"blue"};
function add(num1, num2) {
console.log(this.color + ":" + (num1 + num2));
}
function call1(obj, num1, num2) {
add.call(obj, num1, num2);
}
function apply1(obj, num1, num2) {
add.apply(obj, [num1, num2]);
}
call1(this, 10, 20); //red:30
apply1(this, 20, 40); //red:60
call1(obj, 10, 20); //blue:30
apply1(obj, 20, 40); //blue:60
14.执行环境
执行环境(execution context)是javascript中最为重要的一个概念。执行环境定义了变量或者函数有权访问的其他数据,决定了他们各自的行为。每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
15.作用域链
每一个函数都有自己的执行环境,当执行流进一个函数时,韩式的环境就会被推入 一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返还给之前的执行环境。当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
16.块级作用域
JavaScript没有跨级作用于的概念,如下例
function test() {
for(var i = 0; i <= 5; i++){
console.log(i);
}
console.log(i); //6,此处依然能访问到i
}
test();
我们可以通过()()的方式模拟块级作用域,
function test() {
(function () {
for(var i = 0; i <= 5; i++){
console.log(i);
}
})();
console.log(i); //Uncaught ReferenceError: i is not defined
}
17.闭包
闭包;一个函数可以访问另外一个函数作用域中的变量,起到保护变量的作用
自己理解:一个函数返回另一个函数,返回的函数有外部作用域的访问权限
var name = "abc";
var obj = {
name : "efg",
getName: function () {
return function () {
return this.name;
}
}
};
/**
* 这个方法可以拆解理解的
* var fun = obj.getName() = function(){return this.name}
* fun() = window.fun()
* 所以会返回外部作用于的name
*/
console.log(obj.getName()()); //abc
//返回obj.name解决方案
var obj1 = {
name:"efg",
getName:function () {
var o = this;
return function () {
return o.name;
}
}
};
console.log(obj1.getName()()); //efg
18.面向对象
18.1.创建面向对象的3种方式
//1.普通方法调用
function createPerson(name, age, sex) {
var obj = {};
obj.name = name;
obj.age = age;
obj.sex = sex;
return obj;
}
var person = createPerson("zhangsan", 20, "男");
console.log(person.name + ":" + person.age + ":" + person.sex); //zhangsan:20:男
//2.构造函数创建,这种方式,函数名都是首字母大写
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var person = new Person("lisi", 25, "男");
console.log(person.name + ":" + person.age + ":" + person.sex); //lisi:25:男
//3.通过call/apply的形式调用
var person = {};
Person.apply(person, ["wangwu", 30, "女"]);
console.log(person.name + ":" + person.age + ":" + person.sex); //wangwu:30:女
18.2.原型(prototype)
原型(prototype);每一个函数对象都有一个prototype属性,该属性是一个指针,指向一个对象,这个对象的用途是将特定的属性和方法封装起来,共实例对象共享使用。
function Person() {}
Person.prototype.name = "zhangsan";
Person.prototype.age = 20;
Person.prototype.sayName = function () {
console.log(this.name);
};
var p1 = new Person();
p1.name = "lisi";
var p2 = new Person();
p2.name = "wangwu";
p1.sayName(); //lisi
p2.sayName(); //wangwu
console.log(p1.sayName == p2.sayName); //true
console.log(Person.prototype.isPrototypeOf(p1)); //true 判断是否是某对象的原型
console.log(Object.getPrototypeOf(p1)); //返回Person.prototype对象
构造函数,原型对象,实例对象三者的关系
1.构造函数.prototype = 原型对象
2.原型对象.constructor = 构造函数(模板)
3.原型对象.isPrototypeOf(实例对象) 判断实例对象的原型是否是当前对象
18.3.原型的使用
18.3.1.简单原型模式
该模式要遵循的原则式创建对象必须放在原型后面,否则创建的对象无法访问到原型内的属性或方法
function Person() {}
Person.prototype = {
name:'z3',
age:20,
sayName:function () {
console.log(this.name);
}
}
//定义Person.prototype的构造函数为Person,使用这种方法指定构造函数,for-in的时候无法获取到constructor
Object.defineProperty(Person.prototype, "constructor", {
enumerable:false,
value:Person
})
var p = new Person();
p.sayName(); //z3
console.log(Person.prototype.constructor); //function Person(){}
18.3.2.组合使用构造函数和原型模式
由于上述方式所有属性/方法对所有对象都是共享的,有一个明显的缺点,当属性是应用数据类型时,A对象对这个数组进行了push操作,B对象去访问时得到的时A对象操作后的结果。通过组合使用构造函数和原型模式可以有效解决这个问题
function Person(name, age, friends) {
this.name = name;
this.age = age;
this.friends = friends;
}
Person.prototype = {
constructor : Person,
sayName : function () {
console.log(this.name);
}
}
var p1 = new Person('z1', 20, ["aaa", 'bbb']);
p1.friends.push('zzz');
var p2 = new Person('z2', 22, ['ccc', 'ddd']);
p2.friends.push('yyyy');
p1.sayName(); //z1
p2.sayName(); //z2
console.log(p1.friends); //["aaa", "bbb", "zzz"]
console.log(p2.friends); //["ccc", "ddd", "yyyy"]
18.3.3.动态原型模式
该模式把所有的属性和方法封装到一起,代码更加简洁,如下方式定义,sayName只会被创建一次
function Person(name, age) {
this.name = name;
this.age = age;
if(typeof this.sayName != "function"){
Person.prototype.sayName = function () {
console.log(this.name);
}
}
}
var p1 = new Person('z1', 20);
var p2 = new Person('z3', 22);
p1.sayName(); //z1
p2.sayName(); //z3
18.3.4.稳妥构造函数式
适合在非常安全的环境中使用,他没有公共属性,不能使用this对象,同时创建的时候也不使用new,这种方法类似与java中的private,所有属性都无法通过obj.xxx的方式获取,必须通过对应的方法获取。
function Person() {
var obj = {};
var name = 'z1';
var age = 20;
obj.sayName = function () {
console.log(name);
}
return obj;
}
var p = Person();
p.sayName(); //z1
19.继承
JavaScript通过让子类对象的原型指向父类对象的方式实现继承
19.1.原型继承
特点:即继承了父类的模板,又继承了原型对象
function Sup(name){
this.name = name;
}
function Sub(age) {
this.age = age;
}
var sup = new Sup('z3');
Sub.prototype = sup;
var sub = new Sub(20);
console.log(sub.name); //z3
console.log(sub.age); //20
console.log(sup.isPrototypeOf(sub)); //true
console.log(Sub.prototype.constructor); //function Sup(name){this.name = name;}
console.log(sub instanceof Sub); //true
console.log(sub instanceof Sup); //true
19.2类继承
特点:只继承模板,不继承原型对象,又称借用构造函数方式继承
function Person(name, age) {
this.name = name;
this.age = age;
}
function Boy(name, age, sex) {
Person.call(this, name, age);
this.sex = sex;
}
var boy = new Boy('z3', 20, '男');
console.log(boy.name + " : " + boy.age + " : " + boy.sex); //z3 : 20 : 男
console.log(boy instanceof Boy); //true
console.log(boy instanceof Person); //false
console.log(Boy.prototype.constructor); //Boy(name, age, sex) {Person.call(this, name, age);this.sex = sex;}
19.3混合继承
function Person(name, age) {
this.name = name;
this.age = age;
}
function Boy(name, age, sex) {
Person.call(this, name, age);
this.sex = sex;
}
Boy.prototype = new Person();
var boy = new Boy('z3', 20, '男');
console.log(boy.name + " : " + boy.age + " : " + boy.sex); //z3 : 20 : 男
console.log(boy instanceof Boy); //true
console.log(boy instanceof Person); //true
console.log(Boy.prototype.constructor); //Person(name, age) {this.name = name;this.age = age; }
20.Ajax
20.1创建XHR
目前Javascript主流的都是通过Ajax技术进行网络请求的,Ajax可以不需要刷新页面的同时与服务器进行交互,提高用户体验,Ajax的核心是XMLHttpRequest,目前主流的浏览器都支持原生的XHR,但是IE7以前使用的是MSXML库中的XHR对象,所以为了兼容性,我们可以通过一下方式获取XHR
function createXHR() {
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
}else if(typeof ActiveXObject != "undefined"){
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
var i, len;
for(i = 0, len = versions.length; i < len; i++){
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
}catch (ex){
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error("No XHR object available");
}
}
20.2同步请求
var xhr = createXHR();
xhr.open("get",
"https://accountv3-api.fclassroom.cn/checkVersion.json?jike-client-from=APP&versionType=21&category=20&versionNo=356",
false);
xhr.send(null);
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
}else{
console.log("Request was unsuccessful : " + xhr.status);
}
20.3异步请求
var xhr = createXHR();
xhr.onreadystatechange = function () {
/**
* readyState
* 0:未初始化
* 1:启动
* 2:发送
* 3:接收
* 4:完成
*/
if(xhr.readyState == 4){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
}else{
console.log("Request was unsuccessful : " + xhr.status);
}
}
}
xhr.open("get",
"https://accountv3-api.fclassroom.cn/checkVersion.json?jike-client-from=APP&versionType=21&category=20&versionNo=356",
true);
xhr.send(null);
20.4Get/Post
get请求与上述方式一样,如果需要为请求添加自己的header,可以通过XHR的setRequestHeader(name,value)进行设置,这个方法的调用必须在open之后,send之前。
post请求可以通过FormData来承载需要提交的数据
var xhr = createXHR();
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
}else{
console.log("Request was unsuccessful : " + xhr.status);
}
}
}
xhr.open("post",
"https://accountv3-api.fclassroom.cn/checkVersion.json",
true);
var formData = new FormData();
formData.append("jike-client-from", "APP");
formData.append("versionType", "21");
formData.append("category", "20");
formData.append("versionNo", "356");
xhr.send(formData);
网友评论