js前端面试题


个人博客:xiaolan1.icu


1.预编译

规律一:任何变量,如果未经声明就赋值,此变量是属于 window 的属性,而且不会做变量提升。(注意,无论在哪个作用域内赋值)

比如说,如果我们直接在代码里写 console.log(a),这肯定会报错的,提示找不到 a。但如果直接写 a = 100,这就不会报错,此时,这个 a 就是 window.a

规律二:一切声明的全局变量,全是window的属性。(注意,是全局作用域内声明的全局变量,不是局部变量)

比如说,当我定义 var a = 200 时,此时这个 a 就是 window.a

function fn(a,c){
	console.log(a)  //function a(){ }
    var a = 123
    console.log(a)  //123
    console.log(c)  //function c(){ }
    function a(){ }
    if(false){ 
    	var d=654
    }
    console.log(d)  //undefined
    console.log(b)  //undefined
    var b = function (){ }
    console.log(b)  //function (){ }
    function c(){ }
    console.log(c)  //function c(){ }
}
fn(1,2)

预编译
做法:
1.创建AO对象 
2.找形参和变量的声明,作为AO对象的属性名,值为undefined 
3.实参和形参相统一
4.找函数声明,会覆盖变量的声明
AO{
	a:undefined 1 function a(){ }
	c:undefined 2 function c(){ }
	d:undefined
	b:undefined
}
预编译后函数按执行顺序开始执行

2.作用域

1.全局作用域

(1)全局作用域在页面打开时被创建,关闭时被销毁

(2)编写script标签中的变量和函数,作用域为全局,在页面任意位置都可以访问到

(3)在全局作用域中有全局对象window,由浏览器创建,可以直接调用

(4)全局作用域中声明的变量和函数会作为window对象的属性和方法保存

2.函数作用域

(1)调用函数时,函数作用域被创建,调用结束后被销毁

(2)每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的

(3)在函数作用域中可以访问全局作用域的变量,在函数外无法访问函数作用域中的变量

(4)在函数作用域中访问变量、函数时,会先在自身作用域中寻找,没找到的话回到函数的上一级作用域去寻找,直到全局作用域

作用域—先预编译,参照 前面所讲的1.预编译

3.哪些操作会造成内存泄漏?

1.闭包

2.意外的全局变量

3.没被清除的定时器

4.脱离dom的引用 :获取了dom元素,dom在页面中被清楚了,但这个引用依然存在

4.闭包以及单例模式

概念:一个普通函数function,如果他可以访问外层作用域的自由变量,这个函数就是一个闭包

广义:JavaScript中的函数都是闭包

狭义:JavaScript中的一个函数,如果访问了外层作用域的变量,那么它是一个闭包

var aa= 666
function a() {  //定义函数a,生成函数a外的作用域链
   var aa = 123
   return function b() {
             var bb = 231
             console.log(aa);
    }
}
let res= a() //执行函数a,产生函数a内的作用域链,函数a中定义函数b,即函数b产生函数b外的作用域链,被保存在了内存中,
res()  //输出123 虽然函数a的作用域链被销毁了,但函数a返回函数b,函数b外的作用域链保存在了内存中,这里执行了函数b,函数b随之产生函数b内的作用域链,因为函数b中未定义aa,所以返回上一级作用域链去查找aa,aa=123,输出123;若函数a中未定义aa,则再返回上一级作用域链中查找aa,直到返回到全局作用域链中查找aa,这里输出666

//es5单例模式,body中有一个<button id="button">登陆</button>
var createLogin = function () {
     var div = document.createElement('div')
     div.innerHTML = '123456'
     document.body.append(div)
     return div
 }
 var getSingle = function (fn) {
     var result; 
     return function () {
         return result || (result = fn.apply(this, arguments))
     }
 }
 var create = getSingle(createLogin)
 document.querySelector('#button').addEventListener('click', function () {
     var loginLay = create()
     loginLay.style.display = 'block'
 }) //点击登陆,会出现一次123456,再次点击不会产生变化

