[toc]
## previously
JS中的对象和函数汇总
>对象数据类型的值
>- `{}`普通对象
> - `[]` 数组
> - `/^$/` 正则
> - `Math` 数学函数
> - 一般类的实例都是对象数据类型
> - 函数的`prototype`属性
>
> - 实例的`__proto__`属性
> - ...
>
> 函数数据类型值
> - 普通函数
> - 所有的类(内置类和自定义类)
> - ...
```
typeof Object === 'function'
typeof String === 'function'
typeof Fn === 'function'
```
## 原型(xx.prototype)
>1、 所有的函数都天生自带一个属性:prototype(原型),它是一个对象数据类型的值,在这个对象中存储了为其类的实例提供的公共属性和方法。
>
>2、 prototype这个对象,浏览器会默认为其开辟一个堆内存,在这个堆内存中天生自带一个属性:constructor(构造函数),这个属性存储的值就是当前函数本身。
>
>3、 每一个类的实例(每一个对象)都天生自带一个属性:`__proto__`,属性值是当前对象所属类的原型(prototype)。
>
>4、 每一个类的原型的`__proto__`都指向`Object`类的原型
```
function Fn(name,age){
}
```
```
function Fn(name,age){
this.name = name;
this.age = age;
this.say = function(){
console.log(`my name is ${this.name}!i am ${this.age}years old!`)
}
}
Fn.prototype.say = function(){
console.log('hello world!');
}
Fn.prototype.eat = function(){
console.log('i love food!');
}
var f1 = new Fn('ahhh',11);
var f1 = new Fn('ahhh2',70);
```
![](https://box.kancloud.cn/e42c605c3ee662ce123251fc8b9a7d62_1535x581.png)
## 原型链(`__proto__`)
也是一种设计模式,原型链模式
若一个对象下的属性或方法在自己身上找不到,会顺着`__proto__`网上找,`__proto__`指向的是另外一个对象,这个对象中有的方法和属性,都能传递给下层的对象
![](https://box.kancloud.cn/4a53ffe0b3529f4343aca6ed6b989d2a_1771x566.png)
### this问题
> 关于原型链中提供的私有(公有)方法中的THIS指向问题
> 1、 看点前面是谁,THIS就是谁
> f1.say():this->f1
> f1.__proto__.say():this->f1.__proto__
> Fn.prototype.say():this->Fn.prototype
> ...
>2、 把需要执行方法中的THIS进行替换
>3、 替换完成后,如果想要知道结果,值需按照原型链的查找机制去查找即可
### 向原型上批量增加属性和方法
```
function Fn(name,age){
this.name = name;
this.age = age;
}
Fn.prototype.aa = function(){
};
Fn.prototype.bb = function(){
};
...
var f = new Fn('xxx',28);
```
#### 设置别名
```
//设置别名
var pro = Fn.prototype; //=>指向同一个堆内存
```
#### 重新构造原型(内置类不支持,内置类想添加方法和属性只能一个个加)
```
Fn.prototype = {
//=>让原型指向自己开辟的堆内存有一个问题,自己开辟的堆内存中没有constructor这个属性,所以实例在调取constructor的时候找到的是Object,这样不好,此时我们应该重新设置以下constructor,保证机制的完整性
constructor:Fn
,aa:function(){
}
,bb:function(){
}
};
```
#### 基于内置类的原型扩展方法
>1、 我们新增加的方法最好设置一个前缀,防止我们新增加的方法和内置的方法冲突,把内置的方法替换掉
>2、 返回的结果依然是当前类的实例,这样就可以继续调取当且类的其它方法操作了。
```
//其中obj只是一个key的清单
function distinct(ary){
var obj = {};
for(var i=0;i<ary.length;++i){
var item = ary[i];
if(typeof obj[item]!=='undefined'){
ary[i] = ary[ary.length-1];
ary.length--;
i--;
continue;
}
obj[item] = item;
}
}
//内置方法的方法是一个具名函数
Array.prototype.myDistinct = function myDistinct(){
//=>this:ary当期那要处理的数组
var obj = {};
for(var i=0;i<this.length;++i){
var item = this[i];
if(typeof obj[item]!=='undefined'){
this[i] = this[this.length-1];
this.length--;
i--;
continue;
}
obj[item] = item;
}
obj = null;
return this;
}
```
![](https://box.kancloud.cn/5c822c66c8a9dc3981b93b3b780279b1_212x85.png)
## 习题
实现(3).plus(2).minus(1) =>4
>[warning] **注意:** `()`能将一个数值包装成一个真正的数字类型的实例。(可以使用实例中的方法),其次数值类的this就是数字本身。
```
Number.prototype.plus = function plus(){
var value = Number(arguments[0])||0;
return this+arguments[0];
}
Number.prototype.minus = function minus(){
var value = Number(arguments[0])||0;
return this-arguments[0];
}
console.log((3).plus(2).minus(1))
```
## 函数
### previously
Function -> 函数类
类都天生自带一个属性`prototype`
它的原型上有`call`、`apply`、`bind`等方法
它的原型的`__proto__`也指向`Object.prototype`。
所有函数(包括类)都是`Function`的实例
**所有函数都是`Function`这个类的实例,So所有函数都能作为一个实例存在,也就是一个对象。**
![](https://box.kancloud.cn/b6c62e344d388ab313d18894c3f526d3_1683x773.png)
`Object`类的`__proto__`指向`Function`,而`Function`的`prototype`指向的是`Object.prototype`。
并且`Function`的`__proto__`指向自己的prototype
![](https://box.kancloud.cn/d9cb9ac84c9c68097f0999a779aad9bc_313x65.png)
`Function`的原型是**函数数据类型**的值,但相关操作和之前的一模一样。->anonymous/Empty
### 三种角色
>函数本也会有一些自己的属性:
>`legnth`:0 形参的个数
>`name`:“Fn”函数名
>`prototype`: 类的原型,在原型上定义的方法都是当前Fn这个类实例的公有方法
>`__proto__`:把函数当做一个普通的对象,指向Function这个类的原型
>函数在整个JS中是最复杂也是最重要ode只是
>1、 一个函数存在多面性
>->它本身就是一个普通的函数,执行的时候形成私有的作用域(闭包),形参赋值,预解释,代码执行,执行完成后栈内存销毁/不销毁
>->“类”:它有自己的实例,也有一个叫做prototype属性是自己的原型,它的实例都指向自己的原型
>->“普通对象”:和var obj={}中的obj一样,也是一个对象,它作为对象可以有一些自己私有的属性,也可以通过`__proto__`找到Function.prototype
三种角色之间没有必然联系
```
function Fn(){
var num = 500;
this.x = 100;
}
Fn.prototype.geX = function(){
console.log(this.x);
}
Fn.aaa = 1000;
//类
var f= new Fn;
f.num -> undefined
f.aaa -> undefined;
//普通函数
var res = Fn(); //->Fn中的this是window
res = undefined;
//普通对象
Fn.aaa = 1000;
```
### call
```
//改变this关键字
//Function.prototype.call = function(){}
var obj = {name:'ahhh'}
function fn(){
console.log(this);
}
fn();
// obj.fn();
fn.call(obj)
//->首先我们让原型上的call方法执行,在执行call方法的时候,我们让fn方法中的this变为第一个参数的值,即obj;然后再把fn这个函数执行
Function.prototype.myCall = function(context){
//->myCall方法中的this就是当前我要操作和改变其this关键字的那个函数名
//->1、让fn中的this关键字变为context的值
//->让this这个函数中的"this关键字"变为context
var that = eval(this.toString().replace("this",context));
//->2、让fn方法再执行
that();
};
fn.myCall(obj);
```
```
function fn1(){console.log(1)};
function fn2(){console.log(2)};
fn1.call(fn2);
```
```
fn1.call.call(fn2);
```
首先fn1通过原型链找到callFunction.prototype上的call方法,然后再让call方法通过原型再找到Function原型上的call(因为call本身的值也是一个函数,所以同样可以找到Function.prototype),在第二次再找到call的时候让方法执行,方法中的this是fn1.call,首先让这个方法中的this变为fn2,然后再让fn1.call执行
```
var obj = {name:'ahhh'}
function fn(num1,num2){
console.log(num1+num2);
console.log(this);
}
fn.call(100,200);
fn.call(obj,100,200);
fn.call(); //this->window
fn.call(null);//this->window
fn.call(undefined);//this->window
```
严格模式下this指向
```
"use strict";//=>告诉当前浏览器接下来的JS代码将按照严格模式进行编写
fn.call(); //this->undefined
fn.call(null);//this->null
fn.call(undefined);//this->undefined
```
### apply
apply和方法的作用是一模一样的,都是用来改变this关键字并且把方法执行;而且在严格模式下和非严格模式下对于第一个参数是null/undefined这种情况的规律也是一样的
```
fn.call(obj,100,200);
fn.apply(obj,[100,200]);
```
call在给fn传递参数的时候,是一个个传递值的,而apply不是一个个传的,而是把要给fn传递的参数值统一的放在一个数组中进行操作的->但是也相当于一个个的给fn的形参赋值
### bind
这个方法在IE6~8不兼容
此方法和call/apply类似,都是用来改变this关键字的
```
fn.call(obj,1,2); //->改变this和执行fn函数是都一起完成了
//->预处理:事先把fn的this改变为我们想要的结果,并且把对应的参数值也准备好,以后要用到了,直接执行即可
var tempFn = fn.bind(obj,1,2); //->只是改变了fn中的this为obj,并且给fn传递了两个参数1、2,但此时并没有把fn这个函数执行,执行bind会有一个返回值,这个返回值tempFn就是我们把fn的this改变后的那个结果
tempFn();
```
- 空白目录
- window
- location
- history
- DOM
- 什么是DOM
- JS盒子模型
- 13个核心属性
- DOM优化
- 回流与重绘
- 未整理
- 文档碎片
- DOM映射机制
- DOM库封装
- 事件
- 功能组件
- table
- 图片延迟加载
- 跑马灯
- 回到顶部
- 选项卡
- 鼠标跟随
- 放大镜
- 搜索
- 多级菜单
- 拖拽
- 瀑布流
- 数据类型的核心操作原理
- 变量提升
- 闭包(scope)
- this
- 练习题
- 各种数据类型下的常用方法
- JSON
- 数组
- object
- oop
- 单例模式
- 高级单例模式
- JS中常用的内置类
- 基于面向对象创建数据值
- 原型和原型链
- 可枚举和不可枚举
- Object.create
- 继承的六种方式
- ES6下一代js标准
- babel
- 箭头函数
- 对象
- es6勉强笔记
- 流程控制
- switch
- Ajax
- eval和()括号表达式
- 异常信息捕获
- 逻辑与和或以及前后自增
- JS中的异步编程思想
- 上云
- 优化技巧
- 跨域与JSONP
- 其它跨域相关问题
- console
- HTML、XHTML、XML
- jQuery
- zepto
- 方法重写和方法重载
- 移动端
- 响应式布局开发基础
- 项目一:创意简历