说说JavaScript那些事

今天想说说JavaScript对象的知识点,涉及对象,属性,复杂数据类型,基本数据类型,作用域,继承,this关键字,和window对象等概念。

一,JavaScript对象:

1.1创建对象

在JavaScript世界,我们听的最多的一句话就是:JavaScript里一切皆对象。

的确,JavaScript里的几乎所有东西都是对象或者用起来像对象,就连“my name is sunny”这句普通句子在JavaScript里面表示也是一个对象。

在我们生活的环境,几乎所有的事物都可以看做是对象。

比如,一只猫,猫的毛是白色的,它可以发出“喵喵”的叫声。

那么我们可以这样看,猫毛是猫的属性(特征),叫声就是猫的方法(动作)。

那么在JavaScript里是如何表示对象的呢?

在JavaScript中,对象是由一组用命名值集合而成的容器。

以上面的猫为例

cat

属性 属性值
hair 白色
speak “喵喵”

上面的“cat”就是由一组属性名和所对应值得集合,这些属性和值构成了“cat”,一只白色毛的会说“喵喵”的猫。

然而在JavaScript中是不会用表格去表达的,它是用对象来表达的。

那么上面表格内容转换为实际的JavaScript对象是这样的:

var cat=new Object();
cat.hair="白色“;
cat.speak=function(){"喵喵"}

在JavaScript中的表示可以看出,对象只是属性的容器,每个属性都有一个名称和一个值。

在这里cat只是一个变量,只是通过创建对象(Object)将这个变量表示为了JavaScript对象,然后将一些属性赋值给这个新创建的对象,从而创建出我们的cat对象。

采用Object创建的cat对象是一种Object对象,通过调用Object构造函数而得到的空对象来创建,就是以Object构造函数作为模板来生成预定义对象。

以上的都是指明一个对象,只是表达的方式不一样,一个用表格,一个用“语言”。

我们采用Object对象作为模板创建出一个空对象,其实我们也可以自定义自己的模板对象来创建对象。

<script>
var Person=function(age,hair){//提供生成对象模板
  this.age=age;
  this.getAge=function(){return this.age}
}
var sunny=new Person(22)//对象实例
alert(sunny.getAge())//弹出22

</script>

我们自己定义的Person构造函数可以生成对象sunny,就像原生的array构造函数可以生成数组对象一样,只是一个是自己定义的,一个是JavaScript自带的。

JavaScript实际上是一种预包装若干原生对象构造函数的语言,这些构造函数用来生成一些表达特定类型值

(number,string,function,object,array等)的复杂对象。

1.2构造函数:

构造函数的作用是创建多个共享特定特征和行为的对象,这个对象会提供一些默认的属性和默认的方法。

就是我们上面所说的提供一个模板,然后你们就用这个模板的基础上做出修改或者添加新东西。

总的来说,构造函数在你没有用new来调用时,它也仅仅只是一个普通的函数(function),

但如果你用new来调用时,JavaScript就会赋予这个函数一些不一样的权利,如,此函数内的this值就设置为正在创建的新对象,另外,此函数还会默认返回这个新创建的对象,该返回对象就是构建该对象构造函数的实例。

构造函数返回的对象被称为实例

当一个函数与new关键字一起使用时,它就会创建一个拥有构造函数内部定义的属性和值的对象。

在使用new关键字时,this指向的就是构造函数所创建的对象实例,但如果创建的构造函数没有用new关键字进行调用,那么this指向的就是该函数的“父”对象(方法)。

1.3JavaScript原生的对象构造函数

JavaScript提供了9个原生(内置)对象构造函数,

它们分别是“number,string,Boolean,function,object,array,date,regexp,error”。

JavaScript就是使用这些对象来构造JavaScript语言的。

就是说这些构造函数是不需要我们定义的,直接使用即可。

大家也许会觉得奇怪,怎么没有“Math“?

Math对象和其他的对象是有很大区别,它是一个静态对象,而不是构造函数。

这意味着它是不需要被new出来使用的,它可以直接被使用,如Math.PI。

这里值得注意的是:

Number(),String()和Boolean()构造函数不仅能构建对象也能为字符串,数字和布尔值提供基本数据值,这取决于你是如何使用它们的。

如果直接调用这些构造函数,那么就会返回一个复杂数据值(对象),

如果只是简单的在代码中表示一个数字,字符串或者布尔值(“my name is sunny”,5,true),那么它就会返回一个基本数据值。