//es6,class类来实现单例模式,不会用到闭包
//静态方法 static
class Foo{
	static classMethod(){
        return 'hello'
    }
}
let foo = new Foo()
console.log(Foo.classMethod())	//hello
console.log(foo.classMethod())	//foo.classMethod is not a function

//实现单例
class xiaoLan{
    constructor(name,age,sex){
		this.name=name
        this.age = age
        this.sex = sex
    }
    static getInstance(name,age,sex){
		if(!this.instance){
			this.instance = new xiaoLan(name,age,sex)
        }
        return this.instance
    }
}

let xiaolan = xiaoLan.getInstance('小蓝',20,'男')
let xiaolan1 = xiaoLan.getInstance('小蓝',20,'男')
console.log(xiaolan===xiaolan1) //true

5. arguments对象

arguments是类数组对象

注意:箭头函数没有arguments对象

function get(){
    console.log (arguments)
}
get(1,2,3) //Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//转化成数组
function getArr(){
    console.log([...arguments])
}
getArr(1,2,3) //[1,2,3]

6.数组扁平化处理

const arr = [1, [2, [3, [4, [5, 6], 7], 8], 9]]
//利用ES10新增的flat方法
let arr1 = arr.flat(Infinity)
console.log(arr1)	//[1,2,3,4,5,6,7,8,9],底下的输出参照这个
//利用正则表达式+数组的方法
let arr2 = JSON.stringify(arr).replace(/\[|\]/g, '')
arr2 = arr2.split(',').map((item, index) => {
    return parseInt(item)
})
console.log(arr2)
//利用正则表达式与JSON.parse
let arr3 = JSON.parse(
    '[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']'
)
console.log(arr3)
//利用递归
let arr4 = []
let fn = (arr) => {
    for (let i = 0; i < arr.length; i++) {
        if (Array.isArray(arr[i])) {
            fn(arr[i])
        } else {
            arr4.push(arr[i])
        }
    }
}
fn(arr)
console.log(arr4)
//利用数组的reduce方法+递归
let fnc = (arr) => {
    return arr.reduce((pre, cur) => {
        return pre.concat(Array.isArray(cur) ? fnc(cur) : cur)  
    }, [])
}
let arr5 = fnc(arr)
console.log(arr5)

7.对象函数中this指向以及this的绑定规则

this的绑定和定义的位置没有关系,跟函数调用的方式以及调用的位置有关

this是在运行时被绑定的

this的绑定规则:

①默认绑定 :独立的函数调用(函数没有被绑定到某个对象上进行调用)

②隐式绑定 :通过某个对象进行调用

③显示绑定:call,apply,bind在执行函数时,可以明确的绑定this

④new绑定:使用new关键字来调用函数

规则优先级:

①默认绑定规则优先级最低

②显示绑定优先级高于隐式绑定

③new绑定优先级高于隐式绑定

④new 关键字不能和apply,call一起使用,new绑定优先级高于显示绑定

总结:new绑定 >显示绑定(apply/call/bind) >隐式绑定 (obj.foo()) >默认绑定(独立函数调用)

var name = 222
var a = {
    name: 111,
    say: function(){
		console.log(this.name)
    }
}
var fun = a.say
fun()  //fun.call(window) 此时this指向window,输出222 (默认绑定)
a.say()	//a.say.call(a) 此时this指向a,输出111	(隐式绑定)

var b ={
    name: 333,
    say: function(fun){
		fun()
    }
}
b.say(a.say) //直接看b中say这个函数 fun()相当于fun.call(window),此时this指向window,输出 222
b.say = a.say
b.say()  //b.say.call(b),此时this指向b,输出333 (隐式绑定)

function sum(num1,num2){
    console.log( num1+num2,this)
}

//显示绑定
sum.call('asd',20,30)	//50 String{'asd'}
sum.apply('asd',[20,30]) //50 String{'asd'}
var newSum = foo.bind('asd',20,30)
newSum()			//50 String{'asd'}

//默认绑定和显示绑定冲突(显示绑定优先)
function foo(){
    console.log(this)
}
var newFoo = foo.bind('aaa')
newFoo()  //String{'aaa'} 

