2

javascript是一门重要弱类型的语言,因为它是web浏览器的语言,它与浏览器的结合使他成为世界上最流行的编程语言之一。

js历史

Nombas 和 ScriptEase

大概在 1992 年,一家称作 Nombas 的公司开发了一种叫做 C 减减(C-minus-minus,简称 Cmm)的嵌入式脚本语言。Cmm 背后的理念很简单:一个足够强大可以替代宏操作(macro)的脚本语言,同时保持与 C (和 C ++)足够的相似性,以便开发人员能很快学会。这个脚本语言捆绑在一个叫做 CEnvi 的共享软件中,它首次向开发人员展示了这种语言的威力。

Nombas 最终把 Cmm 的名字改成了 ScriptEase,原因是后面的部分(mm)听起来过于消极,同时字母 C “令人害怕”。

现在 ScriptEase 已经成为了 Nombas 产品背后的主要驱动力。

Netscape 发明了 JavaScript

当 Netscape Navigator 崭露头角时,Nombas 开发了一个可以嵌入网页中的 CEnvi 的版本。这些早期的试验被称为 Espresso Page(浓咖啡般的页面),它们代表了第一个在万维网上使用的客户端语言。而 Nombas 丝毫没有料到它的理念将会成为万维网的一块重要基石。

当网上冲浪越来越流行时,对于开发客户端脚本的需求也逐渐增大。此时,大部分因特网用户还仅仅通过 28.8 kbit/s 的调制解调器连接到网络,即便这时网页已经不断地变得更大和更复杂。而更加加剧用户痛苦的是,仅仅为了简单的表单有效性验证,就要与服务器进行多次地往返交互。设想一下,用户填完一个表单,点击提交按钮,等待了 30 秒的处理后,看到的却是一条告诉你忘记填写一个必要的字段。

那时正处于技术革新最前沿的 Netscape,开始认真考虑开发一种客户端脚本语言来解决简单的处理问题。

当时工作于 Netscape 的 Brendan Eich,开始着手为即将在 1995 年发行的 Netscape Navigator 2.0 开发一个称之为 LiveScript 的脚本语言,当时的目的是在浏览器和服务器(本来要叫它 LiveWire)端使用它。Netscape 与 Sun 及时完成 LiveScript 实现。

就在 Netscape Navigator 2.0 即将正式发布前,Netscape 将其更名为 JavaScript,目的是为了利用 Java 这个因特网时髦词汇。Netscape 的赌注最终得到回报,JavaScript 从此变成了因特网的必备组件。

javascript的函数(主要)基于词法作用域(lexical scoping)的顶级对象。

hello world

demo.html
<!DOCTYPE html>
<html>
<head>
    <title>javascript demo</title>
</head>
<body>
 <pre>
     <script type="text/javascript" src="demo.js"></script>
 </pre>
</body>
</html>
demo.js
document.writeln('hello world')
<!DOCTYPE html>
<html>
<head>
    <title>html text</title>
</head>
<body>
   <script type="text/javascript">
      document.write('hello js')
   </script>
</body>
</html>

<!-- javascript 生产普通文本和标签 -->
<!DOCTYPE html>
<html>
<!-- javascript 生产普通文本和标签 -->
<head>
    <title>html text</title>
</head>
<body>
   <script type="text/javascript">
      document.write('<h1>hello js</h1>')
   </script>
</body>
</html>

<!-- javascript head 部分 onload事件 -->
<!DOCTYPE html>
<html>
<!-- javascript head 部分 onload事件 -->
<head>
    <title>html text</title>
       <script type="text/javascript">
          function msg(){
              alert("onload event on head parts")
          }
       </script>
</head>
<body onload="msg()">
</body>
</html>

<!-- javascript 点击事件调用函数 -->

<!DOCTYPE html>
<html>
<!-- javascript 点击事件调用函数 -->
<head>
    <title>html text</title>
       <script type="text/javascript">
          function myFun(){
          <!--JavaScript 语句向浏览器发出的命令。语句的作用是告诉浏览器该做什么。下面的 JavaScript 语句向 id="demo" 的 HTML 元素输出文本 "Hello World",在 JavaScript 中,用分号来结束语句是可选的。-->
              document.getElementById('demo').innerHTML='My html'
          }
       </script>
</head>
<body>
  <p id = "demo">My link</p>
  <button type="button" onclick="myFun()">try it</button>
</body>
</html>

<!-- 请使用 document.write() 仅仅向文档输出写内容。如果在文档已完成加载后执行 document.write,整个 HTML 页面将被覆盖-->
<!DOCTYPE html>
<html>
<!-- 请使用 document.write() 仅仅向文档输出写内容。如果在文档已完成加载后执行 document.write,整个 HTML 页面将被覆盖-->
<head>
    <title>html text</title> 
</head>
<body>
  <p id = "demo">My msg</p>
  <button type="button" onclick="myFun()">try it</button>
  <script type="text/javascript">
          function myFun(){
              document.write('output msg,then whole page will be overide')
          }
       </script>
</body>
</html>
<!-- 你可以在文本字符串中使用反斜杠对代码行进行换行。-->
<!DOCTYPE html>
<html>
<head>
    <title>html text</title> 
</head>
<body>
<script type="text/javascript">
              document.write('hi \
                  jim')
</script>
</body>
</html>

<!-- 变量是存储信息的容器 -->
<!DOCTYPE html>
<html>
<head>
    <title>html</title>
    <script type="text/javascript">
    function fun() {
        var num1 = 1;
        var num2 = 2;
        var num3 = num1 + num2;
        document.write(num3);//点击try it按钮,打出计算结果 3
    }
    </script>
</head>
<body>
    <button type="button" onclick="fun()">try it</button>
</body>
</html>

<!-- js创建数组 -->
<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
       <script type="text/javascript">
        var cars = new Array();
        cars[0] = 'aodi';
        cars[1] = 'baoma';
        cars[2] = 'benchi';
        for(var i = 0;i<cars.length;i++){
            document.write(cars[i]+'<br/>')
        }
    </script>
</body>
</html>
<!-- js创建对象并且获取对象 -->
<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
       <script type="text/javascript">
         var cars = {
             'name1':'baoma',
             'name2':'aodi', 
             'name3':'dazhong'
         }
        document.write(cars.name1)
    </script>
</body>
</html>

1,语法
1.1 空格
var that = this;
var 和that之间的空白不能移除,但是其他的空格都是可以移除的。
注释
js的注释有两种方法:/ / 和//
/ var rm_a = /a/.match(s) */就会导致错误,所以一般注释用//.
1.2 标识符
标识符有一个字母开头,可以选择性的加上一个或是多个字母,数字或下划线,但是不能使用下面的保留字
abstract,boolean,break,byte,case,catch,char,class,const,continue,debugger,default,delete,do,double,else,enum,export,extends,false,final,finally,float,for,function,goto,if,implements,import,in,instanceof,int,interface,long,native,new,null,package,private,protected,public,return,short,static,super,switch,synchronized,this,throw,thransient,true,try,typeof,while,with
2,对象
js中,对象是可变的键控集合(keyed collections),在js中,数组是对象,函数是对象,正则表达式是对象。
对象字面量:对象字面量提供了一种非常方便的创建新对象值的表达法,一个对象字面量就是包围在一对花括号中的零或多个"键/值"对。

var name = {
    "name1":"mike",
    "name2":"mike2"
}

对象也可以嵌套使用:

var flight = {
    airline:"oceanic",
    number:125,
    departure:{
        city:"beijing",
        time:"2015/01/05"
    },
    arrival:{
        city:"amrica",
        time:"2015/01/06"
    }
}

2.1 对象的检索
检索对象中包含的值,可以采用在[]后缀中括住一个字符串表达式。

name["name1"] //mike1
flight.arrival.city //amrica

2.2属性值更新
name["name1"] = "Jet li"
2.3引用传递对象
对象通过引用来传递
var = {},b = {},c = {}//a,b,c 都引用一个不同的空对象
a = b = c = {} //a b,c都引用同一个空对象

3.2 原型
http://www.crockford.com/java...
原型是一个对象,其他对象可以通过它实现属性继承。
每个对象都连接到一个原型对象,并且他可以从中可以继承属性,原型连接在属性更新的时候是不起作用的,原型连接只用在检索的时候才会被用到,如果我们尝试去获取对象的某个属性值,且该对象没有此属性值,那么js会尝试从原型对象上获取,如果也没找到,返回undefined,这个过程叫委托

typeof

typeof 运算符有一个参数,即要检查的变量或值

var a = "str"; alert(typeof a);//string
var a = 'str'; alert(typeof 123);// number

对变量或值调用 typeof 运算符将返回下列值之一:

undefined - 如果变量是 Undefined 类型的
boolean - 如果变量是 Boolean 类型的
number - 如果变量是 Number 类型的
string - 如果变量是 String 类型的
object - 如果变量是一种引用类型或 Null 类型的

为什么 typeof 运算符对于 null 值会返回 "Object"。这实际上是 JavaScript 最初实现中的一个错误,然后被 ECMAScript 沿用了。现在,null 被认为是对象的占位符,从而解释了这一矛盾,但从技术上来说,它仍然是原始值。

Undefined 类型

如前所述,Undefined 类型只有一个值,即 undefined。当声明的变量未初始化时,该变量的默认值是 undefined。

var str; console.log(str==undefined)//true
var str; console.log(typeof str)//undefined

Null 类型

另一种只有一个值的类型是 Null,它只有一个专用值 null,即它的字面量。值 undefined 实际上是从值 null 派生来的,因此 ECMAScript 把它们定义为相等的。

var str = null; console.log(str==undefined)//true

尽管这两个值相等,但它们的含义不同。undefined 是声明了变量但未对其初始化时赋予该变量的值,null 则用于表示尚未存在的对象(在讨论 typeof 运算符时,简单地介绍过这一点)。如果函数或方法要返回的是对象,那么找不到该对象时,返回的通常是 null。

Boolean 类型
它有两个值 true 和 false (即两个 Boolean 字面量)。

即使 false 不等于 0,0 也可以在必要时被转换成 false,这样在 Boolean 语句中使用两者都是安全的。

注意数值的表示法
var str = !0;console.log(str)//true
var str = !1;console.log(str)//false

Number 类型
ECMA-262 中定义的最特殊的类型是 Number 类型。这种类型既可以表示 32 位的整数,还可以表示 64 位的浮点数。

直接输入的(而不是从另一个变量访问的)任何数字都被看做 Number 类型的字面量。例如,下面的代码声明了存放整数值的变量,它的值由字面量 32 定义:

var num = 32;console.log(num)//32

JavaScript 拥有动态类型

JavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型:

Undefined 和 Null

Undefined 这个值表示变量不含有值。

可以通过将变量的值设置为 null 来清空变量。

<!--可以通过null来清空对象-->
<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
       <script type="text/javascript">
         var cars='baoma';
         document.write(cars+'<br/>')
         cars = null;
         document.write(cars)
         alert(cars==undefined)//true
    </script>
</body>
</html>

声明变量类型
当您声明新变量时,可以使用关键词 "new" 来声明其类型:

<!DOCTYPE html>
<html>
<!-- 声明新变量时,可以使用关键词 "new" 来声明其类型 -->
<head>
    <title>html</title>