1.4:自定义对象构造函数

在里面的例子中,我们可以看到,我们是可以自己创建自己需要的构造函数,从中可以生成多个自定义对象。

<script>
var Person=function(age,hair){
  this.age=age;
  this.getAge=function(){return this.age}
}
var sunny=new Person(22)
alert(sunny.getAge())//
var Kris=new Person(23)
alert(Kris.getAge())//

</script>

通过传递特定的参数和调用Person()构造函数,我们可以创建大量特定的people对象。

当你需要多个举个相同属性但具有不同值得对象时,这是很便捷的。

1.5:字面量值

JavaScript提供了一些创建“字面量”的快捷方式来创建原生对象值,而不必使用new XX()这种方式。

字面量语法:var name="sunny".

需要注意的是,

字符串,数字和布尔值当做字面量使用时,它们的值具有的是基本类型值的特点而不是复杂类型值(对象)的特点。

但是当它们被视为对象的情况下就会拥有复杂对象的特点。

就是说,在尝试使用与构造函数关联的方法或检索属性之前,就一直作为基本数据类型来使用,直到这种情况发生,JavaScript就会在幕后为此字面量创建一个临时的包装器对象,以便将该值视为一个对象。一旦执行完后,JavaScript就会去除掉这个临时的包装器对象,该值就又作为基本数据类型值来使用。这就是为什么尽管我们只是普通的定义一个字符串却还可以调用字符串对象方法的原因。

字面量创建值返回的是基本数据类型值,new创建值返回的是复杂数据类型值(对象)。

string,number和Boolean构造函数是有两种目的创建值的,分别是字面量以及复杂值。

1.5.1访问属性时,字面量值被转换为对象

通过尝试访问属性而将这些字面量值当做对象时,JavaScript将从原始值的相关构造函数创建一个包装器对象,这样就可以访问包装器对象的属性和方法。一旦访问过属性后,包装器对象就会被丢弃。

这种转换使得我们再编写代码时候,可以让字面量值看起来像一个对象。说实话,在代码中将它看做对象时,JavaScript会将它转换成一个对象,从而可以进行属性访问,一旦返回值,就会将它转换会字面量值。

1.6:基本数据类型

10,“sunny”,true,null和undefined等JavaScript值都被视为基本数据类型值,其中null和undefined是不需要构造函数也没有使用new来将自己创建为复杂数据类型值(对象)。

1.7,存储和复制基本数据类型值

我们先看一个例子:

<script>
var str01="sunny";
var str02=str01;
alert(str02);//sunny
str01="Kris";
alert(str02)//sunny
</script>

大家看到没有?

我们把str01的值复制给str02,然后修改str01的值,str02没有受到任何的影响。

就是说基本数据类型值是按值来存储的,而等下我们说到的复杂数据类型值却是按引用来存储值的。

1.7存储和复制复杂数据类型值

我们再看一个例子

<script>
var obj={};
var obj1=obj;
obj.name="sunny";
alert(obj.name+"===="+obj1.name);//都是sunny
obj.name="Kris";
alert(obj.name+"===="+obj1.name);//都是Kris
</script>

当一个改变了另一个也跟着改变,因为他们引用的是同一个引用地址。

注意:

使用new关键字创建String(),Number()和Boolean()值时,或者这些值在幕后被转换成复杂对象时,它们的值依然是按照值来进行存储的。

<script>
var str1=new String("sunny");
var str2=str1;
alert(str1+"======="+str2);//sunny,sunny
str1=new String("Kris")
alert(str1+"======="+str2);//Kris,sunny
</script>

还有一个地方需要注意的是,

指向内存中复杂对象的变量,只有在引用相同地址时才是相等的,相反,两个单独创建的对象,即使具有相同的类型和完全相同的属性,它们也是不相等的。而我们上面的所说的基本数据类型,只要它们的值相同就相等。

<script>
var obj1={name:"sunny"};
var obj2={name:"sunny"};
alert(obj1==obj2)//false
</script>

复杂值是通过引用进行存储和操作的。

创建一个包含复杂对象的变量时,其值是内存中的一个引用地址。

1.8:复杂对象具有动态属性

复杂对象支持动态对象属性,因为我们可以定义对象,然后创建引用,再更新对象,并且所有指向该对象的变量都会获得更新。

