先简单介绍简历上的项目。
1、用两种方法实现一个布局,左边div固定px,右边div占满剩余且随窗口变化。
方法一:flex布局下,使用flex属性和flex-grow属性
- "width: 100%; display: flex;">
- <div style="width: 200px; height: 200px;">div>
- <div style="flex-grow: 1; height: 200px;">div>
方法二: 定位布局下,使用calc()函数
- <div style="width: 100%; position: relative;">
- <div style="width: 200px; height: 200px;">div>
- <div style="position: absolute; top: 0; left: 200px; width: calc(100% - 200px); height: 200px;">div>
- div>
2、显式原型和隐式原型。
显式原型:每个函数都有prototype属性,指向它的原型对象。
隐式原型:每个实例对象都有__proto__属性,指向实例的构造函数的原型对象。
(1)问了Array的显式原型,这里总结所有类型的显示原型。并且打印每种类型的实例。可以看到类型的显示原型和实例的隐式原型是一致的。
- console.log(Array.isArray(Array.prototype)); // true
- // 附加各种数据类型的原型类型判断。Null和Undefined没有原型
- console.log(Object.prototype.toString.call(Number.prototype)); // Number
- console.log(Object.prototype.toString.call(String.prototype)); // String
- console.log(Object.prototype.toString.call(Boolean.prototype)); // Boolean
- console.log(Object.prototype.toString.call(Array.prototype)); // Array
- console.log(Object.prototype.toString.call(Function.prototype));// Function
- console.log(Object.prototype.toString.call(Object.prototype)); // Object
- console.log(Object.prototype.toString.call(Date.prototype)); // Object
- console.log(Object.prototype.toString.call(RegExp.prototype)); // Object
- // 附加各种数据类型实例的隐式原型判断
- let num = 123;
- console.log(Object.prototype.toString.call(num.__proto__)); // Number
- let str = '123';
- console.log(Object.prototype.toString.call(str.__proto__)); // String
- let bln = false;
- console.log(Object.prototype.toString.call(bln.__proto__)); // Boolean
- let arr = [1,2,3];
- console.log(Object.prototype.toString.call(arr.__proto__)); // Array
- let fct = function(){};
- console.log(Object.prototype.toString.call(fct.__proto__)); // Function
- let obj = {1:1,2:2,3:3};
- console.log(Object.prototype.toString.call(obj.__proto__)); // Object
- let dat = new Date();
- console.log(Object.prototype.toString.call(dat.__proto__)); // Object
- let reg = new RegExp();
- console.log(Object.prototype.toString.call(reg.__proto__)); // Object
总结,原始类型(Number、String、Boolean)和引用类型(Array、Function、Object)的显式原型就是本身的类型。这些类型的显式原型和其实例的隐式原型是一致的,因此类型也是一致的。
(2)问了Array的隐式原型 ,这里总结所有类型的显示原型。
- console.log(typeof Array.__proto__); // Function
- // 附加各种数据类型的原型属性类型判断
- console.log(Object.prototype.toString.call(Number.__proto__)); // Function
- console.log(Object.prototype.toString.call(String.__proto__)); // Function
- console.log(Object.prototype.toString.call(Boolean.__proto__)); // Function
- console.log(Object.prototype.toString.call(Array.__proto__)); // Function
- console.log(Object.prototype.toString.call(Function.__proto__));// Function
- console.log(Object.prototype.toString.call(Object.__proto__)); // Function
- console.log(Object.prototype.toString.call(Date.__proto__)); // Function
- console.log(Object.prototype.toString.call(RegExp.__proto__)); // Function
如果是自定义的构造函数与其实例,情况如下:
- // 构造函数
- function Father(){
- this.name = "father";
- }
- console.log(Object.prototype.toString.call(Father.prototype)); // Object
- console.log(Object.prototype.toString.call(Father.__proto__)); // Function
- // 实例
- let tmp = new Father();
- console.log(Object.prototype.toString.call(tmp)); // Object
- console.log(Object.prototype.toString.call(tmp.__proto__)); // Object
总结,构造函数的隐式原型__proto__都是Function类型。除数据类型外,其他构造函数的显式原型prototype是Object类型,其实例的隐式原型和其构造函数的显示原型是一致的Object类型。不管是实例还是实例的隐式原型,它们的类型是一致的,因为要顺着原型链去找类型。
3、实现object和array的浅拷贝。
(1)遍历
- let origin = {
- a: 1,
- b: [2,3,4],
- c: {
- d: 'name'
- }
- };
- let shallow_copy = {};
- for(const key in origin){
- if(origin.hasOwnProperty(key)){ // 用hasOwnProperty()可以过滤掉原型上的属性和对象
- shallow_copy[key] = origin[key];
- }
- }
- console.log(shallow_copy);
打印shallow_copy的结果:
(2)用object.assign()
- let origin = {
- a: 1,
- b: [2,3,4],
- c: {d: 'name'}
- };
-
- let shallow_copy = Object.assign({}, origin);
- // 或者
- // let shallow_copy = null;
- // Object.assign(shallow_copy, origin);
- console.log(shallow_copy);
打印shallow_copy的结果:
但是如果修改origin的数据,再打印shallow_copy,
- origin.a = 6;
- origin.b[0] = 6;
- origin.c.d = '6';
shallow_copy的值会变。
如果修改shallow_copy的数据,然后打印origin,
- shallow_copy.a = 6;
- shallow_copy.b[0] = 6;
- shallow_copy.c.d = '6';
origin只会改变引用类型的数据。
(3)数组的其他浅拷贝方法Array.prototype.concat()和Array.prototype.slice()
- let arr1 = [1,3,{user: 'aaa'}]
- let arr2 = arr1.concat();
- let arr3 = arr1.slice();
总结,浅拷贝和深拷贝都是针对对象的。对于对象的数值类型数据,浅拷贝会复制值,对于引用类型数据,浅拷贝只复制内存地址。因此对浅拷贝出来的新对象,修改引用类型的数据,会影响到原始对象。
4、js的事件代理和事件委托。
百度说,事件代理和事件委托实际上说的是同一件事,只是站在不同的角度来说的。比如说元素A把事件处理委托给自己的父元素B去处理,那么A就是事件委托方,而B就是事件代理方,两者参与的实际上是同一件事。下面就只说事件委托。
事件委托针对的场景
用addEventListener()给所有
- let children = document.querySelectorAll('li');
- for(let i=0; i
length; i++){ - children[i].addEventListener('click', function(){
- console.log(this.id, this.innerHTML);
- })
- }
-
- <li id="0">你li>
- <li id="1">好li>
- <li id="2">啊li>
打印结果如下:
但如果
事件委托就是来解决这个问题的。事件流是,捕获阶段——目标——冒泡阶段。事件委托发生在冒泡阶段。实现它的方法是,在父元素上绑定一个事件,利用该事件对象(里面的target)来判断当前事件流正在进行的元素。如果元素和期望元素相同,则执行相应的代码。
- let parent = document.querySelector('ul');
- parent.addEventListener('click', function(e){
- let event = e || window.event; // 获取event对象
- let target = event.target; // 获取target对象
- if(target.nodeName.toLowerCase() == 'li'){
- console.log(target.id, target.innerText);
- }
- })
5 vue 自定义组件实现v-model的功能。
其实考察父子组件通信。自定义组件要实现v-model的功能,即实现数据双向绑定,该自定义组件可看作子组件,引用该组件的为父组件。当父组件修改信息时,通过props传递给子组件,子组件的数据修改时,通过$emit派发事件给父组件修改数据。
子组件:
- <div>子组件中的input: div><br/>
- <input type="text" :value="message" @input="changeData"><br/>
- <div>子组件中的message: {{message}}div><br/>
- template>
-
- <script>
- export default{
- props: ["message"], // 父组件传来的数据
- emits: ['emit'], // 父组件传来的事件
- methods:{
- changeData(e){
- // 触发父组件的emit事件
- this.$emit('emit', e.currentTarget.value);
- }
- }
- }
- script>
父组件:
-
- <Child :message="fatherData" @emit="childMethod">Child>
- <div>父组件中的message: {{fatherData}}div>
-
- <script>
- import Child from './components/Child.vue'
- export default{
- data(){
- return{
- fatherData: "请输入" // 要传给给子组件的数据
- }
- },
- methods:{
- childMethod(childData){ // 子组件要触发的函数
- this.fatherData = childData;
- }
- },
- components:{
- Child
- }
- }
- script>
效果:
修改输入值:
可以看到,修改子组件的input值,父组件中message被$emit触发事件改变值,同时,父组件通过props传给子组件的message也随之改变。
6、vue数组变异方法。
Vue存在双向绑定失效的情况,
对于数组,解决的方法有以下几种,
(1)数组原有方法
push()、pop()、shift()、unshift()、sort()、reverse()、splice()
(2)替换数组
不会改变原始数组,但总是返回一个新数组。
filter()、concat()、slice()
(3)修改响应数据
- Vue.set(array, index, newValue) // 修改数组某个下标的值
- vm.$set(array, index, newValue) // 同上
- vm.array.splice(newLength) // 修改长度
vm代表Vue的实例。参数array表示要处理的数组名称或者对象,index表示要处理的数组的索引或者对象名,newValue表示要设置的数组值或对象值。