JavaScript学习笔记

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);

你可能感兴趣的:(JavaScript学习笔记)