jQuery火箭图标返回顶部代码

JavaScript 是一种面向对象的动态语言,它包含类型、运算符、标准内置( built-in)对象和方法。它的语法来源于 Java 和 C,所以这两种语言的许多语法特性同样适用于 JavaScript。需要注意的一个主要区别是 JavaScript 不支持类,类这一概念在 JavaScript 通过对象原型(object prototype)得到延续(有关 ES6 类的内容参考这里Classes)。另一个主要区别是 JavaScript 中的函数也是对象,JavaScript 允许函数在包含可执行代码的同时,能像其他对象一样被传递。

  • Number(数字)
  • String(字符串)
  • Boolean(布尔)
  • Symbol(符号)(第六版新增)
  • Object(对象) Function(函数)
  • Array(数组)
  • Date(日期)
  • Math(数学对象)
  • RegExp(正则表达式)
  • Null(空)
  • Undefined(未定义)
  • Error(错误)类型 
一 、number详解
Javascript中采用全浮点计算(双精读64位)
注意 !在某些运算中会出错   eg:0.1 0.2 0.30000000000000004
我们也可以使用JavaScript提供的Math内置对象,和 内置函数parseInt();
此外JavaScript还提供了parseFloat(),但是它只支持解析十进制数字
在parseInto("123",10)  //123      -->10的含义是十进制
parseInt("010", 10); //10
parseInt("010");  //  8    如果没有第二个参数,那么以0开头就是八进制  0x开头就是16进制
parseInt("0x10"); // 16
如何把二进制转为整数值?
parseInt("10011",2);
当第一个参数不是数字型字符串 
parseInt("hello", 10); // NaN
NaN是一个特殊值   用它与任何数字计算   结果都是NaN
此外  还有两个特殊值  Infinity  和 -Infinity  (正无穷和负无穷)
用内置函数  isFinite()可以判断一个变量是否为Infinity   -Infinity    NaN
二、字符串
JavaScript中的字符串是一个Unicode字符序列
每一个编码单元由一个 16 位二进制数表示。每一个Unicode字符由一个或两个编码单元来表示。
"hello".charAt(0); // "h"
"hello, world".replace("hello", "goodbye"); // "goodbye, world"
"hello".toUpperCase(); // "HELLO"
"hello".length; // 5
三、其他类型(null 和 undefined)
null的本质是一个空值,必须使用null关键字才能访问
undefined是一个未定义类型的对象(也是一个对象),它表示一个未初始化的值,也就是还没有被分配值。(JavaScript允许声明变量但不对其赋值,一个未被赋值的变量就是undefined类型)
布尔型:(true / false)其他类型对其转化
flase,0,"",NaN,null,undefined都会在JavaScript需要一个布尔值变量的时候隐式转换为false  (其他的都会转化为true)
四、变量
在JavaScript中声明一个变量用var
var a; 
var name = "simon";
在JavaScript中的语句块中  是没有作用域的
五、运算符
JavaScript的算术操作符包括 +-*/% ——求余(与模运算不同)。赋值使用 = 运算符,此外还有一些复合运算符,如 +=-=,它们等价于 x = x op y
+可以用来连接字符串
"3" + 4 + 5; // 345
3 + 4 + "5"; // 75
1 === true; //false
123 === "123"; // false
123 == "123" // true
1 == true; // true

六、控制结构

if()...else if()...else()
while()
do...while()
for( ; ; )/for( : )
  1. 短路与:var name = o && o.getName();
  2. 短路或:var name = otherName || "default";
  3. 三元运算符:var allowed = (age > 18) ? "yes" : "no";
  4. 多重分支时可以使用 

基于一个数字或字符串的switch 语句:(在 switch 的表达式和 case 的表达式是使用 === 严格相等运算符进行比较的:)