JavaScript中的对象是动态的,这使得JavaScript中的对象是可以改变的。也就是说我们可以在原生构造函数上哪存储属性,并在原型对象上,向原生对象额外添加新方法。本质上说,整个JavaScript语言都可以变为自定义版本。如果更改了JavaScript的原生内部运作机制,你可以获得一个自定义版本的JavaScript来进行程序处理。

1.9,指向其构造函数的constructor属性

构造函数实例都拥有指向其构造函数的constructor属性。

任何对象实例化时,都是在幕后将constructor属性创建为对象/实例的属性,这属性是指向创建该对象的构造函数的。

<script>
var str=new String("sunny");
alert(str.constructor===String)//true
alert(str.constructor)//输出string的构造函数代码
</script>

在字面量/基本数据类型值上使用constructor属性都能正确的指向构造函数。

<script>
var str="sunny";
alert(str.constructor===String)
alert(str.constructor)
</script>

constructor属性也适用于用户自定义的构造函数

1.20:验证对象是否是某构造函数实例的instanceof操作符

通过使用instanceof操作符,可以确定(true or false)一个对象是否是某个构造函数的实例,它也是适用于自定义对象。

<script>
var str1=new String("sunny");
alert(str1 instanceof String)//true
var str2="sunny";
alert(str2 instanceof String)//false

</script>

注意的是,基本数据类型就算是当做对象使用(对象包装器)判断也为false,只有用new创建时才为true。

所以,instanceof只适用于构造函数返回的复杂对象和实例。

1.21:返回正在使用值的类型的taype操作符

<script>
var str="sunny";
alert(typeof str)//string

</script>

1.22:构造函数创建的实例可以拥有自己独立的属性和方法

在JavaScript中,对象在任何时候都可以扩展(即动态属性)

<script>
var str1=new String("sunny");//创建一个实例
str1.age=22;//扩展该实例属性
alert(str1.age)//22
var str2="sunny";
str2.age=22;
alert(str2.age)//undefined
</script>

从上面的例子可以看出,字面量不能实现此功能。

除了自己的属性外,实例还可以拥有继承自原型链的属性

二:对象与属性

2.1:用点表示法或中括号表示法获取/设置/修改对象属性

<script>
var Person=function(name){
  this.name=name;
}
var per=new Person("sunny")
alert(per.name);//sunny
alert(per["name"]);//sunny
var str_name="name";
alert(per[str_name]);//sunny
</script>

我们比较常用的是点表示法,但是需要用变量来获取的话,那就只能用中括号表示法。

因为对象可以包含其他对象,所以,obj.obj1.obj2.name来获取属性是很常见的,这就是我们说的“对象链”。

2.2删除对象属性的delete操作符

delete操作符可以用于将属性从一个对象中完全删除。但是delete不会删除在原型链上找到的属性。delete是将一个对象中属性删除的唯一方法,将属性定义为undefined或者null也只是改变了它的值,并没有把属性从对象中删除。

<script>
var Person=function(name){
  this.name=name;
}
var per=new Person("sunny")
alert(per.name);//sunny
delete per.name
alert(per.name);//undefined
</script>

2.3:属性的引用

如果试图访问对象中没有的属性,JavaScript会一直试图在原型链上来找,如果一直找到原型链的末端都没有,那么就会返回undefined。

当试图访问一个对象的属性时,JavaScript会检查该属性的对象实例,如果该实例拥有属性,那么就直接返回该实例中属性值,但是这时候是没有继承发生的,因为利用到原型链。

JavaScript中所有的对象实例独有一个属性,我们称为_proto_的链接,它链接到实例的构造函数,我们可以利用这个链接来获取构造函数,特别是实例构造函数的prototype属性。

我们前面说过,JavaScript中所有皆对象,函数也是一个拥有属性都属性,那么说是对象从其他对象中获得(继承)属性也是可以的。JavaScript通过prototype对象默认的为原生对象完成这些工作,换成我们自己定义的构造函数中,我们也是可以利用原型链的。

<script>
var arry1=["sunny","Kris"];
alert(arry1.length)//2
arry1.push("summer")
alert(arry1.length)//3
</script>

奇怪,我们在创建数组实例的时候并没有为它定义push()方法,那为什么arry1实例却可以使用这个方法呢?

答案就是,push方式是被定义在Array.prototype中的,这样使得所有的数组实例都可以直接使用这个方法,而不需要各自定义,当然如果你是想重写此方法 ,我就无话说。

