JS是一种事件驱动型语言, 只有当浏览器要执行事件时才会执行JS代码。
浏览器产生事件之后,JS的事件管理器会先到事件队列中查找与此类事件相关的处理方法(即绑定了相应事件的函数), 如果存在,则会执行绑定了相应事件的JS代码(函数), 如果没有找到一个函数绑定了相应事件,则会丢弃这次事件的请求
JS的属性:
JS的属性分为两种类型, 一种是基础类型, 一种是对象类型。
对象属性又分为object对象和function对象
基础类型的属性不能再包含属性
对象类型的属性可以再包含自己的属性
JS内存模型:
在内存中,直接量通过两块内存分别保存属性名和属性值
对象需要三块内存, 分别保存属性名、属性地址和 属性内容 即 属性名指向属性对应的地址, 而该属性存储在另一块空间中
function类型和function对象
创建function:
创建function有两种方式:
①函数声明:
function 函数名 (形参) {函数体}
②函数表达式:
var 变量名 = function (参数列表) {函数体} 省去了函数名, 但是前面用一个变量保存函数对象的地址
两种创建函数方式的关系:
在JS中所有的数据只有两种形式,要么是对象的属性, 要么是变量。
无论是对象的属性还是变量, 在内存中都是名值对的结构
因为函数是对象, 所以也应该是名值对的结构
通过声明方式创建函数时, JS首先创建了函数对象, 然后又创建了和函数名同名的变量, 并将创建出来的函数赋值给了这个变量
函数本身也是对象:
JS中的函数本身也是对象, 那么就可以有自己的属性, 函数的属性一般是使用点操作符来操作的, 可以通过点来给对象的属性进行赋值, 如果属性不存在则会直接创建该属性, 如果存在, 则可以对其中的内容进行修改
函数的属性可以是直接量, object对象和 function对象中的任意一种, 如果function对象类型的属性, 还可以通过点操作符来调用,示例代码如下:
function Func () {
}
Func.val = "I am Func";
a = "a";
a = "b";
Func.logVal = function(){
console.log(this.val);
}
Func.logVal();
进入strict模式:
可以在文件或者函数内部使用"use strict" 字符串进入严格模式, 推荐以function级的严格模式, 因为可能有时会用到其他人的代码
调用子函数和嵌套函数中查找变量的区别:
使用嵌套函数,变量会从作用域链的上部往下依次找, 即从内层往外层依次找
调用子函数不会使用主调函数中的变量
var v = 0; //定义全局变量
function logV() {
console.log(v); //这里因为函数内部没有定义变量v, 所以会使用全局的v, 但是不会使用其他函数中的值
//因为他们并不是存放在一块内存区域,他们不在一个作用域链中
}
function f (){
var v = 1; //定义函数内部变量是v, 作用域是function 级
logV(); //调用子函数
}
闭包:
在JS中, 函数就是一块保存了现有数据的内存, 只要找到这块内存就可以对其进行调用。 想办法获取内部定义的嵌套函数,就可以在外部使用嵌套函数来调用内部的局部变量, 这种用法就是闭包。
function f1 (){
var v = 1;
function f2(){
console.log(v);
}
return f2;
}
var f = f1(); //通过调用外层函数来获取内部的嵌套函数对象的地址, 然后赋值给f, 这样f就指向了这块空间, 则可以通过f调用内层函数
//进而使用内部的局部变量 v;
f();
在使用闭包时, 在保存返回函数的变量失效之前定义闭包的function 会一直保存在内存中
当function的函数体返回一个对象类型时, 使用new关键字创建的对象就是返回的对象 而不是function所对应的对象
function F(){}
function Car (color, displacement){
this.color = color;
this.displacement =displacement;
return new F(); //此时返回的是通过new创建的F函数类型的对象,而不是这个F函数对象
}
var car = new Car("black", "2.4T"); //因为构造函数Car中最后返回了 F类型的对象, 所以car指向的是那个新建的F函数对象类型的类型的对象
console.log(car.color + ", "+ car.displacement); //undefined, undefined;
console.log(car instanceof Car); //false;
console.log(car instanceof F); //true;
prototype 注意事项:
prototype 可以实现继承和多层继承
function log(msg){ //创建一个名称为log 的函数对象
console.log(msg);
}
function Person(){} //创建一个名称为 Person 的函数对象
Person.prototype.logPerson = function(){ //给函数对象Person 的 prototype属性添加一个名称为 logPerson的function对象类型的属性
log("Person"); //调用子函数log
}
function Teacher() { //创建一个名称为Teacher的function对象
this.logTeacher = function(){ //给通过Teacher创建出来的对象创建 名称为logTeacher的 function对象类型的属性
log("teacher"); //调用子函数log
}
}
Teacher.prototype = new Person(); //让Teacher 的 prototype属性指向 一个 Person函数对象类型的对象
Teacher.prototype.logPrototype = function(){ //给Teacher的prototype属性再添加一个 logPrototype 属性
log("Prototype"); //调用子函数log
}
var teacher = new Teacher(); //创建Teacher 函数对象类型的对象teacher
teacher.logTeacher(); // 先查看自己是否有这个属性, 有, 则调用自己的属性
teacher.logPrototype(); // 先查看自己是否有这个属性, 没有, 则到 Teacher 的prototype 属性中查找是否有这个属性, 有, 则调用
//Teacher 的 prototype属性的logPrototype属性
teacher.logPerson();
//先查看自己是否有这个属性, 没有, 则到 Teacher的 prototype属性中查找是否有这个属性, 没有,
//因为Teacher的prototype属性指向了一个 Person函数对象类型的对象, 所以会到Person 的prototype属性中查找是否有这个属性, 有
//则调用Person 的 prototype属性的 logPerson属性
prototype 是属于 function 类型对象的属性
function 类型对象的 prototype 属性是 object 类型的对象
一:
function 类型对象的 prototype 属性对象的属性 可以被 function 类型对象所创建的 object类型的实例对象使用,
但是object类型的实例对象自身并没有prototype 属性
二:
如果要给 function 对象的 prototype 属性赋予新的值并且又要添加新的属性, 则应该先赋予新的值, 再添加属性。
否则再赋值时, 会出现找不到给赋值之前的 prototype 对象, 进而就找不到之前添加的属性
总结:
function创建的对象在调用属性时, 是按照prototype 链依次查找的, 而不是将 prototype中的属性关联到创建的对象本身,
因此创建完对象后, 再修改function 的 prototype 也会影响到创建的对象的调用
prototype 中的属性是动态查询的。
prototype除了可以实现继承外, 还可以节约内存, 因为无论使用function 创建多少对象, 他们所指向的prototype 对象在内存中都只有一份
但是prototype 中的属性比直接使用对象中定义的属性在执行效率上要低一些
object类型对象:
创建 object类型对象的三种方法:
①:通过花括号创建
var obj = {
v:6,
innerObj: {
v: 7
},
logV: function(){
console.log(this.v);
}
}
console.log(obj.v); //6
console.log(obj.innerObj.v); //7
console.log(obj.logV); //6
②: 使用function类型对象 创建:
function F(){
this.name = "liu";
}
var obj = new F(); //通过函数对象来创建 object对象
console.log(obj.name);
3: 通过 Object.create 方法创建
var obj = Object.create(
//prototype参数是一个 object 类型的对象, 所以可以用花括号创建
{
type: "by create"
}, //调用函数时,多个参数用逗号隔开
//propertiesObject参数也是一个 object类型对象, 也可以用花括号创建
{
color: { //创建color属性
value: "red",
enumerable: true
}, //花括号创建对象时多个属性用逗号隔开
size: {
value: "37",
enumerable: true
}
}
);
//该obj对象自身只有两个属性 color 和 size
console.log(obj.type); //"by create" 现在当前 object类型对象中找该属性, 没有, 则会去 prototype 属性对象的属性中去找
console.log(obj.color); //red;
console.log(obj.size); //37;
console.log(Object.getOwnPropertyNames(obj));// 获取obj自己拥有的属性 //Array(2) ["color", "size"]
调用 object对象属性的两种方法:
1, 直接通过点操作符调用
2, 通过方括号调用, 当要调用的属性名是一个变量时, 只能由方括号调用
注意点:
对于用花括号和function对象创建的对象, 都可以直接调用 Object 的 prototype 属性对象的属性
但是对于用 Object.create 属性创建的对象, 如果第一个 prototype 参数传递的是null, 则创建出的对象不能直接调用Object 的prototype 属性对象的属性
使用花括号创建的对象, 其constructor指向的是Object 函数对象