</head>
<body>
       <script type="text/javascript">
          var str = new String;
          var bo = new Boolean;
          var num = new Number;
          var cars = new Array;
          var person = new Object;
          alert(typeof str)
          alert(typeof bo)
          alert(typeof num)
          alert(typeof cars)
    </script>
</body>
</html>

创建 JavaScript 对象

JavaScript 中的几乎所有事务都是对象:字符串、数字、数组、日期、函数,等等。

对象(object)定义为“属性的无序集合,每个属性存放一个原始值、对象或函数”。严格来说,这意味着对象是无特定顺序的值的数组。

面向对象语言的要求

一种面向对象语言需要向开发者提供四种基本能力:

封装 - 把相关的信息(无论数据或方法)存储在对象中的能力
聚集 - 把一个对象存储在另一个对象内的能力
继承 - 由另一个类(或多个类)得来类的属性和方法的能力
多态 - 编写能以多种方法运行的函数或方法的能力

对象由特性(attribute)构成,特性可以是原始值,也可以是引用值。如果特性存放的是函数,它将被看作对象的方法(method),否则该特性被看作对象的属性(property)。

你也可以创建自己的对象。

<!DOCTYPE html>
<html>
<!-- 创建 JavaScript 对象-->
<head>
    <title>html</title>
</head>
<body>
       <script type="text/javascript">
         var person= new Object();
         person.name1='mike';
         person.age=23;
         person.color1 = 'yellow';
         document.write('A person named '+ person.name1+' is '+ person.age +' years old')
    </script>
</body>
</html>

访问对象的属性和方法

<!DOCTYPE html>
<html>
<!--访问对象的属性和方法-->
<head>
    <title>html</title>
</head>
<body>
       <script type="text/javascript">
         var str = 'Hellojs'
         document.write('Len: '+str.length+' <br/>Up: '+str.toUpperCase())
    </script>
</body>
</html>

调用带参数的函数
在调用函数时,您可以向其传递值,这些值被称为参数。
变量和参数必须以一致的顺序出现。第一个变量就是第一个被传递的参数的给定的值,以此类推。

<!DOCTYPE html>
<html>
<!--JavaScript 调用带参数的函数-->
<head>
    <title>html</title>
    <script type="text/javascript">
       function fun(name,title){
          alert(name+' is a great '+title)
       }
    </script>
</head>
<body>
   <button type = 'button' onclick="fun('bill','leader')">click</button>
</body>
</html>

带有返回值的函数
在使用 return 语句时,函数会停止执行,并返回指定的值。

<!DOCTYPE html>
<html>
<!--JavaScript 调用带参数的函数-->
<head>
    <title>html</title>
    <script type="text/javascript">
       function re(){
          var num = 4;
          return num;
       }
       // return 返回4
       function fun(){

           document.getElementById('demo').innerHTML=re()
       }
    </script>
</head>
<body>
   <p id="demo">Here is the content will be changed</p>
   <button type = 'button' onclick="fun()">click</button>
</body>
</html>

局部 JavaScript 变量

在 JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它。(该变量的作用域是局部的)。

可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量。

只要函数运行完毕,本地变量就会被删除。

全局 JavaScript 变量

在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。

向未声明的 JavaScript 变量来分配值

如果把值赋给尚未声明的变量,该变量将被自动作为全局变量声明。
将声明一个全局变量,即使它在函数内执行。

函数支持闭包
函数支持闭包,也即是说,函数可以使用函数之外定义的变量。

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
      var say = 'hello world'
       function fun(){
          alert(say)
       }
       fun()
    </script>
    <!-- 在上面这段代码中,脚本被载入内存后,并没有为函数 fun() 计算变量 say 的值。该函数捕获 say 的值只是为了以后的使用,say 将在函数调用 fun() 时(最后一行)被赋值,显示消息 "hello world"。-->
</body>
</html>

JavaScript 运算符
如果把数字与字符串相加,结果将成为字符串。

逗号运算符
用逗号运算符可以在一条语句中执行多个运算。常用在变量声明中。

var iNum1 = 1, iNum = 2, iNum3 = 3;

JavaScript Switch 语句

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
    <p id="demo"><p>
    <button type="button" onclick='fun()'>try it</button>
    <script type="text/javascript">
           function fun(){
             var str =''
             var day = new Date().getDay();
            switch(day)//注意day返回的是星期几,也就是数字0-6
             {
                 case 1:
               str = 'today is mon'
                 break
                 case 2:
                 str = 'today is Tus'
                 break 
                 case 3:
                 str = 'today is wens' 
                 break 
                 case 4:
                 str = 'today is thus'
                 break 
                 case 5:
                 str = 'today is fri' 
                 break 
                 case 6:
                 str = 'today is sat'
                 break
                 case 7:
                 str = 'today is sun'
                 break
                 default:
                 str='expecting weekends'
          }
          document.getElementById('demo').innerHTML=str;
      }
    </script>
</body>
</html>

for循环

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
    <!-- javascript 遍历对象属性 -->
</head>
<body>
    <p id="demo"><p>
    <button type="button" onclick='fun()'>try it</button>
    <script type="text/javascript">
          var i;
          var txt = ''
           function fun(){
               var person = {'name':'bill','age':'23','cookie':'true','single':'true'}
               for(i in person){
                   txt+=i+'<br/>'
               }
              document.getElementById('demo').innerHTML=txt;
          }
    </script>
</body>
</html>

do/while

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
    <!-- javascript do/while -->
