一、基本数据类型以及循环
二、函数
1. 回调函数
- 定义
- 示例
2. 变量作用域(使用var时,变量作用域和变量提升的关系?写个体现这种关系的demo)
- 闭包函数
- 实现闭包的集中方式? 将函数内部的变量或者函数直接赋值给一个全局变量; 将函数内部的函数return出去,即将其返回值赋值给一个全局变量。
- 定义?特点?循环中使用闭包解决了什么问题? 问题思考:
Demo:1
function F() {
var arr = [], i;
for (i = 0; i < 3; i++) {
arr[i] = function () {
return i;
};
}
return arr;
}
let arr = F();
arr[0]() // 3
arr[2]() // 3
arr[3]() // 3
期望打印是0,1,2,为什么每次都是3 ?
demo:2
如何改进?
- 示例(包含getter/setter的安全函数怎么实现?迭代器next怎么实现?)
三、对象
(1)对象中 this 定义和使用场景
(2)场景对象的方式
方式1:使用new操作符
- 对象中 构造函数 的定义和使用场景,使用构造函数创建对象的好处(能够传参使用,创建多个对象)?
- 构造器属性:一个对象的
construction函数的定义?使用场景? - instanceof 操作符 ? 通过 instanceof 操作符,我们可以测试一个对象是不是由某个指定的构造器函数所创建的。
>
> h instanceof Hero;faxdfasdfasdf
true
(3)两个对象比较的问题
let a = {age: 2};
let b = {age: 2};
a === b // false 解释为什么是false?
(4)内建对象
valueOf()
valueOf()方法也是为所有对象共有的一个方法。对于简单对象(即以Object()为构造器的对象)来说,valueOf()方法所返回的就是对象自己。
var a = {};
a.valueOf() === a // true
(5)Function
每个函数都有call()、apply() 方法等,也有length、constructor、prototype属性
- 5.1
prototype属性
每个函数的 prototype 属性中都指向了一个对象;
它只有在该函数是构造器时才会发挥作用;
该函数创建的所有对象都会持有一个该 prototype 属性的引用,并可以将其当做自身的属性来使用。
Demo:
var ninja = {
name: 'Ninja',
say: function () {
return 'I am a ' + this.name;
}
};
> F.prototype = ninja;
> function F(){}
> var baby_ninja = new F();
> baby_ninja.name; // "Ninja"
> baby_ninja.say(); // "I am a Ninja"
- 5.2
call()和apply()这两个方法还有另外一个功能,它可以让一个对象去“借用”另一个对象的方 法,并为己所用。也就是改变this指向。
Demo:
var some_obj = {
name: 'Ninja',
say: function (who) {
return 'Haya ' + who + ', I am a ' + this.name;
}
};
> some_obj.say('Dude'); // "Haya Dude, I am a Ninja"
> var my_obj = {name: 'Scripting guru'};
下面期望my_obj调用some_obj的say方法
some_obj.say.call(my_obj, 'jack') // "Haya jack, I am a Scripting guru"
apply()的工作方式与 call()基本相同,唯一的不同之处在于参数的传递形式。一个传字符串,一个传数组。
理解并举例说明apply()、call()、bind()的区别?
(6)String
String对象的一些方法:
indexOf()、includes(),可用于字符的模糊查询。
(7)Date
ES5 还为 Date 构造器新增了 now()方法,以用于返回当前 timestamp。
> Date.now(); // 1606362656105
- 计算生日: 计算一个自己2030年的生日(6 月 20 日)是星期几,就可以这样:
> var d = new Date(2030, 5, 20);
> d.getDay(); // 4 生日是星期四
- 计算从2020至2030之间周一至周日各多少天
var stats = [0,0,0,0,0,0,0];
for (var i = 2016; i < 3016; i++) {
stats[new Date(i, 5, 20).getDay()]++;
}
[140, 146, 140, 145, 142, 142, 145] // 周一140天,周二146天等等
三、原型
明白此图,你可以不用往下看了。还有更多事情等着你去做~~传送门
(1)函数
每个函数都有call()、apply()等方法,也有length、constructor、prototype等属性。
但是,prototype 一般是用在构造函数中。
function Gadget(name, color) {
this.name = name;
this.color = color;
this.whatAreYou = function () {
return 'I am a ' + this.color + ' ' + this.name;
};
}
Gadget.prototype.price = 100;
> var newtoy = new Gadget('webcam', 'black');
// 继续操作
Gadget.prototype.get = function(what) {
return this[what];
};
// 即便 newtoy 对象在 get()方法定义之前就已经被创建了,但我们
依然可以在该对象中访问新增的方法:
> newtoy.get('color');
"black"
(2)对象
每个实例对象都有constructor等属性。返回实例对象的构造函数。
// 语法:
object.constructor
constructor 属性返回对创建此对象的数组函数的引用。
// 情况1:
> let a = {age: 213}
> a.constructor
ƒ Object() { [native code] } // 指向最高级Object
// 情况2:
> function J (name) {this.name = name;}
> const p = new J('jack');
> p.constructor
ƒ J (name) {this.name = name;} // 指向构造函数J
> p.constructor === J
true
(3)hasOwnProperty
hasOwnProperty方法来判断一个属性是自身属性还是原型属性。
如果遇上对象的自身属性与原型属性同名,则对象自身属性的优先级高于原型属性。
> function N(name) {this.name = name};
> const j = new N('jack');
> N.prototype.name = 'tom';
> N.prototype.age = 12;
> j.name
'jack'
> j.age
12
// 通过 hasOwnProperty()方法来判断一个属性是自身属性还是原型属性。
> j.hasOwnProperty('name')
true
> j.hasOwnProperty('age')
false
- 仍然可以使用
hasOwnProperty()属性,判断一个对象的某个原型属性到底是原型链中的哪个原型的属性。 判断 toString 属性来自于哪里?
> toy.hasOwnProperty('toString');
false
> toy.constructor.hasOwnProperty('toString');
false
> Object.prototype.hasOwnProperty('toString'); // 此方法终于找到
true
(4)isPrototypeOf()方法
每个对象中都会有一个 isPrototypeOf() 方法,这个方法会告诉我们当前对象是否是另一个对象的原型。
var monkey = {
hair: true,
feeds: 'bananas',
breathes: 'air'
};
function Human(name) {
this.name = name;
}
Human.prototype = monkey;
> var george = new Human('George');
> monkey.isPrototypeOf(george);
true // “monkey 是 george的原型
需要注意的是,我们在这里是预先知道了
monkey可能是george的原型,才提出了 问题“monkey是你的原型吗?”,然后获得一个布尔值作为回应。那么,是否能在不知道 某个对象原型是什么的情况下,获得对象的原型呢?
答案是:大多数浏览器可以。因为大 多数浏览器都实现了ES5的Object.getPrototypeOf()方法。
> Object.getPrototypeOf(george) === monkey;
true
而对于另一部分实现了 ES5 部分功能,却没有实现 getPrototypeOf()方法的浏览
器,我们可以使用特殊属性__proto__。
(5)__proto__
因为该属性在
Internet Explorer之类的浏览器中是不存在的,因此脚本就不能实现跨平台了。
另外,__proto__与 prototype 并不是等价的。__proto__实际上 是某个实例对象的属性,而 prototype 则是属于构造器函数的属性。
具体理解如下图:传送门
注意:__proto__只能在学习或调试的环境下使用。或者如果你的代码碰巧只需 要在符合 ES5 标准的环境中使用的话,你也可以使用 Object.getPrototypeOf()方法。
(6)更好的使用实例对象
- 枚举对象属性
for-in遍历对象,最好使用for-in
(7)使用原型注意点
在处理原型问题时,我们需要特别注意以下两种行为:
- 当我们对原型对象执行完全替换时,可能会触发原型链中某种异常
(exception)。prototype.constructor属性是不可靠的。 当我们重写某对象的 prototype 时,需要重置相 应的constructor 属性。
四、继承
继承中用到的检测语法:传送门
instanceof// 运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个 要检测对象的原型链上isPrototypeOf// 判断的是一个对象是否存在于另一个对象的原型链之中
JS中继承的几种方式:
原型链继承// 控制构造函数的prototype属性,进而赋值并修改原型