如果你试图访问一个属性,但该对象不包含该属性时,JavaScript将针对这个属性搜索原型链。

在上面的例子中,JavaScript将查看创建对象(Array)的构造函数,并检验其原型(Array.prototype),看是否可以找到这个属性,如果没有找到,JavaScript将继续搜索初始构造函数背后的构造函数链,一直搜索到链的末端。

由于所有的prototype属性都是对象,所以链中的最后一个连接是Object.prototype。

2.4:使用hasOwnProperty()检查来自非原型链属性的对象

in操作符可以检查一个对象是否含有一个属性,包括来自原型链上的属性。

hasOwnProperty方法可以检查来自非原型链属性的对象。

当需要确定一个属性是对象本地属性还是继承自原型链的属性时,可以使用hasOwnProperty方法。

<script>
var per={name:"sunny"}
alert("name" in per)
</script>
<script>
var per={name:"sunny"}
alert(per.hasOwnProperty("name"))//true
</script>

判断per是否拥有它自己的名为name的一个属性。

2.5:使用for in枚举对象的属性

<script>
var per={name:"sunny",age:1}
for(var i in per){
  if(per.hasOwnProperty(i)){//避免来自原型链
  alert("key:"+i+"val:"+per[i])
}
}
</script>

for in 不仅会遍历特定对象的本地属性(自身属性),还会遍历所继承(通过原型链)的对象上的属性。访问属性的顺序也不总是它们出现在循环内部被定义时的顺序,另外定义属性的顺序也不一定是访问它们的顺序。

fo

三:JavaScript的常用对象

3.1:Object()对象

我们可以使用内置的Object()构造函数创建动态的普通空对象,这个对象是没有预定义属性和方法的。

Object()拥有prototype属性。

原型链是以Object.prototype结尾的,所以Object()的所有属性和方法都被所有JavaScript对象继承。

Object.prototype是JavaScript寻找值的最后一个位置。

3.2Function()对象

函数是代码语句的容器,可以使用圆括号操作符()来调用.调用函数时,参数可以在圆括号内传递,以便函数中的语句可以访问这些特定值。

函数可用于返回值,构建对象,或者单纯的作为简单的代码运行。

Function()拥有prototype属性。

JavaScript函数是对象,

这意味着函数可以存储在一个变量,数组或者对象中。

函数总是有返回值,如果没有指定返回值,则会返回undefined。

3.2.1函数的参数

在调用函数时,参数是将值传递给函数作用域的工具,在JavaScript中省略参数是合法的,即使定义了接收这些参数,省略的参数会被赋予了undefined值。

如果传递的参数数量多于定义的参数数量,也是合法的,这时候可以从arguments对象中访问这些参数。

3.2.2:this和arguments适用于所以函数

arguments对象是一种类数组对象,它包含所有传递给函数的参数,即使在定义函数时不指定参数,在调用时还是传入参数,我们就可以利用arguments数组来访问。

<script>
var fun=function(){
  alert(arguments[0])
};
fun("hi")//hi
</script>

传递给所有函数的this关键字都是对包含函数的对象的引用,就是说,作为属性包含在对象内的函数(即方法),可以使用this来获得对“父”对象的引用,当函数在全局作用域中定义时,this值就是全局对象。

<script>
var per1={
  name:"sunny",
  fun:function(){return this}//object 这里指向的是per1这个对象
}
alert(per1.fun())
var fun2=function(){return this}
alert(fun2())//window
</script>

对象属性是可以带双引号的。

3.2.3arguments对象中的callee属性

arguments中有一个名为callee属性,它是对当前执行函数引用。该属性可以用于从函数的作用域内引用函数本身--自用引用。

<script>
var fun=function fun(num){
alert(num)
arguments.callee(333)
}
fun(222)
</script>

3.2.4:代码没有执行完成前取消函数执行的return关键字

可以通过返回有值或无值的return关键字在条用时随时取消函数的执行,也就是通过return可以在函数的任意点取消函数的执行。

<script>
var fun=function(){
  return
  alert(2222)

}
fun()
</script>

3.2.5:函数的定义(声明)

函数的定义有三种不同的方式:函数构造函数,函数声明和函数表达式。

函数构造函数(不推荐)数据类型转换会很麻烦。

<script>
var fun1=new Function("num1","num2","return num1+num2")//最后哦一个参数是函数体
alert(fun1("1","2"))
</script>