</head>
<body>
    <p id="demo"><p>
    <button type="button" onclick='fun()'>try it</button>
    <script type="text/javascript">

          var i = 0;
          var txt = '';
          function fun(){
          do
           {
              txt+= 'js running the '+i+'times'+'<br/>'
              i++
          }
          while(i < 5)
          document.getElementById('demo').innerHTML = txt;
      }
    </script>
</body>
</html>

while 遍历数组

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
    <!-- javascript do/while 遍历数组 -->
</head>
<body>
    <p id="demo"><p>
    <script type="text/javascript">
    var i = 0;
       var cars = ['baoma','benchi','qq','aodi']
       while(cars[i]){
            document.write(cars[i]+'<br/>')
            i++
       }
    </script>
</body>
</html>

try/catch

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
    <script>
    function myFunc() {
        try {
            var x = document.getElementById('inputName').value;
            if (x == '') throw 'the input number should not be empty';
            if (isNaN(x)) throw 'the input content should be number';
            if (x < 5) throw 'the number was too small';
            if (x > 10) throw 'the number was too large';
        } catch (err) {
            var y = document.getElementById('miss');
            y.innerHTML = 'error ' + err;
        }
    }
    </script>
    <input type="text" id='inputName'>
    <button type='button' onclick='myFunc()'>click</button>
    <p id='miss'></p>
</body>
</html>

通过标签名查找 HTML 元素
getElementsByTagName

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
  <div id = 'main'>
      <span>this is the first doc</span>
      <p>this is the second doc</p>
      <p>this is the third doc</p>
  </div>
    <script>
       var x = document.getElementById('main');
       var y = x.getElementsByTagName('p');
       document.write('The first doc is '+y[0].innerHTML)
    </script>
</body>
</html>

改变 HTML 内容
修改 HTML 内容的最简单的方法时使用 innerHTML 属性。

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
      <p id='main'>this is the first doc</p>
    <script>
       document.getElementById('main').innerHTML='angularjs'
    </script>
</body>
</html>

改变 HTML 样式

如需改变 HTML 元素的样式,请使用这个语法:

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
      <p id='main'>this is the first doc</p>
    <script>
       document.getElementById('main').style.color='red'
    </script>
</body>
</html>

点击更改html

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
  <p onclick="this.innerHTML='Thank you'">please click it</p>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
  <script>
    function func(id){
        id.innerHTML='Thank you!'
    }
  </script>
  <p onclick="func(this)">please click it</p>
</body>
</html>

打印系统时间

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
  <p id='demo'></p>
  <script>
    function func(){
        document.getElementById('demo').innerHTML= Date();
    }
  </script>
  <button type='button' onclick="func()">please click it</p>
</body>
</html>

button和点击分离
<!DOCTYPE html>
<html>
<!-- 可以将点击按钮分离 -->
<head>
    <title>html</title>
</head>
<body>
    <button id='btm'>click here</button>
    <script>
    document.getElementById("btm").onclick = function() {
        displayDate()
    }
    function displayDate() {
        document.getElementById("demo").innerHTML = Date()
    }
    </script>
    <p id="demo"></p>
</body>
</html>

onload事件

<!DOCTYPE html>
<html>
<!-- onload 事件检查cookie是否开启 -->
<head>
    <title>html</title>
</head>
<body onload="checkCookies()">
  <script type="text/javascript">
  function checkCookies(){
      if(navigator.cookieEnabled==true){
       alert('cook enabled')
     }else{
      alert('cookie down')
     }
  } 
  </script>
</body>
</html>

onchange事件,点击离开,输入内容大写

<!DOCTYPE html>
<html>
<!-- onchange事件点击离开,输入的英文变大写 -->
<head>
    <title>html</title>
</head>
<body>
  <script type="text/javascript">
  function func(){
      var x = document.getElementById('demo');
      return x.value = x.value.toUpperCase()
  } 
  </script>
  <input type="text" id="demo" onchange="func()">
</body>
</html>

mouseover/mouseout

<!DOCTYPE html>
<html>
<!-- onmouseout onmouseover事件点击离开,更改样式 -->
<head>
    <title>html</title>
</head>
<body>
  <div onmouseover="mover(this)" onmouseout="mout(this)" style="background-color: green;height:100px;width:100px;text-align: center">what 's that</div>
  <script type="text/javascript">
     function mover(obj){
       obj.innerHTML='THANK YOU'
     }
     function mout(obj){
         obj.innerHTML='LEAVE'
     }
  </script>
</body>
</html>

mouseup/mousedown

<!DOCTYPE html>
<html>
<!-- onmouseup onmousedown事件点击离开,更改样式 -->
<head>
    <title>html</title>
</head>
<body>
  <div onmouseup="mover(this)" onmousedown="mout(this)" style="background-color: green;height:100px;width:100px;text-align: center"></div>
  <script type="text/javascript">
     function mover(obj){
       obj.innerHTML='please click mouse'
       obj.style.backgroundColor='red'
     }
     function mout(obj){
         obj.innerHTML='please release your mouse'
         obj.style.backgroundColor='#ccc'
     }
  </script>
</body>
</html>

当输入字段获得焦点时,会触发改变背景颜色的函数。

<!DOCTYPE html>
<html>
<!-- onfocus 当输入字段获得焦点时,会触发改变背景颜色的函数。-->
<head>
    <title>html</title>
</head>
<body>
  <script type="text/javascript">
      function func(obj){
         // return obj.style.backgroundColor = 'yellow'
          obj.style.background='red'//使用这两种方式都可以
      }
  </script>
  <input type="text" onfocus="func(this)">
</body>
</html>

创建新的 HTML 元素
如需向 HTML DOM 添加新元素,你必须首先创建该元素(元素节点),然后向一个已存在的元素追加该元素。

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
<div id='main'>
    <p id='p1'>the second para</p>
    <p id='p2'>the second para</p> 
