Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

深入理解ES6函数系列二 #3

Open
laihuamin opened this issue Aug 18, 2017 · 0 comments
Open

深入理解ES6函数系列二 #3

laihuamin opened this issue Aug 18, 2017 · 0 comments

Comments

@laihuamin
Copy link
Owner

laihuamin commented Aug 18, 2017

承接上面一篇

在ES6中如何判断是否是new调用了构造函数

//es6
function Person(name){
    if(typeOf new.target !== undefined){
        this.name = name
    }else{
        throw new Error('you must use new with Person')
    }
}
var person = new Person(lai);
var notPerson = Person.call(person, 'lai'); //报错

ES6中增加理new.target属性,减少了new调用的不确定性

块级函数

在ES3以前,在代码块中声明函数,严格意义上是一个语法错误,但是大部分浏览器都支持这种语法,但是在行为上会有差异,最佳实践是不要在代码块中声明函数,而是选择函数表达式。

在ES5的严格模式中声明函数会发生错误,因为想要去兼容这种不确定行为

"use strict"
if(true) {
    function doSomething(){
    }
}
//报错

但在ES6中却没有问题,因为ES6中会将doSomething()视为块级声明

"use strict"
if(true) {
    console.log(typeof doSomething) //function
    function doSomething(){
    }
doSomething();
}
console.log(typeof doSomething) //undefined

函数声明存在变量提升,当你换成let定义函数表达式的时候,就会发生错误,即暂时性死区

在非严格模式下使用块级函数

if(true) {
    console.log(typeof doSomething) //function
    function doSomething(){
    }
doSomething();
}
console.log(typeof doSomething) //function

作用域会被提升到所在函数,或者是全局环境的顶部

箭头函数

他的行为在很多重要的方面与传统函数有不同:

1.没有this、super、arguments、也没有new.target绑定this、super、arguments。
2.也不能被new调用:所以不能成为构造函数。
3.没有原型,没有prototype属性
4.没有arguments对象,所以你必须依赖具名参数或剩余参数来访问函数的参数
5.不能变更this的绑定:this的值在函数内部不能被修改,在函数的整个生命周期中this的值固定不变
6.不允许重复具名函数:箭头函数不允许拥有重复的具名函数参数。

箭头函数的语法

var sum = (num1, num2) => num1+num2;
//等价于
var sum = function(num1, num2){
    return num1 + num2;
}

箭头函数返回字面量

var person = (name, age) => ({'name': name, 'age': age})

创建立即调用函数表达式

let person = function(name) {
    return {
        getName: function() {
            return name;
        }
    }
}('lai');
console.log(person.getName()); //'lai'
//等价于
let person = (name) => {
    return {
        getName: function() {
            return name;
        }
    }
}('lai');
console.log(person.getName()); //'lai'

JS常见的问题this的绑定,由于一个函数内部this可以被改变,取决的函数的上下文。因此完全会出现一种情况,你想修改一个对象,却修改了另一个对象,例如:

var PageHandler = {
    id: '123',
    init: function(){
        document.addEventListener('click', function(event){
            this.doSomenthing(event.type);
        }, false);
    },
    doSomenthing: function(type){
        console.log(`Handling${type}for${this.id}`);    
    }
}

上述例子会发生错误,原因很简单,谁调用this,this指向谁,那么在init方法中是document对象调用this,所以this指向document对象,但是这个对象没有doSomething方法,在ES5中还有解决方法

var PageHandler = {
    id: '123',
    init: function(){
        document.addEventListener('click', (function(event){
            this.doSomenthing(event.type);
        }).bind(this), false);
    },
    doSomenthing: function(type){
        console.log(`Handling${type}for${this.id}`);    
    }
}

这里其实使用bind在创建了一个新的函数,在将当前的this,也就是document绑定到新的函数上,所以没有发生错误

利用箭头函数,因为箭头函数没有this绑定只能通过作用域链来查找,如果一个箭头函数包含在非箭头函数内,那么他会指向这一个函数,否者,this的值就会指向全局变量

箭头函数和数组

var result = value.sort((a,b) => a-b);

不用书写过多代码

仍可以对箭头函数使用apply,bind,call,但是this不会发生变化

尾调用优化

  • 什么是尾调用

尾调用值得是调用函数的语句是另一个函数的最后语句

function doSomething(){
    return doSomethingElse(); //尾调用
}
  • ES5中如何实现尾调用

ES5中实现尾调用的方法是:一个新的栈桢被创建并推到调用栈之上,用于表示这次函数的调用。这意味着之前每个栈帧都被保留在内存中,当调用栈帧内存过大会出现问题。

  • ES6中有何不同

ES6的严格模式中,特定减少调用栈的大小,非严格模式不变,当满足条件时,会清除当前栈帧,并且再次利用它,新栈帧的特性:

1.尾调用不能引用当前栈帧中的变量——即不能是闭包
2.进行尾调用的函数在尾调用返回的结果后不能做额外操作
3.尾调用的结果作为当前函数的返回值

尾调用优化是你在书写任意递归函数是都需要考虑的因素,因为可以显著提高性能。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant