本文共 7048 字,大约阅读时间需要 23 分钟。
function Person (name, age) { this.type = 'human' this.name = name this.age = age}function Student (name, age) { // 借用构造函数继承属性成员 Person.call(this, name, age)}var s1 = Student('张三', 18)console.log(s1.type, s1.name, s1.age) // => human 张三 18
function Person (name, age) { this.type = 'human' this.name = name this.age = age}Person.prototype.sayName = function () { console.log('hello ' + this.name)}function Student (name, age) { Person.call(this, name, age)}// 原型对象拷贝继承原型对象成员for(var key in Person.prototype) { Student.prototype[key] = Person.prototype[key]}var s1 = Student('张三', 18)s1.sayName() // => hello 张三
function Person (name, age) { this.type = 'human' this.name = name this.age = age}Person.prototype.sayName = function () { console.log('hello ' + this.name)}function Student (name, age) { Person.call(this, name, age)}// 利用原型的特性实现继承Student.prototype = new Person()var s1 = Student('张三', 18)console.log(s1.type) // => humans1.sayName() // => hello 张三
new Function
function foo () { }
var foo = function () { }
下面是一个根据条件定义函数的例子:
if (true) { function f () { console.log(1) }} else { function f () { console.log(2) }}
以上代码执行结果在不同浏览器中结果不一致。
不过我们可以使用函数表达式解决上面的问题:
var fif (true) { f = function () { console.log(1) }} else { f = function () { console.log(2) }}
this
指向的不同场景函数的调用方式决定了 this
指向的不同:
调用方式 | 非严格模式 | 备注 |
---|---|---|
普通函数调用 | window | 严格模式下是 undefined |
构造函数调用 | 实例对象 | 原型方法中 this 也是实例对象 |
对象方法调用 | 该方法所属对象 | 紧挨着的对象 |
事件绑定方法 | 绑定事件对象 | |
定时器函数 | window |
这就是对函数内部 this 指向的基本整理,写代码写多了自然而然就熟悉了。
Function
的实例那了解了函数 this 指向的不同场景之后,我们知道有些情况下我们为了使用某种特定环境的 this 引用,
这时候时候我们就需要采用一些特殊手段来处理了,例如我们经常在定时器外部备份 this 引用,然后在定时器函数内部使用外部 this 的引用。 然而实际上对于这种做法我们的 JavaScript 为我们专门提供了一些函数方法用来帮我们更优雅的处理函数内部 this 指向问题。 这就是接下来我们要学习的 call、apply、bind 三个函数方法。call()
方法调用一个函数, 其具有一个指定的 this
值和分别地提供的参数(参数的列表)。
注意:该方法的作用和 `apply()` 方法类似,只有一个区别,就是 `call()` 方法接受的是若干个参数的列表,而 `apply()` 方法接受的是一个包含多个参数的数组。
语法:
fun.call(thisArg[, arg1[, arg2[, ...]]])
参数:
thisArg
arg1, arg2, ...
apply()
方法调用一个函数, 其具有一个指定的 this
值,以及作为一个数组(或类似数组的对象)提供的参数。
注意:该方法的作用和 `call()` 方法类似,只有一个区别,就是 `call()` 方法接受的是若干个参数的列表,而 `apply()` 方法接受的是一个包含多个参数的数组。
语法:
fun.apply(thisArg, [argsArray])
参数:
thisArg
argsArray
apply()
与 call()
非常相似,不同之处在于提供参数的方式。
apply()
使用参数数组而不是一组参数列表。例如: fun.apply(this, ['eat', 'bananas'])
bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。
当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。 一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。语法:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
参数:
thisArg
arg1, arg2, …
返回值:
返回由指定的this值和初始化参数改造的原函数拷贝。
示例1:
this.x = 9; var module = { x: 81, getX: function() { return this.x; }};module.getX(); // 返回 81var retrieveX = module.getX;retrieveX(); // 返回 9, 在这种情况下,"this"指向全局作用域// 创建一个新函数,将"this"绑定到module对象// 新手可能会被全局的x变量和module里的属性x所迷惑var boundGetX = retrieveX.bind(module);boundGetX(); // 返回 81
示例2:
function LateBloomer() { this.petalCount = Math.ceil(Math.random() * 12) + 1;}// Declare bloom after a delay of 1 secondLateBloomer.prototype.bloom = function() { window.setTimeout(this.declare.bind(this), 1000);};LateBloomer.prototype.declare = function() { console.log('I am a beautiful flower with ' + this.petalCount + ' petals!');};var flower = new LateBloomer();flower.bloom(); // 一秒钟后, 调用'declare'方法
call 和 apply 特性一样
this
的指向null
或者 undefined
则内部 this 指向 windowbind
function fn(x, y, z) { console.log(fn.length) // => 形参的个数 console.log(arguments) // 伪数组实参参数集合 console.log(arguments.callee === fn) // 函数本身 console.log(fn.caller) // 函数的调用者 console.log(fn.name) // => 函数的名字}function f() { fn(10, 20, 30)}f()
function eat (callback) { setTimeout(function () { console.log('吃完了') callback() }, 1000)}eat(function () { console.log('去唱歌')})
function genFun (type) { return function (obj) { return Object.prototype.toString.call(obj) === type }}var isArray = genFun('[object Array]')var isObject = genFun('[object Object]')console.log(isArray([])) // => trueconsole.log(isArray({ })) // => true
function fn () { var count = 0 return { getCount: function () { console.log(count) }, setCount: function () { count++ } }}var fns = fn()fns.getCount() // => 0fns.setCount()fns.getCount() // => 1
{ var foo = 'bar'}console.log(foo)if (true) { var a = 123}console.log(a)
作用域链示例代码:
var a = 10function fn () { var b = 20 function fn1 () { var c = 30 console.log(a + b + c) } function fn2 () { var d = 40 console.log(c + d) } fn1() fn2()}
闭包就是能够读取其他函数内部变量的函数,
由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量, 因此可以把闭包简单理解成 “定义在一个函数内部的函数”。 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。闭包的用途:
示例1:
var arr = [10, 20, 30]for(var i = 0; i < arr.length; i++) { arr[i] = function () { console.log(i) }}
示例2:
console.log(111)for(var i = 0; i < 3; i++) { setTimeout(function () { console.log(i) }, 0)}console.log(222)
示例3:投票
示例4:判断类型
示例5:沙箱模式
思考题 1:
var name = "The Window";var object = { name: "My Object", getNameFunc: function () { return function () { return this.name; }; }};console.log(object.getNameFunc()())
思考题 2:
var name = "The Window"; var object = { name: "My Object", getNameFunc: function () { var that = this; return function () { return that.name; }; }};console.log(object.getNameFunc()())
function fn1 () { console.log(111) fn2() console.log('fn1')}function fn2 () { console.log(222) fn3() console.log('fn2')}function fn3 () { console.log(333) fn4() console.log('fn3')}function fn4 () { console.log(444) console.log('fn4')}fn1()
function factorial (num) { if (num <= 1) { return 1 } else { return num * factorial(num - 1) }}
转载地址:http://sixmi.baihongyu.com/