</div>
  <script type="text/javascript">
     var p = document.createElement('p3')
     var node = document.createTextNode('This is something new')
     p.appendChild(node)
     var e2 = document.getElementById('main')
     e2.appendChild(p)
  </script>
</body>
</html>

删除已有的 HTML 元素

如需删除 HTML 元素,你必须首先获得该元素的父元素

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
<div id='main'>
    <p id='p1'>the first para</p>
    <p id='p2'>the second para</p> 
    <p id='p3'>the third para</p>
</div>
  <script type="text/javascript">
     var a1 = document.getElementById('main');
     var a2 = document.getElementById('p1')
     a1.removeChild(a2)
  </script>
</body>
</html>

javascript 面对对象
使用预定义对象只是面向对象语言的能力的一部分,它真正强大之处在于能够创建自己专用的类和对象。
工厂方式
原始方式

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
      <script type="text/javascript">
       var person = new Object();
       person.color = 'yellow';
       person.hight = 230;
       person.hands = 2;
       //最后一个属性实际上是指向函数的指针,意味着该属性是个方法。执行这段代码后,就可以使用对象 car。
       person.action = function(){
          document.write(this.color);
       }
       person.action();
    </script>
</body>
</html>

工厂模式

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
      <script type="text/javascript">
      function createPerson(){
         var person = new Object();
         person.color = 'yellow';
         person.hight = 230;
         person.hands = 2;
         person.action = function(){
          document.write(this.color);
       }
       return person;
      }
      var person1 = createPerson();
       var person2 = createPerson();
       person1.action();
       document.write('<br>')
       person2.action();
    </script>
</body>
</html>
返回 person 对象(person)作为函数值。调用此函数,将创建新对象,并赋予它所有必要的属性,复制出一个我们在前面说明过的 person 对象。因此,通过这种方法,我们可以很容易地创建 person 对象的两个版本(person1 和 person2),它们的属性完全一样。

工厂模式传递参数

<!DOCTYPE html>
<html>
<!--给工厂模式传递参数-->
<head>
    <title>html</title>
</head>
<body>
      <script type="text/javascript">
      function createPerson(skinColor,phsiHight,hanNum){
         var person = new Object();
         person.color = skinColor;
         person.hight = phsiHight;
         person.hands = hanNum;
         person.action = function(){
          document.write(this.color);
       }
       return person;
      }
      var person1 = createPerson('yellow',100,2);
       var person2 = createPerson('black',130,2);
       person1.action();
       document.write('<br>')
       person2.action();
    </script>
</body>
</html>
给 createPerson() 函数加上参数,即可为要创建的 person 对象的 skinColor、phsiHight 和 hanNum 属性赋值。这使两个对象具有相同的属性,却有不同的属性值

将函数方法定义在工厂函数外面

<!DOCTYPE html>
<html>
<!--在工厂函数外定义对象的方法-->
<head>
    <title>html</title>
</head>
<body>
      <script type="text/javascript">
      function action(){
        document.write(this.color)
      }
      function createPerson(skinColor,phsiHight,hanNum){
         var person = new Object();
         person.color = skinColor;
         person.hight = phsiHight;
         person.hands = hanNum;
         person.action = this.action;
       return person;
      }
      var person1 = createPerson('yellow',100,2);
       var person2 = createPerson('black',130,2);
       person1.action();
       document.write('<br>')
       person2.action();
    </script>
</body>
</html>
<!-- 每次调用函数 createPerson(),都要创建新函数 action(),意味着每个对象都有自己的 action() 版本。而事实上,每个对象都共享同一个函数。 -->

构造函数方法

<!DOCTYPE html>
<html>
<!--构造函数方法-->
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
    function Person(skinColor, phsiHight, hanNum) {
        this.color = skinColor;
        this.hight = phsiHight;
        this.hands = hanNum;
        this.action = function() {
          document.write(this.color)
        }
    }
    var person1 = new Person('yellow', 100, 2);
    var person2 = new Person('black', 130, 2);
    person1.action();
    document.write('<br>')
    person2.action();
    </script>
</body>
</html>

构造函数方法与工厂方式的差别。
首先在构造函数内没有创建对象,而是使用 this 关键字。使用 new 运算符构造函数时,在执行第一行代码前先创建一个对象,只有用 this 才能访问该对象。然后可以直接赋予 this 属性,默认情况下是构造函数的返回值(不必明确使用 return 运算符)。
现在,用 new 运算符和类名 Person 创建对象,就更像 ECMAScript 中一般对象的创建方式了。
就像工厂函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。不过,与工厂函数相似,也可以用外部函数重写构造函数,同样地,这么做语义上无任何意义。这正是下面要讲的原型方式的优势所在。

原型方式

<!DOCTYPE html>
<html>
<!--原型方式-->
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
    function Person(){//该方式利用了对象的 prototype 属性,可以把它看成创建新对象所依赖的原型。
        //这里,首先用空构造函数来设置类名。然后所有的属性和方法都被直接赋予 prototype 属性。
    }
      //通过给 Car 的 prototype 属性添加属性去定义 Car 对象的属性。
        Person.prototype.color = 'yellow';
        Person.prototype.hight = 100;
        Person.prototype.hands = 2;
        Person.prototype.action = function() {
          document.write(this.color)
        }
        //调用 new Person() 时,原型的所有属性都被立即赋予要创建的对象,意味着所有 Person 实例存放的都是指向 action() 函数的指针。从语义上讲,所有属性看起来都属于一个对象,因此解决了前面两种方式存在的问题。
    var person1 = new Person();
    var person2 = new Person();
    person1.action();
    document.write('<br>')
    person2.action();
    </script>