//我们通过一个new关键字调用一个函数时(构造器),这时候this是在调用这个构造器时创建出来的
//this = 创建出来的对象
function Person(name,age){
    this.name = name
    this.age = age
}
var p =new Person('xiaolan',20) //new绑定
console.log(p.name,p.age) //xiaolan 20

//显示优先级高于隐式示例
var obj = {
	name: 'obj',
    foo: function(){
        console.log(this)
    }
}
obj.foo().call('abc') //String{'abc'}

//bind的优先级高于隐式绑定
function foo(){
    console.log(this)
}
var obj = {
    name: 'obj',
    foo: foo.bind('aaa')
}
obj.foo()  //String{'aaa'}

//new绑定优先级高于隐式绑定示例
var obj = { 
    name: 'obj',
    foo: function (){
        console.log(this)
    }
}
var f = new obj.foo() // foo {}

//new绑定优先级高于显示绑定示例
function foo(){
    console.log(this)
}
var bar = foo.bind('aaa')
var obj = new bar()  // foo {}

8.箭头函数以及箭头函数中this指向

箭头函数不会绑定this(可以使用this)、arguments属性

箭头函数不能作为构造函数来使用,即不能和new一起来使用

箭头函数不使用上述所说的this的绑定规则,而是根据外层作用域来决定this

//如果一个箭头函数,只有一行代码,并且返回一个对象,在箭头函数执行的{}外加上一对()
var bar = () => ({ name: 'xlz', age: 20})

//测试箭头函数中this的指向
var foo = () => {
    console.log(this)
}
foo()	//window
var obj = {foo: foo}
obj.foo() //window
foo.call('abc')	//window

var x = 11;
var obj = {
    x: 22,
    say: () =>{
        console.log(this.x);
    }
}
obj.say(); //因为箭头函数,不满足上面this的指向,此时this指向上一级为window,输出 11

var obj = {
	birth: 2000,
    getAge: function(){
        var b = this.birth; //2000
        var fn = () => new Date().getFullYear() - this.birth; 
        return fn()
    }
};
console.log(obj.getAge());//21,此处this指向它的上层作用域为obj

9. this的面试题

//面试题1
var name ='window'
var person1 = {
    name: 'person1',
    foo1: function(){
        console.log(this.name)
    },
    foo2: () => console.log(this.name),
    foo3: function (){
        return function (){
            console.log(this.name)
        }
    },
    foo4: function() {
		return () => {
            console.log(this.name)
        }
    }
}
var person2 = { name:'person2'}

person1.foo1() //person1(隐式绑定)
person1.foo1.call(person2) //person2(显示绑定优先级大于隐式绑定)

person1.foo2() //window(不绑定作用域,上层作用域是全局)
person1.foo2.call(person2) //同上

person1.foo3()() //window(独立函数调用)
person1.foo3.call(person2)() //window(独立函数调用)
person1.foo3().call(person2) //person2(最终调用返回函数时,用显示绑定)

person1.foo4()() //person1(箭头函数不绑定this,上层作用域this 是person1)
person1.foo4.call(person2)()  //person2(上层作用域被显示的绑定了一个person2)
person1.foo4().call(person2)  //person1(作用域上层找到person1,与call无关) 在箭头函数中,call,apply中得到对象没用,直接不看

//面试题2
var name = 'window'
function Person (name) {
    this.name = name
    this.foo1 = function() {
    	console.log(this.name)
   	}
    this.foo2 = () => console.log(this.name)
    this.foo3 = function (){
        return function() {
			console.log(this.name)
        }
    }
    this.foo4 = function (){
        return () =>{
            console.log(this.name)
        }
    }
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.foo1()	//person1
person1.foo1.call(person2)	//person2(显示优先级高于隐式绑定)

person1.foo2()	//person1 (上层作用域中的this是person1)
person1.foo2.call(person2) //person1,call里的person2没用,不绑定this

person1.foo3()()	//window
person1.foo3.call(person2)	//window
person1.foo3().call(person2)	//person2

person1.foo4()()	//person1
person1.foo4.call(person2)()	//person2
person1.foo4().call(person2)	//person1 下面这六个跟面试1题的最后六个分析方法一样

//面试题3
var name = 'window'
function Person (name){
    this.name = name
    this.obj = {
        name: 'obj',
        foo1: function (){
           	return function(){
				console.log(this.name)
        	}
    	},
    	foo2: function (){
			return () => {
				console.log(this.name)
             }
        }
    }    
}

var person1 = new Person('person1')

person1.obj.foo1()()	//window
person1.obj.foo1.call(person2)()	//window
person1.obj.foo1().call(person2)	//person2

person1.obj.foo2()()	//obj
person1.obj.foo2.call(person2)()	//person2
person1.obj.foo2().call(person2)	//obj

10. call和apply的区别

传递参数不同

function sum(num1,num2){
    console.log( num1+num2,this)
}

sum.call('asd',20,30)	//第一个参数指向调用的对象,后面的参数挨个写进去
sum.apply('asd',[20,30])	//第一个参数指向调用的对象,后面的参数写进一个数组进行传参

11.赋值、浅拷贝和深拷贝

赋值:把一个对象赋值给一个新的变量时,赋的是该对象在栈中的地址,不是堆中的数据。因此两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的

浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型共享同一块内存,会相互影响

深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后两个对象互不影响

//赋值
var obj = {}
var person = {
    name: '张三',
    hobby:['学习','看电影','跑步']
}
var person1 = person
person1.name = '李四'
person1.hobby[0] = '玩游戏'
console.log(person)	  //{name: '李四',hobby:['玩游戏','看电影','跑步']}
console.log(person1)  //{name: '李四',hobby:['玩游戏','看电影','跑步']}

//浅拷贝
function shallowCopy(obj){
    var target = {}
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
			target[i]=obj[i]
        }
    }
    return target
}
var person = {
    name: '张三',
    hobby:['学习','看电影','跑步']
}
var person2 = shallowCopy(person)
person2.name = '李四'
person2.hobby[0]='玩游戏'
console.log(person)		//{name: '张三',hobby:['玩游戏','看电影','跑步']}
console.log(person2)	//{name: '李四',hobby:['玩游戏','看电影','跑步']}

//☆☆☆深拷贝
//函数一
function deepClone(obj){
    var cloneObj = obj.push ? [] : {};
    if(obj === null) return obj
    if(obj instanceof Date) return obj
    if(obj instanceof RegExp) return obj
    if (typeof obj != 'object') {
        return obj
    }
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
			cloneObj[i] = deepClone(obj[i])
        }
    }
    return cloneObj
}

//函数二(简单)
function deepClone(obj) {
   let newObj = obj.push ? [] : {};
   for (var i in obj) {
       if (typeof obj[i] === 'object') {
           newObj[i] = deepClone(obj[i]);
        } else {
            newObj[i] = obj[i];
        }
    }
    return newObj
}

var person = {
    name: '张三',
    hobby:['学习','看电影','跑步']
}
var person3 = deepClone(person)
person3.name = '李四'
person3.hobby[0] = '玩游戏'
console.log(person)		//{name: '张三',hobby:['学习','看电影','跑步']}
console.log(person3)	//{name: '李四',hobby:['玩游戏','看电影','跑步']}