switch(action) {
    case 'draw':
        drawIt();
        break;
    case 'eat':
        eatIt();
        break;
    default:
        doNothing();
}
switch(1 + 3){
    case 2 + 2:
        yay();
        break;
    default:
        neverhappens();
}
七、对象
对象的创建方式:
1.var obj = new Object();
2.var obj = {}      --->对象字面量
var obj = {
    name:"carrot",
    "for":"Max",
    details:{
        color:"orange",
        size:12
    }   
  • 可以用链式访问:
            obj.details.color; //orange
  • 可以用中括号访问:
            obj[detail][color];
对象原型:(像是Java中的一个类)
function Person(name,age){
    this.name = name;
    this.age = age;     
}
创建一个Person的对象:
    var You = new Person("zhangjiahao","23");
可用You.name="ZJH"来赋值
obj["name"] = "Simon";
可用var name = You.name;来取值
var name = obj["name"];
中括号的方式的优点:中括号内都是字符串,所以可以用于运行时计算,且可以使用关键字,但在后期被解释时无法优化。
obj.for = "Simon"; // 语法错误,因为 for 是一个预留关键字
obj["for"] = "Simon"; // 工作正常
八、数组
JavaScript中的数组是一个特殊的对象。
与普通对象的区别在于,对于数组中的‘属性’(元素)只能通过中括号来访问。同时数组比普通对象多了一个length属性,该属性值始终比最大索引大一(并非等于数组中的元素个数)
数组的创建:
var a = ['dog','cat','hen'];    //数组字面量
var b = new Array('dog','cat','hen');   //传统方式
如果访问了一个不存在的数组索引 会得到undefined
数组的遍历:
for(var i=0;i<a.length;i++)    //传统方法--->不推荐,每次循环都会计算length,效率不高
 for(var i=0,len = a.length;i<len;i++ )  //改进方法--->先循环开始前,先缓存a.length
 for(var i=0,item;item=a[i++])  //有局限,每次循环都会判断item是否空值或是否定义(是否为真)但是在数组内容中出现假值 会影响循环
 for(var i in a)  //这种循环  不单单会遍历出元素 ,也会遍历出自定义添加的array属性(向 Array.prototype添加了新的属性)
九、函数
对JavaScript的学习最重要的就是对象和函数两个部分。(函数也是对象)
函数:
function add(x,y){
    var total = x + y;
    return total;
}
一个JavaScript函数可以有0个或者多个变量,如果有return,个返回return的值;否则返回undefined。
在使用函数时,函数中的变量也不一定强制与定义函数时的变量一致,如:add();此时x,y为undefined;若add(1,2,3)此时3将会被忽略。
JavaScript 允许你创建匿名函数:
var avg = function() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum / arguments.length;
};

闭包:

var a = 1;
var b = 2;
(function() {
    var b = 3;
    a += b;
})();
a; // 4
b; // 2

递归:

function countChars(elm) {
    if (elm.nodeType == 3) { // 文本节点
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += countChars(child);
    }
    return count;
}

闭包递归:

var charsInBody = (function counter(elm) {
    if (elm.nodeType == 3) { // 文本节点
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += counter(child);
    }
    return count;
})(document.body);

如上所提供的函数表达式的名称的作用域仅仅是该函数自身。这允许引擎去做更多的优化,并且这种实现更可读、友好。该名称也显示在调试器和一些堆栈跟踪中,节省了调试时的时间。

ps:需要注意的是 JavaScript 函数是它们本身的对象——就和 JavaScript 其他一切一样——你可以给它们添加属性或者更改它们的属性,这与前面的对象部分一样。

十、自定义对象
首先我们了解一些面向对象的基本概念和知识。
JavaScript
命名空间:注意:需要认识到重要的一点是:与其他面向对象编程语言不同的是,Javascript中的普通对象和命名空间在语言层面上没有区别。这点可能会让JavaScript初学者感到迷惑。
var MYAPP = MYAPP || {}; //全局命名空间
MYAPP.event = {}; //子命名空间

下面是用于创建命名空间和添加变量,函数和方法的代码写法:

//给普通方法和属性创建一个命名空间
MYAPP.commonMethod = {
    regExForName = "",
    regExForPhone = "",
    validateName = function(name){
         //对参数name做一些操作
    },
    validatePhoneNo = function(phoneNo){
         //对参数phoneNo做一些操作
    }
}
 
MYAPP.event = {
    addListener = function(el , type , fn){
        //code
    }
    removeListener = function(el , type , fn){
        //code
    }
}
 
//使用addListner方法的写法
MYAPP.event.addListener("yourel" , "type" , callback)
自定义对象
JavaScript是一种基于原型的语言,它并没有类似于其他C++/JAVA中的类声明语言。在JavaScript中,我们通常使用方法(function)来当做类。定义一个类跟定义一个函数一样easy
function Person(){}
  //
var Person = function(){}
对象(类的实例)
我们使用 new obj()来创建一个新的实例。
eg:
function Person(){}
var person1 = new Person();
var person2 = new Person();
构造器
在实例化时构造器被调用,在JavaScript中,初始的函数就可以作为构造器使用,而不需要额外的定义构造器方法。类中的每个声明的函数都可以在被实例化后调用执行。(构造器常用于给对象的属性赋初始值)
function Person() {
  alert('Person instantiated');
}
 
var person1 = new Person();
var person2 = new Person();
属性(对象属性)
属性就是当前类中的变量。通常为了正确继承,属性应当为定义在原型属性中。
可以使用关键字this来调用类中的属性,this是对当前对象的引用。
function Person(name){
   this.name = name;
   alert("this is my name" + this.name);
}
var person1 = new Person("Alice");
var person2 = new Person("Bob");
方法(对象属性)
方法和属性相似,不同的是:一个是函数,另一个是可以被定义为函数。为定义一个方法,通常需要将一个函数赋值给类的原型属性,这个赋值给函数的名称就是用来给对象在外部调用它使用的。
function Person(name){
   this.name = name;
}
Person.protopype.sayHello = function(){
   alert("hello,i'm" + this.name);
}
var person1 = new Person("Alice");
var person2 = new Person("Bob");
person1.sayHello();

在JavaScript中方法通常是绑定到一个对象中的普通函数,所以我们也可以在访问域之外对其调用访问。

function Person(name){
   this.name = name;
}
Person.protopype.sayHello = function(){
   alert("hello,i'm" + this.name);
}
var person1 = new Person("Alice");
var person2 = new Person("Bob");
person1.sayHello();  //Alice
 
var helloFunction = person1.sayHello;
helloFunction();  //undefined
 
console.log(helloFunction === person1.sayHello);          // logs true
console.log(helloFunction === Person.prototype.sayHello); // logs true
helloFunction.call(person1);   
继承
创建一个或者多个类的某专门版本类方式称为继承(JavaScript只支持单继承)。创建的专门版本的类通常称作子类。在JavaScript中通过赋予子类一个父类的实例并专门化子类来实现。
function Person(name){
    this.name = name;
}
 
Person.prototype.walk = function(){
    alert("i'm walking!");
}
 
Person.prototype.sayHello = function(){
    alert("Hello , I'm" + this.name );
}
//定义Student构造器
function Student(name , subject){
    Person.call(this , name);//这里也可以用apply(),详细见总结末端
    this.subject = subject;
}
 
//建立一个由Person.prototype继承而来的Student.prototype对象
// 注意: 常见的错误是使用 "new Person()"来建立Student.prototype.
// 这样做的错误之处有很多, 最重要的一点是我们在实例化时
// 不能赋予Person类任何的FirstName参数
// 调用Person的正确位置如下,我们从Student中来调用它
Student.prototype = Object.create(Person.prototype);
 
//设置constructor 属性指向Student
Student.prototype.constructor = Student;
 
Student.prototype.sayHello = function(){
    console.log("hello , I'm" + this.name + "I'm studying" + this.subject);
}
Student.prototype.sayGoodBye = function(){
   alert("GOODBYE");
}
// 测试实例:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello();   // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk();       // "I am walking!"
student1.sayGoodBye(); // "Goodbye!"
 