</body>
</html>

混合的构造函数

<!DOCTYPE html>
<html>
<!--混合的构造函数-->
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
     function Person(sinkColor,job,gender){
        this.color = sinkColor;
        this.title = job;
        this.sex = gender;
        this.numbers = new Array('bill','mike')
     }
     Person.prototype.show = function(){
      document.write(this.title)
    }
     var person1 = new Person('yellow','ceo','man');
     var person2  = new Person('red','dev','femal');
     person1.numbers.push('iven');
    document.write(person1.numbers)
    document.write('<br>')
    document.write(person2.numbers)
    </script>
</body>
</html>

字符串拼接,资源消耗问题

var str = "hello ";
str += "world";

实际上,这段代码在幕后执行的步骤如下:

创建存储 "hello " 的字符串。
创建存储 "world" 的字符串。
创建存储连接结果的字符串。
把 str 的当前内容复制到结果中。
把 "world" 复制到结果中。
更新 str,使它指向结果。

每次完成字符串连接都会执行步骤 2 到 6,使得这种操作非常消耗资源。如果重复这一过程几百次,甚至几千次,就会造成性能问题。解决方法是用 Array 对象存储字符串,然后用 join() 方法(参数是空字符串)创建最后的字符串。想象用下面的代码代替前面的代码:

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
     var arr = new Array();
     arr[0] = 'hello'
     arr[1] = 'world'
     var str = arr.join(',')
     document.write(str)
    </script>
</body>
</html>

这样,无论数组中引入多少字符串都不成问题,因为只在调用 join() 方法时才会发生连接操作。此时,执行的步骤如下:

创建存储结果的字符串
把每个字符串复制到结果中的合适位置

虽然这种解决方案很好,但还有更好的方法。问题是,这段代码不能确切反映出它的意图。要使它更容易理解,可以用 StringBuffer 类打包该功能:

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
    function StringBuffer(){
      this._s_ = new Array();
    }
    StringBuffer.prototype.append = function(str){
      this._s_.push(str)
    }
    StringBuffer.prototype.toString = function(){
      return this._s_.join(",");
    }
     var buffer = new StringBuffer();
     buffer.append('hello')
     buffer.append('world')
     var strs = buffer.toString()
     document.write(strs)
    </script>
</body>
</html>

这段代码首先要注意的是 s 属性,本意是私有属性。它只有两个方法,即 append() 和 toString() 方法。append() 方法有一个参数,它把该参数附加到字符串数组中,toString() 方法调用数组的 join 方法,返回真正连接成的字符串。要用 StringBuffer 对象连接一组字符串

<!DOCTYPE html>
<html>
<head>
<!-- 创建 Date 对象时,如果没有参数,赋予对象的是当前的日期和时间。要计算连接操作历经多少时间,把日期的毫秒表示(用 getTime() 方法的返回值)相减即可。这是衡量 JavaScript 性能的常见方法 -->
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
    var d1 = new Date();
    function StringBuffer(){
      this._s_ = new Array();
    }
    StringBuffer.prototype.append = function(str){
      this._s_.push(str)
    }
    StringBuffer.prototype.toString = function(){
      return this._s_.join(",");
    }
     var buffer = new StringBuffer();
      for(var i = 0;i<10000000;i++){
        buffer.append('txt')
      }
     var strs = buffer.toString()
     var d2 = new Date();
     document.write('<h1>buffer time:</h1>')
     document.write(d2.getTime()- d1.getTime())
     for(var i = 0;i<10000000;i++){
          var txt = txt + "txt";
     }
     var d3 = new Date();
      document.write('<h1>str time:</h1>')
      document.write(d3.getTime()-d2.getTime());
    </script>
</body>
</html>

重命名已有的方法
可以给已有的方法名更改名称,比如可以给 Array 类添加两个方法 enq() 和 inq(),只让它们反复调用已有的 push() 和 shift() 方法即可:
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
     Array.prototype.enq = function(v1){
       return this.push(v1)
     }
     Array.prototype.inq = function(){
      //shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
      return this.shift();
     }
     var arr = new Array(3);
     arr[0] = 'm1';
     arr[1] = 'm2';
     arr[2] = 'm3';
     arr.enq('mike');
     document.write(arr);
     document.write('<br>')
     arr.inq();
     document.write(arr)
    </script>
</body>
</html>

创造方法
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置.但是Array没有indexof方法,这里可以给Array创建一个indexof方法

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
</head>
<body>
    <script type="text/javascript">
        Array.prototype.indeof = function(v){
          for(var i = 0;i<this.length;i++){
            if(v==this[i]){
              return i
            } 
          }
          return -1;
        }
        var arr = new Array('m1','m2','m3');
        var str = arr.indeof('m2')
        document.write(str)
    </script>
</body>
</html>

重定义已有方法
就像能给已有的类定义新方法一样,也可重定义已有的方法。如前面的章节所述,函数名只是指向函数的指针,因此可以轻松地指向其他函数。

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
    <!-- 重定义已有方法 -->
</head>
<body>
    <script type="text/javascript">
       Function.prototype.toString = function(){//重定义toString方法,返回指定字符串
         return'strings'
       }
       function sayHi(){
         document.write('something')
       }
       document.write(sayHi.toString())
    </script>
</body>
</html>

重新定义toString方法,但是保留它的原始指针

<!DOCTYPE html>
<html>
<head>
    <title>html</title>
    <!-- 重定义已有方法 
     Function 的 toString() 方法通常输出的是函数的源代码。覆盖该方法,可以返回另一个字符串
     不过,toString() 指向的原始函数怎么了呢?它将被无用存储单元回收程序回收,因为它被完全废弃了。没有能够恢复原始函数的方法,所以在覆盖原始方法前,比较安全的做法是存储它的指针,以便以后的使用。有时你甚至可能在新方法中调用原始方法:-->