/*浅拷贝的实现方式:
Object.assign()
...args
concat


深拷贝实现方式
$.extend
自定义函数deepClone

12.防抖函数

当持续触发事件 一定时间内没有再触发事件,事件处理函数才会执行一次,如果设定的事件来到之前又一次触发了事件,就重新开始延时

闭包:函数里面return出函数

<!DOCTYPE html>
<html lang="en">
    
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>防抖函数</title>
</head>

<body>
    <input type="text" id="input">
    <script>
        var input = document.querySelector('#input')
		//防抖函数的简单实现
        function debounce(callback, delay) {
            let timer
            return function (value) {
                clearTimeout(timer)
                timer = setTimeout(function () {
                  callback(value)
                }, delay)
            };
        }

        function callback(value) {
            console.log(value);
        }         
        var func = debounce(callback,1000)
        input.addEventListener('keyup', function (e) {
            func(e.target.value)
        })

        //防抖函数运用apply
         function debounce(callback, delay) {
             let timer
             return function () {
                 clearTimeout(timer)
                 timer = setTimeout(() => {
                     callback.apply(this, arguments)
                 }, delay)
             };
        }
      
        input.addEventListener('keyup', debounce(function (e) {
            console.log(e.target.value);
        }, 1000)
        )
        
    </script>
</body>

</html>

13.节流函数

当持续触发事件的时候,保证一段时间内 只调用一次处理函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>节流函数</title>
</head>

<body>
    <button id="button">123</button>
    <script>
        var btn = document.querySelector('#button');
		//节流函数的简单实现
        function throttle(callback, delay) {
            let timer
            return function () {
                if (!timer) {
                    timer = setTimeout(function () {
                        callback.apply(this, arguments)
                        timer = null
                    }, delay)
                }
            }
        }
        
        //节流函数第二种编写方法
        function throttle(callback, delay) {
            let flag = true
            return function () {
                if (!flag) {
                    return
                }
                flag = false
                setTimeout(() => {
                    callback.apply(this, arguments)
                    flag = true
                }, delay)
            }
        }
        btn.addEventListener('click', throttle(function () {
            console.log(123)
        }, 2000))
    </script>
</body>

</html>

14.图片懒加载以及对图片懒加载优化

优势:增强用户体验,优化代码,减少http请求,减少服务器端压

原理:给img的src设置为空,同时给img标签设置一个特殊属性,例如:data-src(自定义设置)用于存放图片的真是预览地址;如果图片未进入可视区域,直接不展示图片,当图片进入可视区域,将data-src的值赋给src

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>图片懒加载</title>
    <style>
        img {
            display: block;
            height: 300px;
        }
    </style>

</head>

<body>
    <div>
        <img src="" data-src="img/f1.png" alt="" />
        <img src="" data-src="img/f2.png" alt="" />
        <img src="" data-src="img/f3.png" alt="" />
        <img src="" data-src="img/f4.png" alt="" />
        <img src="" data-src="img/f5.png" alt="" />
        <img src="" data-src="img/f6.png" alt="" />
        <img src="" data-src="img/f7.png" alt="" />
        <img src="" data-src="img/f8.png" alt="" />
    </div>

    <script>
        var imgs = document.querySelectorAll('img');
        //图片懒加载实现
        function lazyload() {
            var scrollTop = document.documentElement.scrollTop
            var viewportHeight = window.innerHeight || document.documentElement.clientHeight
            for (let i = 0; i < imgs.length; i++) {
                var height = scrollTop + viewportHeight - imgs[i].offsetTop
                if (height > 0) {
                    imgs[i].src = imgs[i].getAttribute('data-src')
                }
            }
        }
        setInterval(lazyload, 1000);
        
        //图片懒加载优化实现
        var num = imgs.length
        var n = 0
        var isLoadImg = false  //是否加载页面中的图片完成

        function lazyload() {
            isLoadImg = n >= num
            var scrollTop = document.documentElement.scrollTop
            var viewportHeight = window.innerHeight || document.documentElement.clientHeight
            for (let i = n; i < num; i++) {
                var height = scrollTop + viewportHeight - imgs[i].offsetTop
                if (height > 0) {
                    imgs[i].src = imgs[i].getAttribute('data-src')
                    n++
                }
            }
        }
        function debounce(callback, delay) {
            let timer
            return function () {
                clearTimeout(timer)
                timer = setTimeout(() => {
                    callback.apply(this, arguments)
                }, delay)
            };
        }
        function throttle(callback, delay, isLoading) {
            if (isLoadImg) {
                return
            }
            let flag = false
            return function () {
                if (flag) {
                    return
                }
                flag = true
                setTimeout(() => {
                    callback.apply(this, arguments)
                    flag = false
                }, delay)

            }
        }
        window.addEventListener('load',throttle(lazyload,100,isLoadImg))
        window.addEventListener('scroll', throttle(lazyload, 100, isLoadImg))
        window.addEventListener('resize',debounce(lazyload, 100))
    </script>
</body>

</html>

15.手写Array.prototype.map方法

var arr = [1, 2, 3]
var array = arr.map((item, index) => {
    return item * 2
})
console.log(array) //[2,4,6]

function map(arr, mapCallback) {
    if (!Array.isArray(arr) || !arr.length || typeof mapCallback !==  'function') {
       return []
   } else {
       let result = []
       for (let i = 0; i < arr.length; i++) {
           result.push(mapCallback(arr[i]))
       }
       return result
   }
}
let res = map(arr, (item) => {
    return item * 2
})
console.log(res); //[2,4,6]

16.策略模式以及表单验证

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>策略模式以及表单验证</title>
</head>

<body>
    <form id="form" action="xxxx.html" method="post">
        用户名:<input type="text" name="username">
        密码:<input type="password" name="password">
        手机号:<input type="text" name="usermobile">
        <button>提交</button>
    </form>
    <script>
        let form = document.querySelector('#form')
        var strategies = {
            isNonEmpty: function (value, errorMsg) {
                if (value === '') {
                    return errorMsg
                }
            },
            minLength: function (value, length, errorMsg) {
                if (value.length <= length) {
                    return errorMsg
                }
            },
            isMobile: function (value, errorMsg) {
                if (!/^1[3|5|8][0-9]{9}$/.test(value)) {
                    return errorMsg
                }
            }
        }

        var Validator = function () {
            this.cache = []
        }
        Validator.prototype.add = function (dom, rule, errorMsg) {
            var arr = rule.split(':')
            this.cache.push(function () {
                var strategy = arr.shift()
                arr.unshift(dom.value)
                arr.push(errorMsg)
                return stra tegies[strategy](...arr)
            })
        }
        Validator.prototype.start = function () {
            for (let i = 0, vaFunc; vaFunc = this.cache[i]; i++) {
                var msg = vaFunc()
                if (msg) {
                    return msg
                }
            }
        }
        var validataFun = function () {
            var validator = new Validator()
            validator.add(form.username, 'isNonEmpty', '用户名不能为空')
            validator.add(form.password, 'minLength:6', '密码长度不能小于6位')
            validator.add(form.usermobile, 'isMobile', '手机号格式不正确')

            var errorMsg = validator.start()
            return errorMsg
        }
        form.onsubmit = function () {
            let msg = validataFun()
            if (msg) {
                alert(msg)
                return false
            }
        }
    </script>
</body>

</html>

17.订阅发布模式

var Event = (function () {
    var list = [],
        listen,
        trigger,
        remove;
    // 订阅
    listen = function (key, fn) {
        if (!this.list[key]) {
            this.list[key] = []
        }
        this.list[key].push(fn)
    }
    // 发布 
    trigger = function () {
        var key = Array.prototype.shift.call(arguments)
        var fns = this.list[key]
        if (!fns || fns.length === 0) {
            return
        }
        for (let i = 0, fn; fn = fns[i]; i++) {
            fn.apply(this, arguments)  //也可以用fn(...arguments)
        }
    }
    // 取消订阅
    remove = function (key, fn) {
        var fns = this.list[key]
        if (!fns) {
            return false
        }
        if (!fn) {
            fn && (fns.length = 0)
        } else {
            for (let i = fns.length - 1; i >= 0; i--) {
                if (String(fn) == String(fns[i])) {
                    fns.splice(i, 1)
                }
            }
        }
    }
    return {
        list,
        listen,
        trigger,
        remove
    }
})()
Event.listen('red', function (size) {
    console.log('尺码是' + size)
})
Event.listen('black', function (size) {
    console.log('尺码是' + size)
})
Event.trigger('red', 42)	//尺码是42
Event.trigger('black', 43)	//尺码是43
Event.remove('red', function (size) {
    console.log('尺码是' + size)
})
Event.trigger('red', 43)	//因为标识符为red的订阅被移除了,这里不会输出任何东西

18.高阶函数

把一个函数如果接受另外一个函数作为参数,或者该函数会返回另外一个函数作为返回值的函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

blue11l

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值