// Check that instanceof works correctly
console.log(student1 instanceof Person);  // true 
console.log(student1 instanceof Student); // true
封装

在上一个例子中,Student类虽然不需要知道Person类的walk()方法是如何实现的,但是仍然可以使用这个方法;Student类不需要明确地定义这个方法,除非我们想改变它。 这就叫做封装,对于所有继承自父类的方法,只需要在子类中定义那些你想改变的即可。

抽象
抽象是允许模拟工作问题中通用部分的一种机制。这可以通过继承或者组合来实现。
JavaScript通过继承来实现具体化,通过让类的实例是其他对象的属性值来实现组合。
var foo = function(){};
console.log( 'foo is a Function: ' + (foo instanceof Function) );                  // logs "foo is a Function: true"
cpnsole.log( 'foo.prototype is an Object: ' + (foo.prototype instanceof Object) ); // logs "foo.prototype is an Object: true"

多态

就像所有定义在原型属性内部的方法和属性一样,不同的类可以定义具有相同名称的方法;方法是作用于所在的类中。并且这仅在两个类不是父子关系时成立(继承链中,一个类不是继承自其他类)。

---------------------------------------------------------------------------------
总结:
    在经典面向对象中,对象指的是数据以及操作数据的集合。与C++ 和 Java 不同,JavaScript是一种基于原型的编程语言,没有Class语句,而是把函数作为类。
eg:(a)
function makePerson(first , last){
    return {
        first : first,
        last : last
    }
}
function personFullName(person){
    return person.first + "    " + person.last;
}
function personFullNameReversed(person){
    return person.last + "    " + person.first;
}
person1 = makePerson("Kobe","Branyt");
personFullName(person1);
personFullNameReversed(person1);
显然上述方法十分麻烦,需要在全局命名空间中写很多的函数。既然函数本身就是对象,如果需要让一个函数
属于一个对象,那么不难得到:(b)
function makePerson(first , last){
    return{
        first : fitst,
        last : last,
        fullName : function(){
            return this.first + '  ' this.last;
        }
    }
}
s = makerPerson('Kobe','Branty');
s.fullName();// Kobe   Branty

注意:this关键字, 当使用在函数中时,this指的是当前的对象,也就是调用该函数的对象。如果一个对象使用了.或者{}来访问其下的属性时,那么该对象就成了this。如果并不存在某个对象,那么此时this指向全局对象。

s =  makePerson('Allen','Iverson');
var fullName = s.fullName;
fullName(); //undefined    undefined

所以我们可以用this来改进上述makePerson函数:

function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = function() {
        return this.first + ' ' + this.last;
    }
    this.fullNameReversed = function() {
        return this.last + ', ' + this.first;
    }
}
var s = new Person("Simon", "Willison");

但此时创建一个Person对象的时候,我们都在其中创建了两个新的函数对象。所以我们可以将里面的函数拿出来:

function personFullName(person) {
    return this.first + ' ' + this.last;
}
function personFullNameReversed(person) {
    return this.last + ', ' + this.first;
}
function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName;
    this.fullNameReversed = personFullNameReversed;
}

最好的方式:

