函数的三种角色
1.普通函数 形参实参 arguments return 执行过程
1.形成私有作用域->2.形参赋值->3.变量提升->4.对this进行指向->5.代码从上到下执行->6.作用域是否销毁
function fn ( ) { }
2.构造函数(类)
1.形成私有作用域->2.形参赋值->3.变量提升->4.对this进行指向->5.创建空对象->6.让this指向这个空的对象->7.代码从上而下执行->8.把this return 出去->9.作用域是否销毁
2.this指向实例
3.如果return一个基本数据类型值,不会影响默认返回的this,如果return一个引用数据类型值,把默认返回的对象覆盖
function Fn ( ) { this . x = x }
var f = new Fn
3.对象
function Fn ( ) {
}
fn ( )
fn. num = 1
var f = new Fn
console. log ( f. num) ;
console. log ( fn) ;
可枚举属性
可枚举属性:1.对象的私有属性 2.给类上面新增扩展的属性
不可枚举属性:对象或原型中天生自带的属性属于不可枚举属性
var obj = { x: 1 , y: 2 , z: 3 }
for ( var key in obj) {
console. log ( key) ;
}
function Fn ( ) {
this . a = 100 ;
this . b= 200
}
Fn. prototype. getX = function ( ) {
}
var f = new Fn
四种继承
原型继承
类b继承了类A的私有属性以及公有属性,这种继承方式为原型继承
function A ( ) {
this . getY = function ( ) {
console. log ( 200 ) ;
}
}
A . prototype. getX = function ( ) {
console. log ( 100 ) ;
}
function B ( ) {
}
B . prototype = new A
var b = new B
b. getY ( )
b. getX ( )
中间类继承
function sum ( ) {
arguments. __proto__ = Array. prototype;
arguments. pop ( )
console. log ( arguments) ;
}
sum ( 100 , 2 , 3 , 56 , 78 , 45 , 36 )
call继承
在类B中,调用了类A,并且通过call改变了类A中this指向,使其指向B的实例,这样类B创建的实例就有了类A的私有属性,这种继承就是call继承
function A ( ) {
this . a = 100
}
function B ( ) {
A . call ( this )
}
var b = new B
console. log ( b) ;
寄生组合继承
解决了继承公有和私有属性
var obj = { age: 1 , hh: '欢迎' }
var o = Object. create ( obj)
console. log ( o) ;
function A ( ) {
}
A . prototype. getX = function ( ) {
}
function B ( ) {
A . call ( this )
}
B . prototype = Object. create ( A . prototype)
var b = new B
call apply bind
call
call
在Function的原型上,Function.prototype
所有函数都可以获取到call
Function.prototype.call
call 可以改变函数this指向 call是一个函数
call的参数
1.如果call不传参,那么函数中this指向window
2.如果有一个参数,那么就是指向第一个实参 在非严格模式下,传null和undefined都指向window
3.如果严格模式下,如果没传或传入undefined,this就是undefined,如果传null,this指向null 'use strict' 严格模式
4.从第二个参数开始,都会一一传给fn
call的this call点前面的fn
fn通过__proto__先找到Function原型中的call方法,让call方法执行,call运行时,改变 call中this 的this 指向,fn中的this 指向call的第一个参数,并且让 call中this 执行
function fn1 ( ) {
console. log ( 100 ) ;
console. log ( this ) ;
}
function fn2 ( ) {
console. log ( 200 ) ;
}
fn1. call. call. call. call ( fn2) ;
1. fn1. call. call. call -- > this -- > fn2;
2. fn1. call. call. call ( )
1. fn2-- > this 没有变
2. fn2 ( ) ;
1. 先执行后面的call方法 ( 这个call方法中的this 是fn1. call) ; 是改变fn1. call中的this 指向fn2; 并且让fn1. call运行;
2. 当fn1. call运行时,改变fn. call中的this 的this 指向没有发生改变,继续让fn1. call中this 执行,也就是让fn2运行;
apply
1.改变this指向,传参不同,第二个参数必须是一个数组
2.传入数组,但fn实际接收的仍然是一个一个接收
3.不想改this,可以占位 传 this null 都指向window
function fn ( a, b) {
console. log ( a, b) ;
console. log ( this ) ;
}
fn. apply ( null , [ 100 , 220 ] )
bind
bind 预处理this
1.在bind函数中,将fn进行包装和处理,改变了fn里面的this指向,并且返回一个改变this之后的新函数
2.bind 在IE8以下不兼容
function xn ( a, b) {
console. log ( a, b) ;
console. log ( this ) ;
}
var f = xn. bind ( [ 1 , 2 ] , 300 , 400 )
f ( 100 , 200 )
类数组转数组
类数组 arguments 没有prototype的属性 元素集合
arguments 直接指向Object的原型 调用不了Array上的方法
function sum ( ) {
var ary = [ ] ;
for ( var i = 0 ; i < arguments. length; i++ ) {
ary. push ( arguments[ i] )
}
console. log ( ary) ;
}
function sum ( ) {
Array. prototype. newSlice = function ( ) {
let aox = [ ] ;
for ( var i = 0 ; i < this . length; i++ ) {
aox[ aox. length] = this [ i]
}
return aox
}
var ary = Array. prototype. newSlice. call ( arguments)
return ary
}
console. log ( sum ( 1 , 2 , 3 , 44 , 5 , 66 , 88 , 45 , 66 ) ) ;
var div1 = document. getElementsByTagName ( 'div' )
function toArray ( likeAry) {
var ary = [ ] ;
try {
ary = Array. prototype. newSlice. call ( likeAry)
} catch ( e) {
console. log ( e) ;
for ( var i = 0 ; i < likeAry. length; i++ ) {
ary. push ( likeAry[ i] )
}
}
return ary
} ( div1)
var newAry = toArray ( div1)
console. log ( newAry) ;