</head>
<body>
    <script type="text/javascript">
      Function.prototype.originalToString = Function.prototype.toString;//这个表达式的意思是存储它的指针
 
      Function.prototype.toString = function(){
        if(this.originalToString().length > 100){
          return 'too long to display'
        }else{
          return this.originalToString();
        }
      }
        function sayHi(){
            alert('something')
        }
      document.write(sayHi.toString())
    </script>
</body>
</html>

javascript的继承机制的实现

选定基类后,就可以创建它的子类了。基类只是用于给子类提供通用的函数。在这种情况下,基类被看作抽象类。

尽管 ECMAScript 并没有像其他语言那样严格地定义抽象类,但有时它的确会创建一些不允许使用的类。通常,我们称这种类为抽象类。

创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。记住,所有属性和方法都是公用的,因此子类可直接访问这些方法。子类还可添加超类中没有的新属性和方法,也可以覆盖超类的属性和方法。
继承的方式

和其他功能一样,ECMAScript 实现继承的方式不止一种。这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适用的继承方式。
1,对象冒充
它是在开发者开始理解函数的工作方式,尤其是如何在函数环境中使用 this 关键字后才发展出来。

<html>

<head>
    <title>Example</title>
</head>
<!-- 构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 构造函数成为 ClassB 的方法,然后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。例如,用下面的方式定义 ClassA 和 ClassB: -->
<body>
    <script type="text/javascript">
    function ClassA(sColor) {
        this.color = sColor;
        this.sayColor = function() {
          document.write(this.color)
        };
    }

    function ClassB(Lor, sName) {
        this.newMethod = ClassA;//因为构造函数只是一个函数,所以可使 一个构造函数成为 另一个函数的方法
        this.newMethod(Lor);
        delete this.newMethod;//最后一行代码删除了对 ClassA 的引用,这样以后就不能再调用它。

        this.name = sName;
        this.sayName = function() {
           document.write(this.name)
        };
    }

    var objA = new ClassA("blue");
    var objB = new ClassB("red", "John");
    objA.sayColor();
    document.write('<br>')
    objB.sayColor();
      document.write('<br>')
    objB.sayName();
    </script>
</body>

</html>

对象冒充可实现多重继承
UML
图片描述

这里存在一个弊端,如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。

由于这种继承方法的流行,ECMAScript 的第三版为 Function 对象加入了两个方法,即 call() 和 apply()。

Call() 方法

<html>
<head>
    <title>Example</title>
</head>
<!-- 构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 构造函数成为 ClassB 的方法,然后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。例如,用下面的方式定义 ClassA 和 ClassB: -->
<body>
    <script type="text/javascript">
    function ClassA(sColor) {
        this.color = sColor;
        this.sayColor = function() {
          document.write(this.color)
        };
    }
    function ClassB(Lor, sName) {
        //this.newMethod = ClassA;
        //this.newMethod(Lor);
        //delete this.newMethod;
        ClassA.call(this,Lor)//call() 方法是与经典的对象冒充方法最相似的方法。它的第一个参数用作 this 的对象。其他参数都直接传递给函数自身。这里的this等于创建了新的ClassB对象,Lor对于两个类来说都是唯一的参数
        this.name = sName;
        this.sayName = function() {
           document.write(this.name)
        };
    }

    var objA = new ClassA("blue");
    var objB = new ClassB("red", "John");
    objA.sayColor();
    document.write('<br>')
    objB.sayColor();
      document.write('<br>')
    objB.sayName();
    </script>
</body>
</html>
var pet = {
    words:'...',
    speak: function(say){
        console.log(say+''+this.words);
    }
}

// pet.speak('speak') //speak ...
// this 指的是调用这个方法的对象 pet


// 狗有自己的话,但是没有speak的方法
var dog = {
    words:'wang'
}

//  pet本来指向的是speak方法,但是call改变了执行上下文,pet 的speak就指向了dog
//dog 现在有了一个pet的技能 speak
pet.speak.call(dog,'speak ')//speak wang
 call 实现继承
 function pet (words) {
    this.words = words;
    this.speak = function(){
        console.log(this.words)
    }
}

function dog(words){
    pet.call(this,words)//dog 没有speak方法,通过call(this) 继承了pet的speak方法
    //pet.apply(this,arry) apply和call的区别在于apply传递的是一个参数列表
}

var dog = new dog('wang');

dog.speak();//wang

apply方法

<html>
<head>
    <title>Example</title>
</head>
<body>
    <script type="text/javascript">
    function ClassA(sColor) {
        this.color = sColor;
        this.sayColor = function() {
          document.write(this.color)
        };
    }
    function ClassB(Lor, sName) {
        //this.newMethod = ClassA;
        //this.newMethod(Lor);
        //delete this.newMethod;
        ClassA.apply(this,arguments)//第一个参数仍是 this,第二个参数是只有一个值 Lor 的数组。可以把 ClassB 的整个 arguments 对象作为第二个参数传递给 apply() 方法:
        this.name = sName;
        this.sayName = function() {
           document.write(this.name)
        };
    }
    var objA = new ClassA("blue");
    var objB = new ClassB("red", "John");
    objA.sayColor();
    document.write('<br>')
    objB.sayColor();
      document.write('<br>')
    objB.sayName();
    </script>
</body>
</html>
//当然,只有超类中的参数顺序与子类中的参数顺序完全一致时才可以传递参数对象。如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。

call(),apply(),bind()的区别

<!DOCTYPE html>
<html>
<!-- 改变执行上下文,call, apply,bind, call 方法可将一个函数的对象上下文从初始的(初始值)上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。同apply类似,唯一区别是:
apply()把参数打包成Array再传入;
call()把参数按顺序传入。-->
<body>
   <script type="text/javascript">
      var obj = {
         log: function() {
         alert(this.foo);
       },
       foo: 'foo'
     };

      var temp = {
       foo:'bar'
     };
      obj.log.bind(temp)();//bar
      obj.log.apply(temp);//bar
      obj.log.call(temp);//bar
   </script>
</body>
</html>
比如,在举一个例子:
<!DOCTYPE html>
<html>
<!-- 在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。
在说区别之前还是先总结一下三者的相似之处:
1、都是用来改变函数的this对象的指向的。
2、第一个参数都是this要指向的对象。
3、都可以利用后续参数传参。 -->
<head>
  <title>比较apply,call,bind的区别</title>
</head>
<body>
  <script type="text/javascript">
    var o ={
     name:'mike',
     age:'20',
     say: function(){
       alert(this.name+' this year '+this.age+' years old')
     }
    }
    var b = {
      name:'mk',
      age:'21'
    }
  o.say()
  </script>
</body>
</html>
这段代码打印出来的肯定是mike this year 20 years old
<!DOCTYPE html>
<html>
<!-- 那么如何用 o 的say方法来显示 b 的数据呢。这是就需要调用call,apply,bind -->
<head>
  <title>比较apply,call,bind的区别</title>
</head>
<body>
  <script type="text/javascript">
    var o ={
     name:'o data',
     age:'20',
     say: function(){
       alert(this.name+' this year '+this.age+' years old')
     }
    }
    var b = {
      name:'b data',
      age:'21'
    }
 // o.say()
    alert('will display call b data')
    o.say.call(b)
    alert('will dispaly apply b data')
    o.say.apply(b)
    alert('will display bind b data')
    o.say.bind(b)()
  </script>
</body>
</html>
<!DOCTYPE html>
<html>
<!-- call,apply直接调用,bind方法返回的仍然是一个函数,因此后面还需要()来进行调用才可以。
call后面的参数与say方法中是一一对应的,而apply的第二个参数是一个数组,数组中的元素是和say方法中一一对应的,这就是两者最大的区别。
但是由于bind返回的仍然是一个函数,所以我们还可以在调用的时候再进行传参。-->
<head>
  <title>比较apply,call,bind的区别</title>
</head>
<body>
  <script type="text/javascript">
    var object1 ={
     name:"object1 data",
     age:"20",
     say: function(gender,job){
       alert(this.name+" this year " + this.age +" years old "+ gender+ " in microsoft, as a/an "+ job)
     }
    }

    var object2 = {
      name:"object2 data",
      age:"21"
    }
 // o.say()
    alert('will display call object2 data');
    object1.say.call(object2,"female","developer");
    alert('will dispaly apply object2 data');
    object1.say.apply(object2,["male","Technical Leader"]);
    alert('will display bind object2 data');
    object1.say.bind(object2)("female","CEO");
  </script>
</body>
</html>

原型链继承

<html>
<head>
    <title>Example</title>
    <!-- prototype 对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。 -->
</head>
<body>
    <script type="text/javascript">
    function ClassA() {

    }
    ClassA.prototype.color = 'red';
    ClassA.prototype.sayColor = function() {
        document.write(this.color)
    }

    function ClassB() {

    }
    ClassB.prototype = new ClassA();//把 ClassB 的 prototype 属性设置成 ClassA 的实例。
    //调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
    ClassB.prototype.name = 'mike'
    ClassB.prototype.sayName = function() {
        document.write(this.name)
    }
    var objA = new ClassA();
    var objB = new ClassB();
    objA.color = 'red'
    objB.name = 'john'
    objB.color = 'green'
    objA.sayColor()
    objB.sayColor()
    objB.sayName()
    </script>
</body>

</html>

混合继承机制

<html>

<head>
    <title>Example</title>
</head>
<body>
    <script type="text/javascript">
    function ClassA(sColor) {
        this.color = sColor;
    }

    ClassA.prototype.sayColor = function() {
        alert(this.color);
    };
    function ClassB(sColor, sName) {
        ClassA.call(this, sColor);//call()继承机制
        this.name = sName;
    }

    ClassB.prototype = new ClassA();//原型链继承机制

    ClassB.prototype.sayName = function() {
        alert(this.name);
    };
    var objA = new ClassA("blue");
    var objB = new ClassB("red", "John");
    objA.sayColor();
    objB.sayColor();
    objB.sayName();
    </script>
</body>
</html>

javasript中需要注意的一些问题

     var obj = {name:'michael',age:'23',gender:'male'}
     var txt = ''
     for(var i in obj){//这里可以不加 var,直接写‘i’但是会把i 做为全局的变量 window.i
        txt +=obj[i]//obj是一个对象,但是可以这样写 obj[i],因为集合也是对象。
     }
     console.log(txt)//michael23male

javascript页面加载刷新就会自动执行部分脚本,请看下面demo

    <ul>
        <li>click me</li>
        <li>click me</li>
        <li>click me</li>
        <li>click me</li>
    </ul>
    
    var eles = document.getElementsByTagName('li')
   var len = eles.length;
   for(var i = 0;i<len;i++){
      eles[i].onclick = function(){
          console.log(i)// 4 4 4 4
      }
   }
页面加载后会自动把脚本部分执行,执行完脚本,i=4. 当点击li触发onclick事件 此时的i早已是4 

javascript 2种截取字符串的方法 substr 和 slice

  var date = '2016-01-05'
  date.slice(0,7) 
  date.substr(0,7)

MichaelDuan
1.8k 声望39 粉丝