前言 每天努力一点点💪,就能升职加薪💰当上总经理出任CEO迎娶白富美走上人生巅峰🗻,想想还有点小激动呢😎。
学习css布局🤣 display属性,它是css中最重要的用于控制布局的属性,每个元素都有一个默认的display值,这与元素的类型有关,大多数元素的默认值一般是block或inline。
block元素叫做块级元素;inline元素叫做行内元素
常用的display值,有时候为none,它是用来再不删除元素的情况下隐藏或显示,display:none。
display设置成none元素不会占据它本来应该显示的空间;使用visibility:hidden会占据空间,只是隐藏了,元素还在。
position属性:static是默认值,口诀,子绝父相。fixed,一个固定定位元素会相对于视窗来定位,即使页面滚动,它也会停留再相同的位置上。
css属性中的float,float可实现文字环绕图片效果:
1 2 3 4 img { float : right; margin : 0 0 1em 1em ; }
clear属性可以用于被控制的浮动元素,如果一个盒子添加了float: left浮动,可以使用clear: left清楚元素的向左浮动。
清楚浮动,clearfix hack,可以使用新的css样式:
1 2 3 .clearfix { overflow : auto; }
百分比宽度,百分比是一种相对于包含块的计量单位。
1 2 3 4 5 6 7 8 9 10 11 12 13 .clearfix { float : right; width : 50% ; } nav { float : left; width : 15% ; } section { margin-left : 15% ; }
响应式设计 是一种让网站针对不同的浏览器和设备“呈现”不同显示效果的策略,可以让网站在不同情况下呈现很好的效果。
inline-block为行内块标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 .box { float : left; width : 200px ; height : 100px ; margin : 1em ; } .after-box { clear : left; } // 相同效果 .box1 { display : inline-block; width : 200px ; height : 100px ; margin : 1em ; }
flexbox是css3种的一种新的布局模式,用于满足现代web的复杂需求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <div class ="flex-container" > <div class ="flex-item" > flex item 1</div > <div class ="flex-item" > flex item 2</div > </div > .flex-container { display: -webkit-flex; display: flex; width: 300px; height: 240px; background-color: Silver; } .flex-item { background-color: DeepSkyBlue; width: 100px; height: 100px; margin: 5px; }
JavaScript变量😊 1,Int整型 2,Float浮点 3,Boolean布尔 4,String字符串 5,Array数组 6,Object对象 7,Function函数 8,Regular Expression正则
驼峰命名法😀
全部小写,单词与单词间用下划线分割
大小写混合,大驼峰,每个单词首字母大写,小驼峰,第一个单词首字母小写,其他首字母大写。
规则😁
首字符,英文字母或者下划线;组成,英文字母,数字,下划线;(禁用,JavaScript关键词与保留字)
声明😃
显示声明,使用var变量名,({没有类型,重复声明,隐式声明,不声明直接复制}),({先声明,后读写,先赋值,后运算})。
变量类型😃
值类型,占用空间固定,保存在栈中,保存与复制的是值本身,使用typeof检测数据的类型,基本类型数据是值类型。
引用类型,占用空间 不固定,保存在堆中,保存与复制的是指向对象的一个指针,使用instanceof检测数据的类型,使用new()方法构造出的对象是引用型。
作用域😄
全局变量,包括,在函数体外定义的变量,在函数体内部定义的无var的变量;调用,在任何位置。
局部变量,包括,在函数内部使用var声明的变量,函数的参数变量;调用,当前函数体内部。
优先级,局部变量高于同名全局变量,参数变量高于同名全局变量,局部变量高于同名参数变量。
特性:忽略块级作用域,全局变量是全局对象的属性,局部变量是调用对象的属性。
作用域链,内层函数可访问外层函数局部变量,外层函数不能访问内层函数局部变量。
声明周期:全局变量,除了被删除,否则一直在,局部变量,声明起到函数运行完毕或显示删除。回收机制,标记清楚,引用计数。
逻辑运算符😅
!逻辑非
返回true
1 2 3 4 5 空字符串 0 null NaN undefined
返回false
注意:逻辑非,连续使用两次,可以将任意类型转为布尔型值
&&逻辑与😆
当第一个操作数是对象,返回第二个操作数
当第二个操作数是对象,第一个操作数值为true时返回该对象
两个操作数都是对象,返回第二个操作数
一个操作数为null时,返回null
一个操作数为NaN时,返回NaN
一个操作数为undefined,返回undefined
注意:当第一个操作数的值时false,则不对第二个操作数进行求值。
逻辑或 ||😉
第一个操作数是对象,返回第一个操作数
第一个操作数值为false,返回第二个操作数
两个操作数都是对象,返回第一个操作数
两个操作数都是null,返回null
两个操作数都是NaN,返回NaN
两个操作数都是undefined,返回undefined
注意:如果第一个操作数值为true,就不会对第二个操作数求值。
JavaScript数组
添加
push()在数组末尾添加数组 unshift()在数组头部添加元素 concat()合并两个数组
删除
pop()删除并返回数值的最后一个元素 shift()删除并返回数组的第一个元素
队列方法(先进先出);栈方法(后进先出)。
splice()和slice()
splice()
删除任意数量的项:1,要删除的起始下标,2,要删除的项数
在指定位置插入指定的项:1,起始下标,2,0(不删除任何项),3,要插入的项。
替换任意数量的项:1,起始下标,2,要删除的项数,3,要插入的项
splice()方法,注解,该方法会改变原始数组 。用于添加或删除数组中的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 arrayObject.splice (index,howmany,item1,.....,itemX) var arr = ['a' , 'b' , 'c' ]arr.splice (2 ,1 ) ['c' ] arr.splice (2 ,0 ) [] var array = [1 ,2 ,3 ,4 ,5 ];array.splice (3 ,2 ); console .log (array);var myFish = ['angel' , 'clown' , 'mandarin' , 'sturgeon' ];var removed = myFish.splice (2 );
所有主要浏览器都支持splice()
Array数组的splice()方法,它的作用删除,插入,替换
插入的用法
1 2 3 4 5 6 7 8 语法:array.splice (starti,0 ,值1 ,值2. ..); var array = [1 ,2 ,3 ,4 ,5 ];array.splice (2 ,0 ,11 ,22 );
替换的用法
1 2 3 4 5 6 语法:array.splice (starti,n,值1 ,值2 ); var array = [1 ,2 ,3 ,4 ,5 ];array.splice (2 ,2 ,11 ,22 );
slice()功能,从已有数组中选取部分元素构成新数组
返回项的起始位置
返回项的结束位置
特性,如果是负数,则用数组长度加上该值确定位置,启示位置实为数组的实际下标,结束位置的实际下标为结束数值减1。
Array.prototype.slice()
slice()方法返回一个新的数组对象。原始数组不会被改变。 这一对象是一个由begin和end决定的原数组的浅拷贝。
表扬一下:
1 2 3 4 5 6 7 8 9 10 const animals = ['1', '2', '3', '4', '5']; console.log(animals.slice(2)); // expected output: Array ["3", "4", "5"] console.log(animals.slice(2, 4)); // expected output: Array ["3", "4"] console.log(animals.slice(1, 5)); // expected output: Array ["2", "3", "4", "5"]
slice(start,end),从start开始截取到end单不包含end,返回值为截取出来的元素的集合(只是返回一个浅复制了原数组中的元素的要给新数组)
1 2 3 4 5 var fruits = ['a' , 'b' , 'c' , 'd' , 'e' ];var citrus = fruits.slice (1 , 3 );
slice方法用一个类数组对象/集合转换成一个新数组。
1 2 3 4 5 function list ( ) { return Array .prototype .slice .call (arguments ); } var list1 = list (1 , 2 , 3 );
在JavaScript中,几乎所有东西都是一个对象,除了string,number 和 booleans这样不可变的原始值。
Array.prototype.slice
1 2 3 4 5 6 7 8 9 10 function myFunc ( ) { arguments .sort (); var args = Array .prototype .slice .call (arguments ); args.sort (); }
数组排序,reverse()颠倒数组中元素的顺序,sort()对字符数组或数字数组进行排序。
1 2 3 4 5 6 7 8 9 function compare (value1, value2 ) { if (value1 < value2) { return -1 ; }else if (value1 > value2) { return 1 ; }else { return 0 ; } }
数组转换
toString()转换为字符串并返回
toLocaleString()转换为本地格式字符串并返回
join()用指定分割符分割数组并转换为字符串
toString()函数用于将当前对象已字符串的形式返回。该方法属于Object对象。
迭代方法:参数
every 如果该函数对每一项都返回true,则返回true
filter 返回值为true的所有数组成员
forEach 无返回值
map 返回每次函数调用的结果数组
some 有任意一项返回true,则返回true
接收参数:
要在每一项上运行的函数
运行该函数的作用域对象
传入参数:
数组项的值item
该项在数组中的位置index
数组对象本身array
缩小方法:
reduce 从数组起始位开始遍历
reduceRight 从数组末尾开始遍历
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
reduce() 可以作为一个高阶函数,用于函数的 compose。
注意: reduce() 对于空数组是不会执行回调函数的 。
1 2 var numbers = [1 , 2 , 3 , 4 ];numbers.reduce (回调函数);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const array1 = [1 , 2 , 3 , 4 ];const reducer = (accumulator, currentValue ) => accumulator + currentValue;console .log (array1.reduce (reducer));console .log (array1.reduce (reducer, 5 ));var arr = [1 ,2 ,3 ,4 ];var sum = arr.reduce ((x,y )=> x+y)var sum1 = arr.reduce ((x,y )=> x*y)
求数组项的最大值
1 2 3 var max = arr.reduce (function (prev, cur ) { return Math .max (prev,cur); });
取两值最大值后继续进入下一轮回调。
数组去重
1 2 3 4 5 6 7 8 9 10 11 12 arr.reduce (function (prev,cur,index,arr ){ ... }, init); arr 表示原数组; prev 表示上一次调用回调时的返回值,或者初始值 init; cur 表示当前正在处理的数组元素; index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0 ,否则索引为1 ; init 表示初始值。 arr.reduce (callback,[initialValue]) initialValue (作为第一次调用 callback 的第一个参数。)
如果这个数组为空,运用reduce是什么情况?
1 2 3 4 5 6 7 8 9 10 11 12 13 var arr = [];var sum = arr.reduce (function (prev, cur, index, arr ) { console .log (prev, cur, index); return prev + cur; }) var arr = [];var sum = arr.reduce (function (prev, cur, index, arr ) { console .log (prev, cur, index); return prev + cur; },0 ) console .log (arr, sum);
js 中in,一般用来遍历对象, 也可以用来遍历数组
in作用,判断属性是否存在于对象中,在true,不在false。
in作用,判断数组,索引号就是属性。
对于数组循环出来的是数组元素;对于对象循环出来的是对象属性;当‘对象’是数组时:“变量”指的是数组的“索引”;当‘对象’为对象是,“变量”指的是对象的“属性”。
计算数组中每个元素出现的次数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // 求总成绩 var scoreReport = [ { name: 'dada', score: 100 }, { name: '魔王哪吒', score: 99 } ] // for var sum = 0 for(var i = 0; i<scoreReport.length; i++) { sum += scoreReport[i].score }
如果使用reduce
1 2 3 var sum = scoreReport.reduce(function(prev, cur) { return cur.score + prev },0);
Vuex Vuex中规则只能在mutations里修改state中的数据,actions不能直接修改state
创建Vuex.Store实例保存到变量store中,使用export default导出store
1 2 3 4 5 6 7 import Vuex from 'vue' import Vuex from 'vuex' Vue .use (Vuex )const store = new Vuex .Store ({ }) export default store
state
常常写的文件store.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import Vue from 'vue' import Vuex from 'vuex' // import * as getters from './getters' Vue.use(Vuex) const state = { // 放置初始状态 a: 123 }; const mutations = { // 放置我们的状态变更函数 }; export default new Vuex.Store({ state, mutations, // getters })
this.$store.state
来获取定义的数据
1 2 3 4 5 6 7 8 9 import Vuex from 'vue' import Vuex from 'vuex' Vue .use (Vuex )const store = new Vuex .Store ({ state : { count : 1 } }) export default store
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import Vuex from 'vue' import Vuex from 'vuex' Vue .use (Vuex )const store = new Vuex .Store ({ state : { count : 1 }, getters : { getStateCount : function (state ){ return state.count +1 ; } } }) export default store
要修改state中的值,需要提交mutation来修改
Vuex中的getter,就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,并且只有当它的依赖值发生了改变才会被重新计算。
Getter 接受 state 作为其第一个参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 const store = new Vuex .Store ({ state : { todos : [ { id : 1 , text : '...' , done : true }, { id : 2 , text : '...' , done : false } ] }, getters : { doneTodos : state => { return state.todos .filter (todo => todo.done ) } } })
getter 在通过属性访问时,是作为 Vue 的响应式系统的一部分缓存其中的 getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 某函数中{ this .$store .commit ('add' ); } import Vuex from 'vue' import Vuex from 'vuex' Vue .use (Vuex )const store = new Vuex .Store ({ state : { count : 1 }, getters : { getStateCount : function (state ){ return state.count +1 ; } }, mutations : { add (state ) { state.count += 1 ; }, } }) export default store{{$store.getters .getStateCount }}
提交 mutation-对象风格的提交方式,直接使用包含 type 属性的对象:
1 2 3 4 store.commit ({ type : 'increment' , amount : 10 })
Vuex中还有一个Actions,这个目的是不想上面那样直接修改store里面的值,而是通过去提交一个actions,然后再在actions中提交mutations中去修改状态值。
先定义actions提交mutations的函数
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 某函数中{ this .$store .dispatch ('addFun' ) } import Vuex from 'vue' import Vuex from 'vuex' Vue .use (Vuex )const store = new Vuex .Store ({ state : { count : 1 }, getters : { getStateCount : function (state ){ return state.count +1 ; } }, mutations : { add (state ) { state.count += 1 ; }, }, actions : { addFun (context ){ context.commit ('add' ) }, } }) export default store
使用mapState,mapGetters,mapActions,代替this.$store.state.count和this.$store.dispatch('addFun')
这种写法。
如何使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import {mapState, mapGetters, mapActions} from 'vuex' ;computed : { ...mapState ({ countdada : state => state.count }) } import { mapGetters } from 'vuex' export default { computed : { ...mapGetters ([ 'doneTodosCount' , 'anotherGetter' , ]) } } ...mapGetters ({ doneCount : 'doneTodosCount' })
JavaScript中的this this,是什么,这个,this关键字执行为当前执行环境的ThisBinding。
大多数情况下,函数的调用方式决定了this的值。this指向是调用时决定,而不是创建时决定的。
1 2 3 4 5 6 function dadaqianduan ( ) { return this ; } console .log (dadaqianduan () === window );
使用call(),apply(),this指向为绑定的对象上。
1 2 3 4 5 6 7 8 9 10 var person = { name : 'dada' , age : 12 }; function sayHello (job ) { console .log (this .name + "," + this .age + "," + job); } sayHello.call (person, 'it' ); sayHello.apply (person, ['it' ]);
箭头函数,所有的箭头函数都没有自己的this,并指向外层。箭头函数会捕获其所在上下文的this值,作为自己的this值。(函数内部,this的值取决于函数被调用的方式)
箭头函数的this,总是指向定义时所在的对象。不是运行时所在的对象。
1 2 3 4 5 6 7 function da ( ) { setTimeout (()=> { console .log ('this' ,this .id ) },1000 ); } da.call ({id : 12 });
箭头函数位于da函数内部,只有da函数运行后,才会按照定义生成,so,da运行时所在的对象,刚好是箭头函数定义时所在的对象。
(值得探讨的一句话),在箭头函数里使用this,就像使用普通变量一样,在箭头函数的scope内找不都会一直向父scope寻找。
this又指向全局变量,如下:
感谢掘金网友:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var name = 'da' ;var person = { name : 'dadaqianduan' , fun : function ( ) { return this .name ; } } var getName = person.getName ();console .log (getName ()); var name = 'da' ;var person = { name : 'dadaqianduan' , getName : function ( ) { return this .name ; } } var fun = person.getName ;console .log (fun ());
作为一个构造函数,this被绑定到正在构造的新对象。
1 2 3 4 5 6 7 8 9 10 function Person(name) { this.name = name; this.age = 12; this.say = function() { console.log(this.name + ":" + this.age); } } var pserson = new Person('dadaqianduan'); person.say();
this的几种调用场景:
1 2 3 4 5 6 var obj = { a : 1 , b : function ( ) { console .log (this ); } }
当作为对象调用时,指向该对象obj.b(); // 指向obj
当作为函数调用时,var b = obj.b; b(); // 指向全局window
当作为构造函数调用时,var b = new Fun(); // this.指向当前实例对象
当作为call与apply调用 obj.b.apply(object, []); // this指向当前的object
示例:
1 2 3 4 5 6 7 8 9 10 11 var a = dadaqianduan;var obj = { a : dada } function fun ( ) { console .log (this .a ); } fun (); fun.call (obj);
1 2 3 4 5 6 7 function da (a,b,c ) { console .log (arguments ); var arg = [].slice .call (arguments ); } da (1 ,2 ,3 )
全局上下文,非严格模式和严格模式中this指向顶层对象。
函数上下文
1 2 3 4 5 var name = 'dadaqianduan' ;var fun = function ( ) { console .log (this .name ); } fun ();
call()方法使用一个指定的this值和单独给出的一个或多个参数来调用一个函数。
该方法的语法和作用与apply()方法类似,只有一个区别,就是call()方法接受的是一个参数列表,apply()方法接受的是一个包含多个参数的数组。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 function da (name, age ) { this .name = name; this .age = age; } function dada (name, age ) { da.call (this , name, age); this .job = 'it' ; } console .log (new dada ('dadaqianduan, 12' ).name );
语法:
1 function .call (thisArg, arg1, arg2, ...)
参数:thisArg
,在function函数运行时使用的this值,this可能不是该方法看到的实际值。arg1,arg2,...
指定的参数列表。
返回值,使用调用者提供的this值和参数调用该函数的返回值。若该方法没有返回值,则返回undefined。
描述:
call()
允许为不同的对象分配和调用属于一个对象的函数/方法。提供新的this值给当前调用的函数/方法。你可以使用call来实现继承。
使用call方法调用父构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function Person (name, age ) { this .name = name; this .age = age; } function Child1 (name, age ) { Person .call (this , name, age); this .eat = 'beff' ; } function Child2 (name, age ) { Person .call (this , name, age); this .eat = 'food' ; } var da1 = new Child1 ('魔王哪吒1' , 12 );var da2 = new Child2 ('魔王哪吒2' , 12 );
使用call方法调用匿名函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var person = [ { name : 'da1' , age : 1 }, { name : 'da2' , age : 2 } ]; for (var i=0 ; i<person.length ; i++) { (function (i ){ this .fun = function ( ) { console .log ('dadaqianduan' ); } this .fun (); }).call (person[i], i); }
1 2 3 4 5 6 7 8 9 10 class Person { constructor (name ) { this .name = name; } fun ( ){ console .log (this .name ); } } let da = new Person ('达达前端' );da.fun ();
对于箭头函数调用,没有自己的this,super,arguments,new.target绑定,不能使用new来调用,没有原型对象,不可以改变this的绑定,形参名称不能重复。
this的绑定对象,通过new调用绑定到新创建的对象,return函数或对象,返回值不是新创建的对象,而是显式的返回函数或对象;call或apply的调用,非严格模式,为null和undefined;对象上的函数调用,绑定到这个对象;普通函数的调用,严格模式,为undefined。
注意:(一起来探讨) 也可以这样记住:对象中有this,对象中的方法(函数),以及普通函数来记住。
绑定例子,this在非严格模式下this指向全局对象,严格模式下this绑定到undefined,隐式绑定,obj.foo()的调用方式,foo内的this指向了obj。
显示绑定,call()或apply()方法直接指定this的绑定对象,箭头函数中this指向由外层作用域决定的。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 var a = "dadaqianduan" ;function foo () { console .log (this .a ) } foo ();window .a = "dadaqianduan" ;function foo ( ) { console .log (this .a ) } window .foo ();
严格模式,只是使得函数内的this指向undefined,而不会改变全局中的this指向。只有var会把变量绑定到window上,而let和const不会。
1 2 3 4 5 6 7 8 9 10 11 12 13 let a = "dada" const b = "dada1" function foo () { console .log (this .a ) console .log (this .b ) } foo ();console .log (window .a )
1 2 3 4 5 6 7 var a = "da" ;function fun ( ) { var a = "da1" ; console .log (this ); console .log (this .a ); } fun ();
1 2 3 4 5 6 7 8 9 10 var a = "da" ;function fun ( ) { var a = "da1" ; function inner ( ) { console .log (this .a ); } inner (); } fun ();
谁最后调用函数,函数内的this指向最近原则
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function fun ( ) { console .log (this .a ) } var obj = { a : 'da' , fun } var a = 'da1' ;obj.fun (); obj对象引用fun () 赋值 obj.fun 上,调用的是obj对象,打印的就是obj中的a var obj = { a : 'da' , fun : function ( ) { console .log (this .a ) } } var a = 'da1' obj.fun ()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function fun ( ) { console .log (this .a ); }; var obj = { a : 'da' , fun }; var a = 'da1' ;var fun1 = obj.fun ;obj.fun (); fun1 ();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function fun ( ) { console .log (this .a ); }; var obj = { a : 'da' , fun }; var a = 'da1' ;var fun1 = obj.fun ;var ojb1 = { a : 'da2' , fun2 : obj.fun }; obj.fun (); fun1 (); obj1.fun2 ();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function fun ( ) { console .log (this .a ); }; function doFun (fn ) { console .log (this ); fn (); }; var obj = { a : 'da' , fun }; var a = 'da1' ;doFun (obj.fun );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function fun ( ) { console .log (this .a ); }; function doFun (fn ) { console .log (this ); fn (); }; var obj = { a : 'da' , fun } var a = 'da1' ;var obj1 = { a : 'da2' , doFun }; obj1.doFun (obj.fun ) 原因:把一个函数当做参数传递给另一个函数,会发生隐式丢失,就是回调函数丢失this 绑定。
call,apply,bind 使用call和apply的函数会直接执行,bind是创建一个新的函数,需要手动调用才行。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function fun ( ) { console .log (this .a ); }; var obj = { a : 'da' }; var a = 'da1' ;fun (); fun.call (obj); fun.apply (obj); fun.bind (obj);
示例:
1 2 3 4 5 6 7 8 9 10 11 如果call,apply,bind接收 参数 为空或者null ,undefined ,会忽略这个参数 function fun ( ) { console .log (this .a ); }; var a = 'da' ;fun.call (); fun.call (null ); fun.call (undefined );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var ojb1 = { a : 'da' }; var obj2 = { a : 'da1' , fun1 : function ( ) { console .log (this .a ); }, fun2 : function ( ) { setTimeout (function ( ){ console .log (this ); console .log (this .a ); },0 ) } } var a = 'da2' ;obj2.fun1 (); obj2.fun2 ();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var obj1 = { a : 'da' }; var obj2 = { a : 'da1' , fun1 : function ( ) { console .log (this .a ); }, fun2 : function ( ) { setTimeout (function ( ) { console .log (this ); console .log (this .a ); }.call (obj1), 0 ) } } var a = 'da2' ;obj2.fun1 (); obj2.fun2 ();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var obj1 = { a : 'da' }; var obj2 = { a : 'da1' , fun1 : function ( ) { console .log (this .a ); }, fun2 : function ( ) { function inner ( ) { console .log (this ); console .log (this .a ); } inner (); } } var a = 'da2' ;obj2.fun1 (); obj2.fun2 ();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function fun ( ) { console .log (this .a ); }; var obj = { a : 'da' }; var a = 'da1' ;fun (); fun.call (obj); fun ().call (obj);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function fun ( ) { console .log (this .a ); return function ( ) { console .log (this .a ); } }; var obj = { a : 'da' }; var a = 'da1' ;fun (); fun.call (obj); fun ().call (obj);
bind绑定,只是返回一个新的函数
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function fun ( ) { console .log (this .a ); return function ( ) { console .log (this .a ); } } var obj = { a : 'da' }; var a = 'da1' ;fun (); fun.bind (obj); fun ().bind (obj);
1 2 3 4 5 6 7 8 9 10 11 12 13 function fun ( ) { console .log (this .a ); return function ( ) { console .log (this .a ); } } var obj = { a : 'da' }; var a = 'da1' ;fun.call (obj)();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var obj = { a : 'da' , fun : function ( ) { console .log (this .a ); return function ( ) { console .log (this .a ) } } }; var a = 'da1' ;var obj1 = { a : 'da2' }; obj.fun ()(); obj.fun .call (obj1)(); obj.fun ().call (obj1);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var da1 = { name : '魔王哪吒' , sayHello : function (age ) { console .log (this .name + age); } }; var da2 = { name : '达达前端' , }; da1.sayHello (12 ); da1.sayHello .apply (da2, [12 ]); da1.sayHello .call (da2, 12 );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 模拟 Function .prototype .applyFun = function (context ) { context.fn = this ; context.fn (); delete context.fn ; } Function .prototype .applyFun = function (context ) { context.fn = this ; var args = arguments [1 ]; context.fn (args.join (',' )); delete context.fn ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var a = 'da' ;function sayHello ( ) { console .log (this .name ); } sayHello.apply (null ); var a = 'da' ;function sayHello ( ) { console .log (this .name ); } sayHello.apply ();
重写属性,ES5:
1 2 3 4 5 var a = { name : 'da' }; a.name = 'da1'
es6引入一种原始数据类型Symbol,表示独一无二的值,Symbol函数可以接收一个字符串作为参数。Symbol函数不能使用new命令,生成Symbol是一个原始类型的值,不是对象。
示例:
1 2 3 4 5 6 7 8 9 var s1 = Symbol ();var s2 = Symbol ();s1 === s2 var s1 = Symbol ("foo" );var s2 = Symbol ("foo" );s1 === s2
Symbol值作为对象属性名时,不用点运算符。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var mySymbol = Symbol ();var a = {};a[mySymbol] = '魔王哪吒' ; var a = { [mySymbol]: '魔王哪吒' }; var a = {};Object .defineProperty (a, mySymbol, { value : '魔王哪吒' });a[mySymbol]
1 2 3 4 5 var a = {};var name = Symbol ();a.name = 'da1' ; a[name] = 'da2' ; console .log (a.name ,a[name]);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var obj = { a : 'da' , fun : function (b ) { b = b || this .a return function (c ) { console .log (this .a + b + c) } } } var a = 'da1' ;var obj1 = { a : 'da2' } obj.fun (a).call (obj1, 1 ) obj.fun .call (obj1)(1 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function fun1 () { console .log (this .a ); }; var a = 'da' ;var obj = { a : 'da1' } var fun2 = function ( ) { fun1.call (obj); }; fun2 (); fun2.call (window );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function fun1 (b ) { console .log (`${this .a} + ${b} ` ) return this .a + b } var a = 1 var obj = { a : 3 } var fun2 = function ( ) { return fun1.call (obj, ...arguments ) } var dada = fun2 (5 )console .log (dada)'3 + 5' 8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function fun (item ) { console .log (item, this .a ); }; var obj = { a : '魔王哪吒' }; var a = 'dada' var arr = [1 ,2 ,3 ];arr.filter (function (i ){ console .log (i, this .a ); return i>2 },obj) 1 '魔王哪吒' 2 '魔王哪吒' 3 '魔王哪吒'
1 2 3 4 5 6 7 8 9 10 function da (name) { this .name = name }; var name = 'da1' ;var dada = new da ('da2' );console .log (dada.name )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var name = '魔王哪吒' ;function fun (name) { this .name = name; this .daFun = function ( ) { console .log (this .name ); return function ( ) { console .log (this .name ); } } } var da1 = new fun ('魔王哪吒1' );var da2 = new fun ('魔王哪吒2' );da1.daFun .call (da2)() da1.daFun ().call (da2)
改变思路,改变想法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 var name = '魔王哪吒' ;var da1 = { name : '魔王哪吒1' , daFun : function ( ) { console .log (this .name ); return function ( ) { console .log (this .name ); } } } var da2 = { name : '魔王哪吒2' , daFun : function ( ) { console .log (this .name ); return function ( ) { console .log (this .name ); } } } da1.daFun .call (da2)() da1.daFun ().call (da2)
箭头函数
箭头函数里的this,由外层作用域决定,指向函数定义时的this,非执行时。(探讨)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var obj = { name : '魔王哪吒' , fun1 : () => { console .log (this .name ) }, fun2 : function ( ) { console .log (this .name ) return () => { console .log (this .name ); } } } var name = '达达前端' ;obj.fun1 (); obj.fun2 ()();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var name = '达达前端' ;var obj1 = { name : '魔王哪吒1' , fun : function ( ) { console .log (this .name ) } } var obj2 = { name : '魔王哪吒2' , fun : () => { console .log (this .name ) } } obj1.fun () obj2.fun ()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 var name = '达达前端' ;var obj1 = { name : '魔王哪吒1' , fun : function ( ) { console .log (this .name ); return function ( ) { console .log (this .name ); } } } obj1.fun ()(); var obj2 = { name : '魔王哪吒2' , fun : function ( ) { console .log (this .name ); return () => { console .log (this .name ); } } } obj2.fun ()(); var obj3 = { name : '魔王哪吒3' , fun : () => { console .log (this .name ); return function ( ) { console .log (this .name ) } } } obj3.fun ()(); var obj4 = { name : '魔王哪吒4' , fun : () => { console .log (this .name ); return () => { console .log (this .name ); } } } obj4.fun ()();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var name = '达达前端' ;function dada (name) { this .name = name; this .fun1 = function ( ) { console .log (this .name ); } this .fun2 = () => { console .log (this .name ); } } var da2 = { name : 'da2' , fun2 : () => { console .log (this .name ); } } var da1 = new dada ('魔王哪吒' );da1.fun1 (); da1.fun2 (); da2.fun2 ();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 var name = '达达前端' ,function dada (name ) { this .name = name; this .fun1 = function ( ) { console .log (this .name ); return function ( ) { console .log (this .name ); } } this .fun2 = function ( ) { console .log (this .name ); return () => { console .log (this .name ); } } this .fun3 = () => { console .log (this .name ); return function ( ) { console .log (this .name ) } } this .fun4 = () => { console .log (this .name ); return () => { console .log (this .name ); } } } var da1 = new dada ('达达' );da1.fun1 ()(); da1.fun2 ()(); da1.fun3 ()(); da1.fun4 ()();
箭头函数中的this,无法用bind,call,apply函数来直接修改,可以通过改变作用域中this的指向来修改。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 var name = '达达前端' ;var obj1 = { name : '达达1' , fun1 : function ( ) { console .log (this .name ); return () => { console .log (this .name ); } }, fun2 : () => { console .log (this .name ); return function ( ) { console .log (this .name ); } } } var obj2 = { name : '达达2' }; obj1.fun1 .call (obj2)() obj1.fun1 ().call (obj2) obj1.fun2 .call (obj2)() obj1.fun2 ().call (obj2)
注意:字面量创建的对象,作用域是window,如果是箭头函数,this指向window
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 var name = '达达前端' ;var da1 = { name : 'dada1' , fun1 : function ( ) { console .log (this .name ); }, fun2 : () => console .log (this .name ); fun3 : function ( ) { return function ( ) { console .log (this .name ); } }, fun4 : function ( ) { return () => { console .log (this .name ); } } } var da2 = { name : 'dada2' }; da1.fun1 (); da1.fun1 .call (da2); da1.fun2 (); da1.fun2 .call (da2); da1.fun3 ()(); da1.fun3 .call (da2); da1.fun3 ().call (da2); da1.fun3 () () { console .log (this .name ) } function ( ) { return function ( ) { console .log (this .name ); } }, da1.fun4 ()(); da1.fun4 .call (da2)(); da1.fun4 ().call (da2);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 var name = '达达前端' ;function dada (name ) { this .name = name; this .fun1 = function ( ) { console .log (this .name ); }, this .fun2 = () => console .log (this .name ), this .fun3 = function ( ) { return function ( ) { console .log (this .name ) } }, this .fun4 = function ( ) { return () => { console .log (this .name ) } } } var da1 = new dada ('1' );var da2 = new dada ('2' );da1.fun1 (); da1.fun1 .call (da2); da1.fun2 (); da1.fun2 .call (da2); da1.fun3 ()(); da1.fun3 .call (da2)(); da1.fun3 ().call (da2); ƒ () { console .log (this .name ) } da1.fun4 ()(); () => { console .log (this .name ) } da1.fun4 .call (da2)(); da1.fun4 ().call (da2); () => { console .log (this .name ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 var name = '达达前端' function Person (name) { this .name = name this .obj = { name : 'obj' , fun1 : function ( ) { return function ( ) { console .log (this .name ) } }, fun2 : function ( ) { return () => { console .log (this .name ) } } } } var da1 = new Person ('1' )var da2 = new Person ('2' )da1.obj .fun1 ()(); da1.obj .fun1 .call (da2)(); da1.obj .fun1 ().call (da2); da1.obj .fun2 ()(); da1.obj .fun2 .call (da2)(); da1.obj .fun2 ().call (da2);
1 2 3 4 5 6 7 8 9 10 function fun ( ) { console .log (this .a ); }; var a = 'da' ;(function ( ){ 'use strict' ; fun (); })();
this的指向 示例:
1 2 3 4 5 function dada ( ) { this .a = 'da' ; console .log (this .a ); } dada ();
函数dada中的this,在函数被调用时确定,指向函数当前运行的环境
示例:
1 2 3 4 5 6 7 8 9 10 11 var a = 'da' ;function da ( ) { console .log (this .a ); }; var obj = { a : 'da1' , fun : da }; obj.fun ();
对象方法调用,指向这个对象obj
call模拟实现 示例:
1 2 3 4 5 6 7 8 9 var obj = { name : 'dada' }; function fun ( ) { console .log (this .name ); }; fun.call (obj);
1 2 3 4 5 6 7 8 9 10 var obj = { name : 'dada' , fun : function ( ) { console .log (this .name ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 obj.fun = 函数(赋值一个函数) obj.fun () delete obj.fun 这个属性var obj = { name : 'dada' }; function fun ( ) { console .log (this .name ); }; fun.call (obj);
看着上面的写下面的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Function .prototype .myCall = function (一个对象context ) { context.fun = this ; context.fun (); delete context.fun ; } var obj = { name : 'dada' }; function dada ( ) { console .log (this .name ); }; dada.myCall (obj);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var obj = { value : 'dada' }; function fun (name, age ) { console .log (name) console .log (age) console .log (this .value ); } fun.call (obj, 'da' , 12 );
arguments
是类数组对象
1 2 3 4 5 6 7 8 看看arguments arguments = { 0 : obj, 1 : 'da' , 2 : 12 , length : 3 }
下面一步是为了取出参数:
call原方法,调用是分开的
JavaScript eval() 函数
定义和用法
eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。
如果参数是一个表达式,eval() 函数将执行表达式。如果参数是Javascript语句,eval()将执行 Javascript 语句。
1 2 3 4 5 6 7 8 9 Function .prototype .myCall = function (context ) { context.fun = this ; var args = []; for (var i = 1 , len = arguments .length ; i < len; i++) { args.push ('arguments[' + i + ']' ); } eval ('context.fun(' + args +')' ); delete context.fun ; }
注意:参数可以为null
1 2 3 4 5 var name = 'dada' ;function fun ( ) { console .log (this .name ); } fun.call (null );
so改一下
1 2 3 4 5 6 7 8 9 10 11 Function .prototype .myCall = function (context ) { var context = context || window ; context.fun = this ; var args = []; for (var i = 1 , len = arguments .length ; i < len; i++) { args.push ('arguments[' + i + ']' ); } var result = eval ('context.fun(' + args +')' ); delete context.fun return result; }
apply模拟实现 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 传入一个对象,和数组 代码来自于@掘金冴羽 Function .prototype .apply = function (context, arr ) { var context = Object (context) || window ; context.fn = this ; var result; if (!arr) { result = context.fn (); } else { var args = []; for (var i = 0 , len = arr.length ; i < len; i++) { args.push ('arr[' + i + ']' ); } result = eval ('context.fn(' + args + ')' ) } delete context.fn return result; }
bind模拟实现 bind绑定函数,特点,返回一个函数,可以传参
示例:
1 2 3 4 5 6 7 8 9 10 11 12 var obj = { name : 'da' ; }; function fun ( ) { console .log (this .name ); } var da1 = fun.bind (obj);da1 ();
bind()方法创建一个新的函数,在bind()被调用时,新函数的this被指向bind()的第一个参数,绑定对象,其余参数将是新函数的参数。
bind改变函数this的指向,但bind并不会立即执行函数,而是返回一个绑定了this的新函数。
模拟实现:
模拟实现第一步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Function .prototype .myBind = function (context ){ var that = this return function ( ){ return that.apply (context) } } Function .prototype .bind_ = function (obj ) { var fn = this ; return function ( ) { fn.apply (obj); }; };
模拟实现第二步:支持函数传参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Function .prototype .myBind = function (context ) { var that = this ; var args = Array .prototype .slice .call (arguments , 1 ); return function ( ) { var bindArgs = Array .prototype .slice .call (arguments ); return that.apply (context,args.concat (bindArgs)); } } Function .prototype .bind_ = function (obj ) { var args = Array .prototype .slice .call (arguments , 1 ); var fn = this ; return function ( ) { fn.apply (obj, args); }; }; Function .prototype .bind_ = function (obj ) { var args = Array .prototype .slice .call (arguments , 1 ); var fn = this ; return function ( ) { var params = Array .prototype .slice .call (arguments ); fn.apply (obj, args.concat (params)); }; };
新增this判断以及原型继承
1 2 3 4 5 6 7 8 9 10 11 12 13 Function .prototype .bind_ = function (obj ) { var args = Array .prototype .slice .call (arguments , 1 ); var fn = this ; var instanceObj = function ( ) { var params = Array .prototype .slice .call (arguments ); fn.apply (this .constructor === fn ? this : obj, args.concat (params)); }; instanceObj.prototype = fn.prototype ; return instanceObj; };
模拟实现修改版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Function .prototype .bind = Function .prototype .bind || function (context ) { var me = this ; var args = Array .prototype .slice .call (arguments , 1 ); var F = function ( ) {}; F.prototype = this .prototype ; var bound = function ( ) { var innerArgs = Array .prototype .slice .call (arguments ); var finalArgs = args.concat (innerArgs); return me.apply (this instanceof F ? this : context || this , finalArgs); } bound.prototype = new F (); return bound; } Function .prototype .myBind = function (obj ) { if (typeof this !== "function" ) { throw new Error ('error' ) }; var args = Array .prototype .slice .call (arguments , 1 ); var fn = this ; var fn_ = function ( ) {}; var instanceObj = function ( ) { var params = Array .prototype .slice .call (arguments ); fn.apply (this .constructor === fn ? this : obj, args.concat (params)); console .log (this ); }; fn_.prototype = fn.prototype ; instanceObj.prototype = new fn_ (); return instanceObj; };
看到了这样的实现:(一起探讨,您可以通过写一篇文章来给我看哦)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 bind : function bind (that ) { var target = this ; if (!isCallable (target)) { throw new TypeError ('Function.prototype.bind called on incompatible ' + target); } var args = array_slice.call (arguments , 1 ); var bound; var binder = function ( ) { if (this instanceof bound) { var result = target.apply ( this , array_concat.call (args, array_slice.call (arguments )) ); if ($Object(result) === result) { return result; } return this ; } else { return target.apply ( that, array_concat.call (args, array_slice.call (arguments )) ); } }; var boundLength = max (0 , target.length - args.length ); var boundArgs = []; for (var i = 0 ; i < boundLength; i++) { array_push.call (boundArgs, '$' + i); } bound = Function ('binder' , 'return function (' + boundArgs.join (',' ) + '){ return binder.apply(this, arguments); }' )(binder); if (target.prototype ) { Empty .prototype = target.prototype ; bound.prototype = new Empty (); Empty .prototype = null ; } return bound; }
扩展 MDN上的文档:
bind()方法创建一个新的函数,当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供要给给定的参数序列
apply()方法调用一个函数,其具有一个指定的this指,以及作为一个数组提供的参数
es6方式,示例:
1 2 3 4 5 6 7 8 9 10 Function .protype .myCall = function (context ) { var context = context || window ; context.fun = this ; var args = []; for (var i=1 , len = arguments .length ; i<len; i++) { args.push (arguments [i]); } context.fun (...args) delete context.fun }
1 2 3 4 5 6 7 Function .prototype .myCall = function (context,...args ) { context = context || window ; context.fun = this ; let temp = context.fun (...args); delete context.fun ; return temp; }
注意:永远不要使用 eval!
js中的new() 请你讲一下,在js中使用new操作符具体做了什么事情
1、创建一个空的对象
2、链接到原型
3、绑定this指向,执行构造函数
4、确保返回的是对象
示例:
1 2 3 4 5 var obj = new da ();var obj = {};obj.__proto__ = da.prototype ; da.call (obj);
1 2 3 4 5 6 7 function A ( ){}var a = new A ();a.__proto__ === A.prototype A.__proto__ === Function .prototype
补充:prototype和__proto__
每一个函数都有一个prototype的属性,每一个由该函数实例化的对象都包含一个隐式指针(__proto__
)指向该函数的prototype属性
new运算符
创建一个空的JavaScript对象{}
链接该对象到另一个对象
将新创建的对象作为this的上下文
如果该函数没有返回对象,则返回this
示例:
1 2 3 4 5 6 7 8 9 10 function da (name, age, year ) { this .name = name; this .age = age; this .year = year; } const da1 = new da ('dada' , '12' , 2333 );console .log (da1.name );
1 2 3 4 5 6 7 8 9 10 11 12 13 function create ( ){ let obj = new Object (); let Constructor = [].shift .call (arguments ); obj.__proto__ = Constructor .prototype ; let result = Constructor .apply (obj,arguments ); return typeof result === "object" ? result : obj; }
Object.create
的模拟实现:
1 2 3 4 5 Object .create = function ( o ) { function f ( ){} f.prototype = o; return new f; };
参考文献 如果静下心来看的话是一定会有收获的!
不用call和apply方法模拟实现ES5的bind方法
【建议👍】再来40道this面试题酸爽继续(1.2w字用手整理)
JavaScript深入之call和apply的模拟实现
JavaScript深入之bind的模拟实现
面试官问:能否模拟实现JS的bind方法