函数声明

<script>
function fun(num1,num2){
alert(num1+num2)
}
fun(1,2)
</script>

函数表达式

<script>
var fun=function(num1,num2){
  alert(num1+num2)
}
fun(1,2)
</script>

注意的是:

使用不带圆括号的函数名是访问函数指针,而非调用函数。

3.2.6函数声明与函数表达式

用函数声明方式或函数表达式方式定义的函数在被解析时所执行的方式并不是一样的。

在被解析时,解析器会优先读取函数声明,并使其在任何代码之前可用,也就是说定义的函数的语句可以在调用函数语句的后面。

至于函数表达式,则必须等到解析器执行到它所在的代码行时,才会真正被解析执行,也就是说调用它的语句必须在定义它的语句后面。

我们都知道,解析器,这里就说浏览器吧,在解析JavaScript代码时候,都是一行一行从上往下顺序执行的,但如果你是用函数声明方式定义出的函数,那么浏览器在加载时候就会优先解析它们,而用函数表达式的函数就只能按正常的流程处理了。

3.2.7函数的调用

作为函数:fun();

作为方法:obj.fun();

作为构造函数:new fun()

使用apply()或call()方法:apply(fun,"参数1“,“参数2”),call(fun,["参数1",“参数2”])

call()与apply()之间的区别是函数调用时,参数传递的不同,前者传递多个以逗号分开的参数,后者传递多个参数组成的数组。

3.2.8,匿名函数

匿名函数值得是没有给出名字的函数,一般用在将函数作为参数传递给另一个函数。

<script>
var fun=function(fun2){
  fun2()
}
fun(function(){alert(2)})
</script>

3.2.9,自调用的函数表达式

通过圆括号操作符,可以在定义函数表达式后立即调用函数(除用function()构造函数创建的函数)

<script>
var fun=function(num){
  alert(num)
}(2)
</script>

3.2.10自调用的匿名函数语句

<script>
(function(num){
  alert(num)
})(2)
(function(num){
  alert(num)
}(3))
</script>

3.2.11函数可以调用自身(递归)

<script>
var fun=function fun(num){
alert(num)
fun(333)
}
fun(222)
</script>

四:this关键字

创建函数时,系统会创建一个名为this的关键字,它链接到运行该函数的对象。

this对其函数的作用域是可以见的。

this是在函数内部使用,用来引用包含函数的对象,而不是函数本身,使用new或call()和apply()的情况除外。

this值是基于在运行时调用函数的上下文。

4.1:在嵌套函数中用this引用的是window对象

因为在嵌套函数中,this失去了方向,所以引用的就是window对象而不是定义函数所在的对象。

<script>
var obj={
   fun1:function(){
    alert(this)//object
    var fun2=function(){
      alert(this)//window
    }()
  }
}
obj.fun1()
</script>
<script>
var fun=function(fun2){
  fun2()
}
fun(function(){alert(this)})//windown匿名函数内的this指向的window
</script>
<script>
var obj={
   fun1:function(fun){
    alert(this)//object
    fun()//window
    var fun2=function(){
      alert(this)//window
    }()
  }
}
obj.fun1(function(){alert(this)})
</script>

当this值的宿主函数被封装在另一个函数的内部或在另一个函数的上下文被调用时,this值都是对window的引用。

可是我们想在嵌套函数中this指向父对象,该怎么做呢?

可以在父函数中使用作用域链来保留对this的引用,以便this值不丢失。

<script>
var obj={
   fun1:function(fun){
    alert(this)//object
    var that=this//在父函数中保留this到that变量中
    fun()//window
    var fun2=function(){
      alert(that)//object
    }()
  }
}
obj.fun1(function(){alert(this)})
</script>

4.2:使用call()或apply()控制this值

我们都知道this值通常取决于调用函数的上下文,除了后面我们将要说的new创建函数,但我们可以使用apply()或call()来重写this的值,以便在调用函数时定义this指向哪个对象。

使用这个方法就好像在说,“我在调用的是X函数,但是你要告诉X函数把Z对象作为this值使用”

这样做可以改变JavaScript中决定this值的方式。

<script>
var obj={

}
var fun=function(name){
  this.name=name;
    alert(this.name)

}
fun.call(obj,"Kris")//obj中的this设置为fun中的this
alert(obj.name)
</script>

4.3,自定义构造函数内部使用this关键字

在使用new关键字调用函数时,this值(在构造函数中声明)引用实例本身。

<script>
var Person=function(name){
  this.name=name;
}
var per1=new Person("sunny")
</script>

当我们用Person创建出per1这个对象(实例)时,Person中的this指的就是per1这个对象。

使用new关键字调用构造函数时,this引用的是“即将创建的对象”,

如果不使用new关键字,this值将是调用函数的上下文。

4.4:原型方法内的this关键字引用的是构造函数实例

当在添加至构造函数的prototype属性的的函数中使用this,this引用的是调用方法的实例.

<script>
var Person=function(name){
  this.name=name;
}
Person.prototype.getName=function(){//向person.prototype添加getname方法以便所有的person实例都能继承该方法
  alert(this.name)//this引用的是调用它的实例,这里是per1
}
var per1=new Person("sunny")
per1.getName()//sunny
</script>

如果this指向的实例或者对象不包含被引用的属性,其他关于属性查找规则在这里也同样适用,将在原型链上查找属性。在我们这个例子中,如果getName()在实例中找不到name属性,那么将先在Person.prototype中查找,如果找不到就在Object.prototype中查找,如果都没有则返回undefined。

五,作用域和闭包

在JavaScript中,作用域就是执行代码的上下文。

作用域有三种类型:全局作用域,局部作用域(函数作用域)和eval作用域。

在函数内部使用var定义的变量,其作用域是局部的,它只对该函数的其他表达式是“可见的”,包括嵌套/子函数中的代码。

5.1JavaScript是没有块作用域的

<script>
var name="sunny";
if(true){
  name="sunny1";
  for(var i=0;i<5;i++){
name=i;
alert(name)//0,1,2,3,4
  }
}
</script>

由于逻辑语句(if)和循环语句(for)无法创建作用域,所以变量时可以互相被覆盖的,所以代码执行时候,变量name的值是变化的。

5.2作用域链

当JavaScript查找与变量关联的值时,会遵循一个查找链。

<script>
var name="sunny";
function fun(){
  alert(name)
}
fun()
</script>

当name值不包含在fun函数的作用局时,JavaScript是如何找到它的?

JavaScript首先在fun函数中查找一个名为name的变量,如果在fun函数中找到,就会使用fun函数中的name属性值,这时候就会停止查询。

但如果在fun函数中没有找到,那么就会在fun的父函数,这里是window查询,如果在全局作用域中还是没有找到,那么就会返回undefined。

当作用域链内最近的位置查找到变量时,查找即结束,不管作用域链顶部是否还有相同的变量名称。

5.3函数是在定义的时候确定作用域,而不是在调用时候确定

函数决定作用域,并且函数可以像任何JavaScript值那样被传递。

作用域链是根据函数定义时候的位置确定的,而不是在调用时候确定,正因为这样,我们可以创建闭包。

如我们可以让函数向全局作用域返回一个嵌套函数,但该函数仍然可以通过作用域访问其父函数的作用域。

<script>
var fun=function(){
  var name="sunny";
  return function(){
    alert(name)
  }
};
var fun01=fun();//将fun返回的匿名函数赋值给变量fun01
fun01()
</script>

这里的匿名函数被定义包含在fun函数内部,所以它被调用后仍然可以访问fun函数的作用域。

由于作用域是在函数定义时确定的,所以在函数内部传递代码不会改变作用域链。

六,函数原型属性

prototype属性是JavaScript为每个function()实例创建的一个对象,使用prototype属性(它是一个对象),以便让构造函数实例继承属性和方法,这是JavaScript本身允许对象实例从构造函数的prototype属性继承属性和方法的机制。

前面我们说过一个例子,join()方法并没有定义在Array()对象实例中,为什么每个Array()实例却可以调用此方法呢?

这是因为join()方法是被定义在一个地方,它被定义在Array()构造函数的prototype属性中。由于在数组实例对象中没有找到join()方法,因此,JavaScript会在原型链中查找join()方法。

6.1将构造函数创建的实例链接至构造函数的prototype属性

虽然原型只是一个对象,但它是特殊的,因为原型链将每个实例都链接至其构造函数的prototype属性。

<script>
Array.prototype.name="sunny";
var ayy=new Array();
alert(ayy.constructor.prototype.name);//sunny,通过访问constructor.prototype访问name
alert(ayy.name);//sunny 或者使用链访问name
</script>

6.2原型链的最后是Object.prototype

前一个例子中,JavaScript在访问name属性时,首先会在arry对象中查找,如果没有找到就会在Array.prototype中查找该属性,如果还是没有找到,就在Object.prototype中查找,都没有找到就放回undefined。

要记住的是,一旦在链中找到属性,查找即结束,即使链中其他地方也存在相同的属性名称。

6.3用新对象替换prototype属性会删除默认构造函数属性

可以用一个新值来替换prototype属性的默认值,然而这样会删除在原型对象中找到的默认constructor属性,除非自己手动指定一个。

<script>
var fun=function(){};
fun.prototype={}//使用空对象替换prototype属性
var fun01=new fun();
alert(fun01.constructor===fun)//false
</script>

6.4继承原型属性的实例总是能够获取罪行值

实例总是可以从原型获得最新的值而不管它是何时被实例化,更改或者附加的。

<script>
var fun=function(){};
fun.prototype={name:"sunny"}
var fun01=new fun();
alert(fun01.name)//sunny
fun.prototype.name="summer";//用普通值替换prototype属性
alert(fun01.name)//summer

</script>

6.5,用新对象替换prototype属性则不会更新以前的实例

<script>
var fun=function(){};
fun.prototype={name:"sunny"}//
var fun01=new fun();
alert(fun01.name)//sunny
fun.prototype={name:"summer"};
alert(fun01.name);//sunny
var fun02=new fun();//创建一个新的实例
alert(fun02.name)//sunmmer

</script>

一旦开始创建实例,就不应用一个新对象来替换对象的原型,这样将导致实例用一个指向不同原型的链接

6.6,用户自定义构造函数像原生构造函数一样有原型继承

<script>
var per=function(){};
per.prototype.name="sunny";
per.prototype.getName=function(){return this.name};

var per1=new per();
alert(per1.getName())//sunny

</script>

6.7,创建继承链

继承只是一个对象可以访问另一对象的属性

<script>
var per=function(){};
per.prototype.name="sunny";
per.prototype.getName=function(){return this.name};

var newper=function(){};
newper.prototype=new per()
var newper1=new newper();
alert(newper1.getName())//sunny

</script>

具体的做法是,实例化想要继承的对象,将该对象实例作为要继承该对象实例的函数的prototype属性值即可。

其他

JavaScript sort() 方法

sort用于对数组的元素进行排序

arrayObject.sort(sortby)

sortby参数可选。规定排序顺序。必须是函数。返回值是排序后的数组。

如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。

如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。

没有参数按字母排序。

<script type="text/javascript">

var arr = new Array(6)
arr[0] = "10"
arr[1] = "36"
arr[2] = "4"
arr[3] = "25"
arr[4] = "1000"
arr[5] = "1"

document.write(arr + "<br />")
document.write(arr.sort())

</script>

因为sort()方法排序,是基于ASCII值进行排序的。故它会认为36小于4(因为3的ASCII值小于4的ASCII值)。所以要对排序的sort()方法定义一个比较函数:

数组自定义排序

<script type="text/javascript">

function sortNumber(a,b)
{
return a - b
}

var arr = new Array(6)
arr[0] = "10"
arr[1] = "36"
arr[2] = "4"
arr[3] = "25"
arr[4] = "1000"
arr[5] = "1"

document.write(arr + "<br />")
document.write(arr.sort(sortNumber))

</script>

a,b表示数组中的任意两个元素,

若return > 0 b前a后;

reutrn < 0 a前b后;

a=b时存在浏览器兼容

简化一下:a-b输出从小到大排序,b-a输出从大到小排序。

时间: 2024-11-11 18:43:43

说说JavaScript那些事的相关文章

JavaScript 你不知道的事 -- 关于函数

接上篇Javascript 你不知道的事,直接条列了: 每个函数创建时默认带有一个prototype属性,其中包含一个constructor属性,和一个指向Object对象的隐藏属性__proto__.constructor属性的值为该函数的对象.在一个函数前面加上new来调用,则会创建一个隐藏连接到该函数prototype成员的新对象(由__proto__属性来链接),同时函数的this将会被绑定到那个新对象上. 函数总是返回一个值:如果没有指定返回值,就返回undefined:如果当做构造函

Javascript 你不知道的事

NaN表示一个不能产生正常结果的运算结果.它不等于任何值,包括它自己.可以用isNaN(number)来检测. 同Java中的字符串一样,JS中的字符串是不可变的.也就是说一旦字符串被创建,就无法改变.下标表达式(如s[3],代替s.charAt(3))可以读取字符,但是不能用于改变字符. null,undefined,空字符串'',0,NaN被当做false,其余的值(包括"false")或对象都被当做true.所谓的“被当做”并不是说这些值就是布尔值true,例如true==&qu

Javascript 你不知道的事,好吧,是我不知道的事

NaN表示一个不能产生正常结果的运算结果.它不等于任何值,包括它自己.可以用isNaN(number)来检测. 同Java中的字符串一样,JS中的字符串是不可变的.也就是说一旦字符串被创建,就无法改变.下标表达式(如s[3],代替s.charAt(3))可以读取字符,但是不能用于改变字符. null,undefined,空字符串'',0,NaN被当做false,其余的值(包括"false")或对象都被当做true.所谓的“被当做”并不是说这些值就是布尔值true,例如true==&qu

javascript那些事(1)

最近看到winter(寒冬)老师的一篇博文,说的是js这类基于原型的继承与普通的基于类继承方式的差异.文章最后抛出几个有意思的小练习尝试的解决了下. 一般来说,创建一个对象有如下三个步骤: 1. 构建一个新对象 2. 把新对象的__proto__指向函数对象的共有对象属性:prototype 3. 以新对象为this执行构造函数 Function.prototype.prop=1; alert(Object.prop) alert(Function.prop) 输出:1, 1 怎么理解呢? 首先

JavaScript那些事

1.定义静态常量:     const C=1; 该常量不能变化的. 2.在if判断中如果是两个变量比较js会将一个字符和一个数字比较的话,会将字符转换成数字然后在对这两个进行对比: 1 var num=100; 2 var numStr="100"; 3 document.write(num==numStr);//true 4 document.write(num===numStr);//false 3.Boolean变量创建 1 var bl=new Boolean("&

《数据结构与算法 Javascript描述》读书笔记

当初买这本书的原因,在意的是有没有什么令人惊喜的东西,特别是针对Javascript代码的奇思妙想,所以就买下了这本书. 在买的几本书里面,最先看的也是这一本,但看起目录就觉得不大妙,翻起内容时候,才发现真不是那么的新奇的东西,甚至来说几乎不关Javascript的事. 我知道作者讲的是数据结构思想的东西,但是真跟Javascript没关系.作者几乎是把C语言算法的那一套搬到Javascript,看得我直满满都是C语言的影子.我不是排斥Javascript来讲算法的东西,只是觉得Javascri

Angular之双向数据绑定

---恢复内容开始--- angular最初进入前端开发人员视野的时候,给人以不可磨灭的印象之一就是它的双向数据绑定的实现.本篇章会先介绍如何使用此功能,然后在深入解释它的双向绑定的机制是如何实现的. angular中的data-binding指的是模型models和视图views之间的自动同步.angular实现双向绑定后,会让你觉得数据模型是页面中数据唯一的真实来源.当model改变后,视图反映改变,反之亦然.通俗的说,所谓的双向数据绑定,无非就是从界面的操作能实时反映到数据,数据的变更能实

那些让 Web 开发者们深感意外的事情

作为 Web 开发者,对自己的行业前景,人人都有自己的看法,然而,任何行业都有出人意料的地方.著名的 Web 开发设计博客 Nope.com 曾向他们的读者做了一个调查,请他们列举 Web 开发领域那些让他们感到意外的事情,收到了各种各样的反馈,本文就是这次调查的结果与分析. 一个真正的符合 Web 标准的 IE 这个消息让我们振奋,在经过 9 个版本更替后,我们终于看到了(或者说即将看到)一个真正符合 Web 标准的 IE 浏览器.在 Web 开发设计界,人们对 IE 的忍耐到达了极限,最终,

大前端开发者需要了解的基础编译原理和语言知识

转自:https://yq.aliyun.com/articles/180879 在我刚刚进入大学,从零开始学习 C 语言的时候,我就不断的从学长的口中听到一个又一个语言,比如 C++.Java.Python.JavaScript 这些大众的,也有 Lisp.Perl.Ruby 这些相对小众的.一般来说,当程序员讨论一门语言的时候,默认的上下文经常是:“用 xxx 语言来完成 xxx 任务”.所以一直困扰着的我的一个问题就是,为什么完成某个任务,一定要选择特定的语言,比如安卓开发是 Java,前