function Person(first, last) {
    this.first = first;
    this.last = last;
}
Person.prototype.fullName = function() {
    return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function() {
    return this.last + ', ' + this.first;
}
Person.porotype 是一个可以被Person的所有实例共享的对象。他的名字叫做原型链(prototype chain)的查询链的一部分:当你试图访问一个Person中没有定义的属性时,解释器会先检查这个Person.porotype来判断是否存在这样一个属性。所以,在任何时候任何分配给Person.porotype的东西通过this对象构造的实例都是有用的。
这也使得我们可以在任何时候改造原型中的一些东西,甚至是内置对象的原型。给 String 添加一个方法用来返回逆序的字符串:
var s = "Simon";
s.reversed(); // TypeError on line 1: s.reversed is not a function
 
String.prototype.reversed = function() {
    var r = "";
    for (var i = this.length - 1; i >= 0; i--) {
        r += this[i];
    }
    return r;
}
s.reversed(); // nomiS

原型组成链的一部分,那条链的根节点是Object.pototype,它包括toString()方法 --> 将对象转换成字符串调用的方法。这对于调用我们的Person对象很有用。

var s = new Person("Simon", "Willison");
s; // [object Object]
 
Person.prototype.toString = function() {
    return '<Person: ' + this.fullName() + '>';
}
s.toString(); // <Person: Simon Willison>

ps:apply()和 call()

function trivialNew(constructor , ...args){ (...args是剩余参数2015新特性)
    var o = {};//创建一个新对象
    constructor.apply(o,args);
    return o; 
}

apply() 有一个姐妹函数,名叫 call,它也可以允许你设置 this,但它带有一个扩展的参数列表而不是一个数组。

function lastName(){
     return this.last.toUpperCase();
}
var s = new Person("Simon","Willison");
lastName.call(s);
//与下面效果一致
s.lastName = lastName;
s.lastName();

内部函数

JavaScript 允许在一个函数内部定义函数,如果某个函数依赖于其他的一两个函数,而这一两个函数对其余的代码没有用处,可以将它们嵌套在会被调用的那个函数内部,这样做可以减少全局作用域下的函数的数量,这有利于编写易于维护的代码。
function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}
闭包
闭包是JavaScript中必须提到的功能。首先我们来看一个内部函数应用的例子:
function makeAdder(a){
     return funtion(b){
          return a+b; 
     }
}
var x = makeAdder(5);
var y = makeAdder(20);
x(6);//11
y(7);//27
我们来观察一下,在上述代码运行过程中发生了什么:每当JavaScript执行一个函数时,都会创建一个作用域对象(Scopeobject),用来保存 在这个函数中创建的局部变量。它和被传入函数的变量一起被初始化。这与那些保存的所有全局变量和函数的全局对象类似,但有一些区别:
1.每次函数被执行时都会创建一个新的,特定的作用域对象;
2.与全局对象(在浏览器中当做window对象来访问的)不同的是,不能从JavaScript代码中直接访问作用域对象,也没有可以遍历当前的作用域对象里面属性的方法。
 
过程:当调用makeAdder时,解释器创建了一个作用域对象,它带有一个属性a(它被当做参数传入makeAdder函数中,然后makeAdder返回一个新创建的函数)。通常JavaScript的垃圾回收器会在这时候回收makeAdder创建的作用域对象,但是返回的函数却保留了一个指向那个作用域对象的引用。结果是这个作用域对象并不会被垃圾回收器回收。直到指向makeAdder 的那个函数对象的引用计数为零。
 
作用域对象组成了一个名为作用域链(scope chain)的链.它类似于原形(prototype)链一般,被JavaScript的对象系统使用。
 
那么 : 一个闭包就是一个函数 和 在这个函数中被创建函数的作用域对象的组合。
 
闭包允许你保存状态--所以他们通常可以替代对象来使用。
 
内存泄漏
使用闭包的一个缺点就是容易造成浏览器内存泄漏。JavaScript 是一种具有垃圾回收机制的语言——对象在被创建的时候分配内存,然后当指向这个对象的引用计数为零时,浏览器会回收内存。宿主环境提供的对象都是按照这种方法被处理的。
IE 浏览器有自己的一套垃圾回收机制,这套机制与 JavaScript 提供的垃圾回收机制进行交互时,可能会发生内存泄露。
function leakMemory() {
    var el = document.getElementById('el');
    var o = { 'el': el };
    el.o = o;
}

在 IE 中,每当在一个 JavaScript 对象和一个本地对象之间形成循环引用时,就会发生内存泄露。这段代码的循环引用会导致内存泄露:IE 不会释放被elo 使用的内存,直到浏览器被彻底关闭并重启后。


原文地址:https://www.cnblogs.com/MayDayTime/p/9495342.html