原型
- 如何判断一个变量是不是数组
该题考查原型和原型链,判断方法:- instanceof
- Array.prototype.toString.call
- Array.isArray
- 手写一个简易的jquery,考虑插件和扩展性
(function name(params) {
class jQuery {
length = 0;
constructor(selector) {
const dom = document.querySelectorAll(selector);
const length = dom.length;
this.length = length;
for (let index = 0; index < length; index++) {
this[index] = dom[index];
}
return this
}
get(index) {
return this[index]
}
each(fn) {
const length = this.length
for (let index = 0; index < length; index++) {
const element = this[index];
fn(element, index)
}
}
on(type, fn, options) {
options = options || false;
return this.each(ele => {
ele.addEventListener(type, fn, options)
})
}
}
class myJQuery extends jQuery {
constructor(selector) {
super(selector);
}
// 扩展方法
css(property, value) {
this.each(ele => {
ele.style[property] = value
})
}
}
window.$ = function name(selector) {
return new myJQuery(selector)
}
})()
- 原型本质,怎么理解
原型即某对象的prototype,每个实例都有一个隐式原型__proto__
和显示原型prototype
;当实例调用实例方法时,会先再自己的__proto__
找到该对象,然后进行对应方法的查找,若不存在则向上以及的原型查找直到找到该方法或Object,即Object就是所有实例最终的prototype
,Object的prototype
指向null - 手写圣杯模式继承
圣杯模式继承即不实现直接继承,通过临时的function作为中间者,当给son的prototype增加属性时不会影响father。
var inherit = (function () {
function __tempFunc() { }
return function(Target, Origin){
__tempFunc.prototype = Origin.prototype;
Target.prototype = new __tempFunc(); // target.__proto__ => Origin.prototype
Target.prototype.constructor = Target;
Target.prototype.uber = Origin.prototype
}
})()
class
class是function的语法糖,简化了function创建和继承的一系列操作。
- constructor
- 属性
- 方法
举个例子:
class Person {
name = '张三'
constructor (name) {
this.name = name
}
speak (lang) {
console.log(lang)
}
}
// 通过new关键字创建实例
var person1 = new Person('李四');
person1.speak('en');
继承和类型判断
- 继承
class People {
constructor(name) {
this.name = name;
}
eat() {
console.log(this.name + ' is eating something');
}
}
class Student extends People {
constructor(name, number) {
super(name);
this.number = number;
}
sayHi(){
console.log('hi')
}
}
class Teacher extends People {
constructor(name, major) {
super(name);
this.major = major;
}
teach(){
console.log('hi')
}
}
const teaWang = new Teacher('王', '语文');
const stuXia = new Teacher('夏', '222222');
teaWang.number; // undefined
teaWang.major; // 语文
stuXia.major; // undefined
- 类型判断
在javascript类型中,array是继承于Object的,可以用instanceof进行引用类型的判断,instanceof可以用于判断原型链上的继承关系。
stuXia instanceof Student // true
stuXia instanceof People // true
stuXia instanceof Object // true
[] instanceof Array // true
[] instanceof Object // true
{} instanceof Object // true
作用域
- this的不同应用场景,如何取值
- 在class方法中调用:this是class
- 箭头函数:this是上级作用域
- 作普通函数被调用:this是window
- 使用call、apply、bind:this是第一个参数
- 作为class方法被调用:this是class
注意:this指向是在函数执行的时候确认而非函数定义的时候确认
举个例子:
function fn() {
console.log(this)
}
fn(); // window
fn.call({x: 1000}); // {x: 1000}
const fn1 = fn.biond({x: 200});
fn1(); // {x: 200}
- 手写bind、apply、call函数
function fn(a, b, c, d) {
console.log('this', this);
console.log(a, b, c, d);
return 'this is fn'
}
function transformArrayLikeToArray(arrLike) {
return Array.prototype.slice.call(arrLike)
}
Function.prototype.bind1 = function () {
const args = transformArrayLikeToArray(arguments);
const self = this; // current fn
const context = args.shift();
return function () {
const __args = transformArrayLikeToArray(arguments);
return self.apply(context, args.concat(__args))
}
}
Function.prototype.apply1 = function () {
const args = transformArrayLikeToArray(arguments);
const self = this; // current fn
const context = args.shift();
const tempFn = self.bind(context, ...args[0]);
return tempFn()
}
Function.prototype.call1 = function () {
const args = transformArrayLikeToArray(arguments);
const self = this; // current fn
const context = args.shift();
const tempFn = self.bind(context, ...args);
return tempFn()
}
- 实际开发中闭包的应用场景,举例说明
- 隐藏数据
- 简单做一个cache工具,举个例子:
function createCache() {
const data = {};
return {
set: function (key, val) {
data[key] = val
},
get: function (key) {
return data[key]
}
}
}
const cache = createCache();
cache.set('a', 10);
cache.get('a'); // 10
- 创建10个
a
标签,点击的时候弹出对应的序号,代码如下:
var fragment = document.createDocumentFragment();
for (var i = 0; i < 10; i++) {
(function (i) {
var _a = document.createElement('a');
_a.innerHTML = i + '<br />';
_a.addEventListener('click', function (e) {
e.preventDefault();
alert(i)
});
fragment.appendChild(_a)
})(i)
}
document.body.appendChild(fragment)
知识点
-
作用域:
作用域有全局作用域、函数作用域、块级作用域
,变量的使用不能逃出当前所在的作用域之外。 -
自由变量:
一个变量再当前作用域没有定义,但被使用了就会向上一级作用域一次寻找,直到被找到为止;如果到了全局作用域还未被找到,则报错。
注意:自由变量的查找,是在函数定位的地方,向上级查找,不是在函数执行的地方!!! -
闭包:
闭包是函数作用域二点特殊情况,有两种表现:- 函数作为参数被传递
- 函数作为返回值被返回
举个例子
// 函数作为返回值被返回
function create(){
let a = 100;
return function () {
console.log(a)
}
}
let fn = create();
let a = 200;
fn(); // 100
// 函数作为参数被传递
function print(fn) {
let a = 200;
fn()
}
let a = 100;
function fn() {
console.log(a)
}
print(fn); // 100