创建函数,3种:
1 声明:只有声明方式创建的函数才能被声明提前
function fun(arg1, arg2, ...){ statement; return value;}
2 函数直接量:无法被声明提前
var fun = function(arg1, arg2, ...){ statement; return value;};
揭示:函数其实是一个对象,函数名仅仅是一个引用函数对象的普通变量。
3 用new:
var fun = new Function("arg1", "arg2", ..., "statement; return value;");
重载(overload):相同函数名,不同参数列表的多个函数,在调用时,根据传入参数的不同,自动选择匹配的函数执行
目的目的:减少API的数量,减轻调用者的负担
when:如果多个函数只是流程不同,其实都是一类事,就可以将多个函数命名为同名函数,不同参数
how:js语法不支持重载!js中后定义的同名函数会覆盖先定义的。
arguments:函数中自动接收所有传入函数的参数值的类数组对象。
类数组对象:长得像数组的对象
类数组对象和数组的相同点:都用[i]方式访问每个元素;length属性记录元素的个数;for循环遍历每个元素。
对象的创建,3种:
1 对象直接量:
var obj = {
属性名: 属性值;
...,
方法名: function(){},
...
};
注意:每个属性名和方法名不用加引号,但是底层都是用字符串存储。
this:引用当前正在调用函数的对象!
和定义在哪个对象中无关!只和调用时 . 前的对象有关!
固定场景:a.在对象自己的方法中,访问自己的属性
b.在构造函数中,指代正在创建的新对象
c.在原型对象的共有方法中,指代将来调用共有方法的子对象
注意:不是任何对象直接调用的函数中this默认指window对象。
when:对象自己的方法中,想访问对象自己的属性必须用 this.属性名
2 使用new:
var obj = new Object();//创建一个Object类型的空对象
obj.属性名 = 属性值;//等效于 obj["属性名"] = 属性值;
...
obj.方法名 = function(){... this.属性名 ...};
when:如果在创建对象时,暂时不知道包含哪些属性,就先创建一个对象,再添加属性
注意:js中的对象,可以随时添加新属性,只要给不存在的属性赋值,就自动添加
本质:js中一切对象都是hash数组:
a.都可以随时添加新的属性和方法
b.访问对象中一个不存在的属性,返回undefined
c.属性名和方法名其实相当于hash数组中的key
d.都可用for in遍历每个属性
3 反复创建多个相同类型和结构的对象;
a.定义构造函数,描述一类对象的统一结构
构造函数:描述一类对象的统一结构德函数
when:只要反复创建相同结构的多个对象前,都需要先定义构造函数,再创建对象。
how:
function 类型名/构造函数名(属性参数列表){
this.属性名 = 属性参数值;
...
this.方法名 = function(){
... this.属性名...
}
}
b.使用new调用构造函数创建对象并添加属性
var obj = new 构造函数名(属性值列表);
构造函数中的this,指new正在创建的对象
面向对象:
原型和原型链:
原型:保存所有子对象的公共成员的父级对象
每个构造函数,都有一个prototype属性,引用自己的原型对象
每个子对象,都有一个 __proto__ 属性,继承自构造函数的原型对象
继承:父对象的成员,自对象无需创建,可直接使用!
对象创建:
a.创建空对象
b.设置新对象的 __proto__ 属性继承构造函数的原型对象
c.调用构造函数,添加成员
d.返回地址
when:同一类型的子对象共享的属性和方法,都要放在构造函数的原型对象中。
优点:代码重用,节约内存!
删除属性:
a.自有属性: delete 对象.属性名;
b.共有属性:只能通过构造函数的原型对象删除 delete 构造函数.prototype.属性名
判断自有属性与共有属性:
a.判断自有属性:判断指定属性是否直接保存在当前对象本地
var isSelf = obj.hasOwnProperty("属性名");
true:是自有属性
false:无法确定是否为共有
b.判断共有属性:同时满足两条件:
不是自有: obj.hasOwnProperty("属性名") == false;
但是在原型中有: obj.属性名 !== undefined
<script type="text/javascript"> //String类型支持trim(),去掉前后的空格 //如果当前浏览器不支持trim if(String.prototype.trim === undefined){ console.log("当前浏览器不支持trim(),自定义trim()"); String.prototype.trim = function(){ return this.replace(/^s+|s+$/g, ""); }; } var str = " hello js, I like "; console.log(":" + str + ":"); str = str.trim(); console.log(":" + str + ":"); </script>
总结:不使用 obj. 方式访问对象,都去作用域链找,只要使用 obj. 访问成员,都去原型链找。
原型相关API:
1. 获取原型对象,2种:
a. 构造函数.prototype
b. 子对象.__proto__ :内部属性,可能被禁用
尽量使用Object.getPrototypeOf(子对象);
2. 判断对象间是否有继承关系:
var hasInherit = 父对象.isPrototypeOf(子对象);
3. instanceof:判断一个对象是否是指定构造函数的实例
function Student(){};
var jack = new Student();
jack instanceof Student -> true
多态:同一事物,在不同情况下表现出不同样子
重写:override:如果子对象觉得父对象的成员不好用,可在本地定义同名成员,覆盖父对象的。
在原型对象中
如何添加共有属性:只能通过原型对象
构造函数.prototype.属性名 = 值;
原型链:由各级对象的 __proto__ 逐级继承形成的链式关系
规则:在访问对象属性时,只要自己有,就不去父级找,如果自己没有,才去父级找,如果到Object.prototype都没找到,就返回undefined。
和作用域链的比较:
作用域链:控制变量的使用顺序:所有不带.的变量,默认都去作用域找
原型链:控制对象的属性的使用顺序:所有用.访问的对象属性,都去原型链找
每个对象内部有一个属性: class 记录了创建对象时使用的类型名
访问对象内部的class: 只能调用原生的toString()
Object.prototype.toString();//"[object Object]"
对象 class
强行调用原生toString():
原生toString.call(替代this的对象)
call做两件事:a.执行函数;b.替换this
Object.prototype.toString(); this->Object.prototype
Object.prototype.toString.call(obj); this->obj->在执行时,相当于obj.toString()
<script type="text/javascript"> //判断一个对象是否是数组 var obj1 = {};//Object var obj2 = [];//Array var obj3 = function(){};//Function var obj4 = {}; obj4.__proto__ = []; //typeof无法区分数组和对象 console.log(typeof obj1);//object console.log(typeof obj2);//object console.log(typeof obj3);//function console.log(typeof obj4);//object console.log("=================="); //1. isPrototypeOf 不但检查直接父对象,而且检查整个原型链 console.log(Array.prototype.isPrototypeOf(obj1));//false console.log(Array.prototype.isPrototypeOf(obj2));//true console.log(Array.prototype.isPrototypeOf(obj3));//false console.log(Array.prototype.isPrototypeOf(obj4));//true console.log("=================="); //2. constructor 也可检查整个原型链 console.log(obj1.constructor == Array);//false console.log(obj2.constructor == Array);//true console.log(obj3.constructor == Array);//false console.log(obj4.constructor == Array);//true console.log("=================="); //3. instanceof 也可检查整个原型链 console.log(obj1 instanceof Array);//false console.log(obj2 instanceof Array);//true console.log(obj3 instanceof Array);//false console.log(obj4 instanceof Array);//true console.log("=================="); //4. 每个对象内部有一个属性: class 记录了创建对象时使用的类型名 console.log(Object.prototype.toString.call(obj1) == "[object Array]");//false console.log(Object.prototype.toString.call(obj2) == "[object Array]");//true console.log(Object.prototype.toString.call(obj3) == "[object Array]");//false console.log(Object.prototype.toString.call(obj4) == "[object Array]");//false console.log("=================="); //5. ES5: isArray if(Array.isArray === undefined){ console.log("Array.prototype.isArray not exsit."); Array.isArray = function(obj){ return (Object.prototype.toString.call(obj) == "[object Array]"); }; } console.log(Array.isArray(obj1));//false console.log(Array.isArray(obj2));//true console.log(Array.isArray(obj3));//false console.log(Array.isArray(obj4));//false </script>
自定义继承:
a.仅修改一个对象的父对象:
子对象.__proto__ = 父对象;
Object.setPrototypeOf(子对象, 父对象);
b.直接修改构造函数的原型对象,可同时修改之后创建的所有子对象的父对象:
时机:必须在创建第一个对象之前完成,才能保证对象间的一致性。
c.两种类型间的继承:即扩展结构(extends),又继承原型(inherit)
抽象:将多个子类型的相同属性和方法,集中提取到一个公共的父类型中定义。
how:3步:
c1. 将多个子类型的相同属性和方法,抽象到一个公共的父类型中集中定义
c2. 借用构造函数:在子类型构造函数中调用父类型构造函数
问题:如果直接调用父类型构造函数:this->window
解决:强行调用,更换this:父类型构造函数.call(this, 参数1, 参数2, ...);
问题:call要求每个参数都要重复写一遍
解决:使用apply传入arguments,apply可打散arguments,再单独传入:父类型构造函数.apply(this, arguments);
总结:只有两个API可打散数组参数:
arr1.concat(arr2); -> arr1.concat(arr2[0], arr2[1], ...);
fun.apply(obj, arr); -> obj.fun(arr[0], arr[1], ...);
c3. 让子类型的原型继承父类型的原型:Object.setPrototypeOf(子类型的原型, 父类型的原型);
call和apply:
相同:都是强行调用一个函数,并替换this
差别:传入参数的方式:
call:要求每个参数必须单独传入
apply:要求所有参数以一个数组的方式整体传入
<script type="text/javascript"> function Flyer(fname, speed){ this.fname = fname; this.speed = speed; } Flyer.prototype.fly = function(){ console.log(this.fname + " is flying, on speed " + this.speed); }; function Enemy(fname, speed, score){ Flyer.call(this, fname, speed); this.score = score; } Enemy.prototype.getScore = function(){ console.log(this.fname + " score is " + this.score); }; Object.setPrototypeOf(Enemy.prototype, Flyer.prototype); function Bee(fname, speed, award){ Flyer.apply(this, arguments); this.award = award; } Bee.prototype.getAward = function(){ console.log(this.fname + " award is " + this.award); }; Object.setPrototypeOf(Bee.prototype, Flyer.prototype); var e = new Enemy("enemy001", 50, 20); e.fly(); e.getScore(); var b = new Bee("bee001", 5, 2); b.fly(); b.getAward(); </script>
*****ES5
对象的属性:
对象:属性的集合
2大类:
a. 命名属性:自定义的可用,直接访问的属性
a1. 数据属性:直接保存一个数据的属性
a2. 访问器属性:专门保护另外一个数据属性的特殊属性,不直接保存数据
b.内部属性:对象内部自动包含的,无法用.访问到的属性,比如:class
***数据属性:
ES5中规定,每个数据属性都包含4大特性:
value:时机存储属性值的特性
writable:控制当前属性是否可修改 bool
enumerable:控制当前属性能否被 for in 遍历到 bool
configurable:控制当前属性能否被删除,或能否修改其他特性
如何访问属性的特性:
查看属性的特性: var attrs = Object.getOwnPropertyDescriptor(obj, "属性名");
设置属性的特性: Object.defineProperty(obj, "属性名", {value: 值, writable: true/false, enumerable: true/false, configurable: true/false});
注意:一般修改特性时,都要将configurable设置为false:不准修改其他特性;不可逆。
添加一个新属性,并设置四大属性:
Object.defineProperty(obj, "属性名", {value: 值, writable: true/false, enumerable: true/false, configurable: true/false});
注意:使用defineProperty添加的新属性,四大特性默认值为false!
对象直接量中的属性:四大特性默认值为true
同时定义或添加多个属性,并设置四大特性:
Object.defineProperty(obj, {
"属性名": {value: 值, writable: true/false, enumerable: true/false, configurable: true/false},
...
});
<script type="text/javascript"> var emp = {id:1001, name: "jack", salary: 10000}; console.log(Object.getOwnPropertyDescriptor(emp, "id"));//Object {value: 1001, writable: true, enumerable: true, configurable: true} Object.defineProperty(emp, "id", {writable: false});//修改emp的id属性为只读 emp.id = 1002; Object.defineProperty(emp, "salary", {enumerable: false});//修改emp的salary属性为不可遍历 for(var key in emp){ console.log(key + ":" + emp[key]);//id:1001 name:jack } </script>
静态方法:不需要实例化对象,就直接调用的方法。
方法定义在原型对象中,还是定义在构造函数上:
如果只希望当前类型的子对象才能用,就放在原型对象中;
如果不希望实例化任何对象,就可以直接调用,就放在构造函数上。